[Flutter] FCM, Firebase Cloud Messagin 연동

ungchun·2022년 1월 16일
4
post-thumbnail

0. Flutter 앱에 Firebase 추가

  • Firebase는 기본적으로 세팅이 완료된 상태에서 진행하셔야 합니다. 아직 세팅을 안하셨다면 Flutter 앱에 Firebase 추가 문서를 보고 완료해주시거나, 어려우시면 Firebase Android, IOS 연동 를 참고하셔서 Firebase 세팅을 완료해주세요.

1. 사용한 라이브러리

firebase_messaging: ^11.2.5
flutter_local_notifications: ^9.2.0

2. Android 세팅

  • android / app / src / main / AndroidManifest.xml
<manifest
    ...
    <uses-permission android:name="android.permission.INTERNET"/>
    <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" />     
<application
	...
    <meta-data
            android:name="com.google.firebase.messaging.default_notification_channel_id"
            android:value="high_importance_channel" />
<activity
    android:name=".MainActivity"
    ...
    
    android:showWhenLocked="true"
    android:turnScreenOn="true"
    
    <intent-filter>
        <action android:name="FLUTTER_NOTIFICATION_CLICK" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    
    >
  • android / app / build.gradle
dependencies {
    implementation platform('com.google.firebase:firebase-bom:29.0.2')
    implementation 'com.google.firebase:firebase-analytics'
}
  • android / build.gradle
dependencies {
        classpath 'com.android.tools.build:gradle:4.1.0'
        classpath 'com.google.gms:google-services:4.3.10'
    }

3. IOS - APNs 세팅

  • ios 에서 FCM을 이용하기 위해서는 인증서 또는 인증키를 발급해야지 사용할 수 있습니다.
    Firebase 에서도 최신 방식인 인증키를 사용하여 구성하는 것이 좋다고 하니 인증키를 이용하여 구성해보자.
    (조금 더 알아보니 인증서는 매년 갱신해야하고 인증키는 따로 갱신안해도 된다고 함.)

  • 참고로 인증서, 인증키 두개 다 등록하면 이런 알림이 뜬다.

  • apple developer 에 들어가서 Keys + 버튼 클릭.

  • 이름 작성해주고, APNs 체크.

  • 키를 다운로드 합니다. 한번 다운로드 받으면 다시 다운받을 수 없다고 하니 안전한 곳에 잘 보관해 줍니다.

  • 다운받은 키를 Firebase -> 프로젝트 설정 -> 클라우드 메시징 -> apple 앱 구성에 등록해주자.

  • 프로젝트 xcode 를 실행시켜주고, Signing & Capabilities -> Capability 을 눌러 Push Notifications, Background Modes 를 추가시켜줍시다.

  • Background Modes 에 Background fetch, Remote notifications 체크해줍시다.

자세한건 공식 문서 를 참고해주세요.

4. 코드

실행에 앞서 firebase_messaging 공식문서를 통해 몇가지 알아야 할 정보가 있다.
1. ios 시뮬레이터에서는 작동하지 않으며 실기기가 필요하다.
2. 애플리케이션이 foreground 에 있는 경우 Firebase Android SDK는 설정된 알림 채널에 관계없이 FCM 알림 표시를 차단한다고 한다. 따라서 foreground 메시지를 처리하려면 onMessage 로 들어오는 메시지를 처리하고 flutter_local_notifications 으로 로컬 알림을 만들 수 있다.
3. background 메시지 관련 함수는 익명 함수가 아니어야 하고, 최상위에 위치하여야 한다.
( Cloud Messaging, Notifications 공식 문서 참고 )

  • 저는 Android, ios 둘 다 실기기로 테스트 진행했습니다.
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
  print('Handling a background message ${message.messageId}');
}

late AndroidNotificationChannel channel;
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);

  channel = const AndroidNotificationChannel(
    'high_importance_channel', // id
    'High Importance Notifications', // title
    description:
        'This channel is used for important notifications.', // description
    importance: Importance.high,
  );
  
  var initialzationSettingsAndroid =
      AndroidInitializationSettings('@mipmap/ic_launcher');

  var initialzationSettingsIOS = IOSInitializationSettings(
    requestSoundPermission: true,
    requestBadgePermission: true,
    requestAlertPermission: true,
  );

  flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();

  await flutterLocalNotificationsPlugin
      .resolvePlatformSpecificImplementation<
          AndroidFlutterLocalNotificationsPlugin>()
      ?.createNotificationChannel(channel);
      
  var initializationSettings = InitializationSettings(
      android: initialzationSettingsAndroid, iOS: initialzationSettingsIOS);

  await flutterLocalNotificationsPlugin.initialize(
    initializationSettings,
  );

  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
    alert: true,
    badge: true,
    sound: true,
  );
  runApp(const MyApp());
}

class ...
   @override
    void initState() {
      FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
        RemoteNotification? notification = message.notification;
        AndroidNotification? android = message.notification?.android;
        var androidNotiDetails = AndroidNotificationDetails(
          channel.id,
          channel.name,
          channelDescription: channel.description,
        );
        var iOSNotiDetails = const IOSNotificationDetails();
        var details =
            NotificationDetails(android: androidNotiDetails, iOS: iOSNotiDetails);
        if (notification != null) {
          flutterLocalNotificationsPlugin.show(
            notification.hashCode,
            notification.title,
            notification.body,
            details,
          );
        }
      });

      FirebaseMessaging.onMessageOpenedApp.listen((message) {
        print(message);
      });
      super.initState();
    }

5. Firebase console 에서 메시지 보내기

  • 특정기기로 메시지를 보내려면 서버가 기기의 FCM 토큰값을 알아야합니다.
token = await FirebaseMessaging.instance.getToken();

print("token : ${token ?? 'token NULL!'}");

  • 토큰값을 알았다면 Cloud Messaging -> 새 알림 -> 테스트 메시지 전송을 눌러줍니다.

  • 토큰값을 등록해주고 테스트 버튼을 누르면 정상적으로 메시지가 오는것을 확인할 수 있습니다.

8개의 댓글

comment-user-thumbnail
2022년 4월 18일

감사합니다~!

1개의 답글
comment-user-thumbnail
2022년 5월 20일

FCM 구현 예제를 찾고 있었는데 좋은 글 아주 감사합니다.
게시글 참고해서 OnMessage와 백그라운드까지는 구현 완료하였습니다.
하지만 앱이 종료되있는 상태에서 푸시 알림은 실행되지 않습니다.
혹시 조언 좀 구할 수 있을까요?

1개의 답글

좋은글 감사합니다!
한가지 질문이있습니다. 작성해주신 코드 그대로 사용하였는데요.
iOS 에서 앱이 켜져있는 상태에서는 헤드업 노티(?) 가 2번 오고있어서요
해당부분은 어떻게 제어해줘야할까요?

1개의 답글
comment-user-thumbnail
2023년 5월 17일

감사합니다 시뮬레이터에서 안되는지 몰라서 몇시간 동안 삽질했습니다.. 테스트 메시지 전송은 받았는데 알림은 배포하지 않는 이상 오지 않는건가요? 테스트로 실제 알림을 받아보려면 APN 인증키가 아닌 인증서에 샌드박스로 해야하나요?

1개의 답글