개발노트

57. [Flutter] Push 알림 기능 추가하기(Firebase Cloud Messaging) 본문

앱 개발/Flutter

57. [Flutter] Push 알림 기능 추가하기(Firebase Cloud Messaging)

mroh1226 2024. 1. 26. 14:59
반응형

Firebase는 어플리케이션의  Push 알림을 지원합니다.

이를 설정하기 위해 아래와 같이 순서대로 진행합니다.


Firebase Cloud Messaging 패키지 설치하기

- FCM 설정 방법: https://firebase.google.com/docs/cloud-messaging/flutter/client?hl=ko#upload_your_apns_authentication_key

 

Flutter에서 Firebase 클라우드 메시징 클라이언트 앱 설정

Google I/O 2023에서 Firebase의 주요 소식을 확인하세요. 자세히 알아보기 의견 보내기 Flutter에서 Firebase 클라우드 메시징 클라이언트 앱 설정 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐

firebase.google.com

 

1. pub add로 Flutter 프로젝트에 firebase_messaging을 설치합니다.

flutter pub add firebase_messaging

Flutter 프로젝트에 FMC 설치

 

2. flutterfire configure 로 변경사항을 프로젝트에 적용시켜줍니다.

flutterfire configure

flutterfire configure 로 pub 설치 후, 표준 프로세스를 따름


Firebase 콘솔 FCM 시작하기

1. 콘솔 접속 > "Cloud Messaging" 클릭 > "첫 번째 캠페인 만들기" 클릭

 

 

2. Firebase 알림 메시지 Type 선택(앱내에서만 받기 or 상태 전체에서 받기) > 알림 정보 입력 후, 보내기(Token 필요)

 


Message (Model)
class MessageModel {
  final String text;
  final String userId;
  final int createdAt;

  MessageModel({
    required this.text,
    required this.userId,
    required this.createdAt,
  });
  MessageModel.fromJson(Map<String, dynamic> json)
      : text = json["text"],
        userId = json["userId"],
        createdAt = json["createdAt"];
  Map<String, dynamic> toJson() {
    return {
      "text": text,
      "userId": userId,
      "createdAt": createdAt,
    };
  }
}

 

1. Flutter 프로젝트로 돌아와서, 토큰(Token) 얻기 아래 소스로 Token 얻기

ref.read(notificationsProvider(context)); //token을 미리 얻기위해

 

Provider
import 'dart:async';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

class NotificationsProvider extends FamilyAsyncNotifier<void, BuildContext> {
  final FirebaseFirestore _db = FirebaseFirestore.instance;
  final FirebaseMessaging _messaging = FirebaseMessaging.instance;

  Future<void> updateToken(String token) async {
    final user = ref.read(authRepo).user;
    await _db.collection("users").doc(user!.uid).update({"token": token});
  }

  Future<void> initListeners(BuildContext context) async {
    //push 알림 권한 얻기
    final permission = await _messaging.requestPermission();
    if (permission.authorizationStatus == AuthorizationStatus.denied) return;

    //1. 어플이 열려있을 때 Push 알림(Foreground)
    FirebaseMessaging.onMessage.listen((RemoteMessage event) {
      print("foreground message");
      print(event.notification?.title);
    });

    //2. 어플이 닫혀있을 때 Push 알림(Background)
    FirebaseMessaging.onMessageOpenedApp.listen((event) {
      //Push 알림에 data를 추가로 보내고 이를 받아올 수 있음
      //print(event.data["screen"]);
      context.pushNamed(ChatsScreen.routeName);
    });

    //3. 앱이 종료된 상태에서의 Push 알림 (Terminated)
    final notification = await _messaging.getInitialMessage();
    if (notification == null) return;
    //print(notification.data["screen"]);
    context.pushNamed(VideoRecordingScreen.routeName);
  }

  @override
  FutureOr build(BuildContext context) async {
    final token = await _messaging.getToken(); //알림을 보내기 위한 Token을 가져옴
    print("토큰: $token");
    if (token == null) return;
    await updateToken(token);
    await initListeners(context);
    _messaging.onTokenRefresh.listen((newToken) async {
      await updateToken(newToken);
    });
  }
}

final notificationsProvider = AsyncNotifierProvider.family(
  () => NotificationsProvider(),
);

 

2. Function 에 알림에 들어갈 Data 가공

index.ts (Function 기능 활용)
//좋아요 했을 때 likes Collection에서 해당 likeId를 추가생성하고
//videos collection에서 videos like(필드) 값을 증가시키는 메서드
export const onLikedCreated = functions.firestore
  .document("likes/{likeId}")
  .onCreate(async (snapshot, context) => {
    const db = admin.firestore();
    //split으로 "000"을 구분자로 사용하여 videoId, userId를 받아옴
    const [videoId, _] = snapshot.id.split("000");
    await db
      .collection("videos")
      .doc(videoId)
      .update({
        likes: admin.firestore.FieldValue.increment(1), //기존 likes의 값을 +1 증가시켜줌
      });
    const video = await (
      await db.collection("videos").doc(videoId).get()
    ).data();
    if (video == null) return;
    const creatorUid = video.creatorUid;
    const user = await (
      await db.collection("users").doc(creatorUid).get()
    ).data();
    if (user) {
      const token = user.token;
      admin.messaging().send({
        token: token,
        data: { screen: "123" },
        notification: {
          title: "someone liked your video.",
          body: "Likes💕 + 1",
        },
      });
    }
  });

 

 

 

3. 터미널 명령어를 통해 Function 수정사항 배포

firebase deploy --only functions

 

API 설정

1. 아래 링크로 접속합니다.

- API 설정링크: https://console.cloud.google.com/welcome?project=tiktokclone-f68f0

 

Google 클라우드 플랫폼

로그인 Google 클라우드 플랫폼으로 이동

accounts.google.com

 

2. API 및 서비스 >  라이브러리 에 접속합니다.

API 및 서비스 > 라이브러리

 

3. 검색창에 "messaging" 을 검색합니다.

messaging 검색 > Cloud Messaging 클릭

 

 

4. Cloud Messaging 에 들어가 사용을 클릭하여 활성화 시켜줍니다.

 

 


Push 알림 보내기

1. 새 캠패인 만들기 > 알림 정보 입력

 

2. 토큰 입력

 

 

3. 추가 옵션에 키, 값입력으로 데이터를 넘겨줌

 

4. 전송 완료

 

5. Push 알림 전송 성공 (클릭 시, Background / ForeGround / Terminated 상태에 따라 위 소스 처럼 다른 화면으로 접속)

1) 어플이 열려있을 때 클릭하면 이동없음

2) 어플이 닫혀있을 때 Push 알림 클릭 시, ChatsScreen으로 이동

3) 앱이 종료된 상태에서 Push 알림 클릭 시, VideoRecordingScreen으로 이동

(아래 소스 참고)


    //1. 어플이 열려있을 때 Push 알림(Foreground)
    FirebaseMessaging.onMessage.listen((RemoteMessage event) {
      print("foreground message");
      print(event.notification?.title);
    });

    //2. 어플이 닫혀있을 때 Push 알림(Background)
    FirebaseMessaging.onMessageOpenedApp.listen((event) {
      //Push 알림에 data를 추가로 보내고 이를 받아올 수 있음
      //print(event.data["screen"]);
      context.pushNamed(ChatsScreen.routeName);
    });

    //3. 앱이 종료된 상태에서의 Push 알림 (Terminated)
    final notification = await _messaging.getInitialMessage();
    if (notification == null) return;
    //print(notification.data["screen"]);
    context.pushNamed(VideoRecordingScreen.routeName);
 
반응형
Comments