혁신을 이룹니다, 오딘박스(OdinBOX)

언제나 어디서나 오딘박스와 함께!

Flutter FCM(Firebase Cloud Messaging) 알림(Notification) 사용방법

간지뽕빨리턴님 2024. 6. 22. 22:54
반응형

Flutter Notification 추가해 보자!

알림은 이걸로 해보세요!

요즘 업무에서 플러터를 활용하여 앱을 만들어 배포를 해야 하는 일이 생겨 공부를 하고 있는데 이 중에서 앱의 가장 큰 장점 중 하나인 알림을 보내야 하는데 어떻게 하면 좋을지 고민을 하다가 검색을 해보니 FCM이라는 것을 많이 활용하여 만드는 것 같아 이걸로 적용을 하기로 했습니다. 처음 사용하는 분들도 이 글을 보고 도움이 될 수 있도록 정리를 해보려고 합니다.

목차

    FCM(Firebase Cloud Messaging)

    우선, 파이어베이스[#]로 접속을 합니다, 파이어베이스의 경우 구글 계정이 있으면 사용을 할 수 있습니다. 상단 오른쪽을 클릭하여 선택을 하면 구글 계정 로그인을 할 수 있습니다. 로그인 후 Console로 이동을 합니다.

     

    FCM 프로젝트 추가

    콘솔 화면으로 이동을 하고 먼저 Firebase 프로젝트에 여러분이 알림을 적용할 앱 이름으로 프로젝트를 만들어줍니다. 애널리틱스를 설정을 할 수 있는 데 사용 용도에 따라 설정할 수 있는 방법이 다르긴 하지만 저의 경우 애널리틱스 설정을 합니다.

    프로젝트 Firebase 추가

    pubspec.yaml / command / import :

    dependencies:
      firebase_core: ^3.1.0
      firebase_messaging: ^15.0.1
      firebase_analytics: ^11.0.1
      flutter_local_notifications: ^17.1.2
      
      flutter command
      $ flutter pub add firebase_core
      $ flutter pub add firebase_messaging
      $ flutter pub add firebase_analytics
      $ flutter pub add flutter_local_notifications
      
      fluttter import
      import 'package:firebase_core/firebase_core.dart';
      import 'package:firebase_messaging/firebase_messaging.dart';
      import 'package:firebase_analytics/firebase_analytics.dart';
      import 'package:flutter_local_notifications/flutter_local_notifications.dart';

    firebase_core 3.1.0 [#]

    firebase_messaging 15.0.1 [#]

    firebase_analytics 11.0.1 [#]

    flutter_local_notifications 17.1.2 [#]

    Flutter 권한 설정

    Android(Project > Android > App > src > main > androidManifest.xml), iOS(AppDelegate.swift)

      <!-- Permission -->
      <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
      <uses-permission android:name="android.permission.VIBRATE" />
      <uses-permission android:name="android.permission.WAKE_LOCK" />
      <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
      
      -- Device Rebooting Notification Scheduler
      <receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED"/>
            <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
            <action android:name="android.intent.action.QUICKBOOT_POWERON" />
            <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
        </intent-filter>
    </receiver>
    
    -- Push Notification Screen
    <receiver android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
      
      -- Device Lock Notification
      <activity
    android:showWhenLocked="true"
    android:turnScreenOn="true">
    
    
    /*
     iOS : AppDelegate.swift
    */
    if #available(iOS 10.0, *) {
        UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
    }

    Flutter 알림 추가

    String? _fcmToken = await FirebaseMessaging.instance.getToken();
    print(_fcmToken);

    Main.dart에 추가를 해야 하는데 우선 알림을 보내기 위해선 보낼 기기의 토큰 값을 알고 있어야 합니다. 토큰 값은 여러분이 DB에 사용자 정보를 각각 저장하여 관리하는 것을 추천해 드립니다. 저의 경우 로그인 할 때마다 기기 토근값이 변경될 수 있어 항상 토큰 값을 DB에 저장하여 관리를 하고 있습니다.

     

    위 코드를 추가를 하면 디버깅에 token 값이 나오게 됩니다. 콘솔에서 Messaging을 들어가 알림 작성으로 들어가면 테스트할 수 있는 버튼이 활성화됩니다. 해당 버튼을 눌러 제목과 내용을 입력하고 아까 디버깅에 나왔던 토큰 값을 입력을 하면 제대로 수신을 할 수 있는지 확인을 할 수 있습니다.

    @pragma('vm:entry-point')
    Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
      // If you're going to use other Firebase services in the background, such as Firestore,
      // make sure you call `initializeApp` before using other Firebase services.
      await Firebase.initializeApp();
    
      print("Handling a background message: ${message.messageId}");
    }
    
    FirebaseMessaging messaging = FirebaseMessaging.instance;
    
    NotificationSettings settings = await messaging.requestPermission(
      alert: true,
      announcement: false,
      badge: true,
      carPlay: false,
      criticalAlert: false,
      provisional: false,
      sound: true,
    );
    
    print('User granted permission: ${settings.authorizationStatus}');
    
    -- void main() 부분에 추가
    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

    알림 권한 요청하기

    알림 권한을 요청을 해야 하는데 사용자가 알림 권한을 안 해줄 때는 알림을 보낼 수 없으니 앱의 성격에 따라 필수로 받아와야 합니다. 제가 만들 앱의 성격 상 항상 필요하다 보니 앱 로그인 할 때마다 권한을 확인을 하고 진행을 하고 있습니다. 권한을 추가하는 방법은 아래와 같습니다.

    -- AndroidManifest.xml
    <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/>
    
    -- 권한 요청
    if (await Permission.notification.isDenied) {
    	await Permission.notification.request();
    }

    Foreground, Background, Terminate

    FCM을 쓰려면 위 세 가지를 어느 정도 이해를 하고 있어야 합니다. 알림을 발신을 하는 것도 중요하지만 수신을 하는 것은 매우 중요합니다. 첫 번째 포그라운드의 경우 앱 실행 중 알림을 받는 방법입니다. 이때 사용을 하는 것은 fluttter_local_notifications을 사용을 하고 있습니다. 그리고 두 번째인 백그라운드의 경우 말 그대로 백그라운드 상태에서 메시지를 수신하여 가져오는 것을 말하며 마지막으로 터미네이트의 경우 앱 종료 상태에 수신을 하는 것을 말합니다. 각 각 소스는 아래와 같습니다.

    - Foreground
    FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      print('Got a message whilst in the foreground!');
      print('Message data: ${message.data}');
    
      if (message.notification != null) {
        print('Message also contained a notification: ${message.notification}');
      }
    });
    
    - Background
    @pragma('vm:entry-point')
    Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
      // If you're going to use other Firebase services in the background, such as Firestore,
      // make sure you call `initializeApp` before using other Firebase services.
      await Firebase.initializeApp();
    
      print("Handling a background message: ${message.messageId}");
    }
    
    void main() {
      FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
      runApp(MyApp());
    }
    
    - Terminated
    FirebaseMessaging.instance
            .getInitialMessage()
            .then((RemoteMessage? message) {
          if (message != null) {
            if (message.notification != null) {
              	logger.e(message.notification!.title);
                logger.e(message.notification!.body);
                logger.e(message.data["click_action"]);
            }
          }
        });

    Firebase Cloud Messaging API (V1) -> Send

    테스트를 하는 것은 필요 없는 방법이지만 계속 테스트만 할 수 없는 것이고 이제 가장 중요한 방법입니다. 예전 FCM 연결 글들의 설명을 보면 예전 방식이라 위와 같이 하고 발신정도만 추가를 하면 끝나는 방법인데 구글 정책 변경이라고 봐야 하나 아니면 보안 업그레이드인지 API를 통해 Key를 생성하는 방식입니다. GCP 이동을 해서 API 발급을 하고 JSON을 선택을 하면 키값을 발급을 할 수 있습니다. 그리고 난 뒤 Google API에서 Firebase Cloud Messaging API V1을 선택을 하고 Authorize APIs를 클릭하여 키값을 받아야 합니다.

    - 이 방법이 짜증 나는 이유는 API 키값을 받고 일정시간 뒤에 다시 리셋된 키값을 받아야 하는데 이게 생각보다 귀찮습니다.

    URL : https://fcm.googleapis.com/v1/projects/프로젝트명/messages:send
    
    - Headers
    'Content-Type': 'application/json'
    'Authorization': 'Bearer $_accessToken'
    
    message": {
                  "token": 받을기기토큰값,
                  "notification": {
                    "title": "제목",
                    "body": "내용",
                  }
    }

    기본적으로 위와 같은 방식으로 발송을 하면 됩니다.

     

    참고문서

    Firebase 공식문서 [#]

    마무리

    요즘 플러터를 공부를 시작하게 되었는데 생각보다 재미있는 기능들이 다양하게 많아 시도를 해보고 있습니다. 그중 웹이나 이런 것들을 할 때도 물론 할 수 있는 기능은 있었지만 크게 특별한 기능이 아니었던 알림이 앱에선 정말 유용하게 활용할 수 있는 기능이라 추가를 하기 위해 이곳저곳 알아보며 준비를 하여 실제 기기들에 적용하여 알림이 오는지 테스트를 해봤을 때 다행히 아직까지 위와 같은 방식으로 추가해서 큰 문제없이 적용을 할 수 있었습니다. 지금 이 글은 계속해서 내용을 추가하고 수정할 수 있는 글입니다. 나중에 기간이 지난 다음 이 글을 보더라도 다시 적용을 할 수 있도록 길잡이 글이 될 수 있도록 문서 내용을 조금 더 가다듬고 수정하려고 합니다. 혹시 이 글을 보고 수정할 내용이나 궁금한 내용이 있다면 댓글을 통해 글을 남겨주시면 답변드리도록 하겠습니다 :D