본문 바로가기

dev/flutter

flutter - fcm 푸시 메세지 처리

firebase에서 설명해주는 순서대로 진행하면 된다.

 

 

Flutter 앱에서 메시지 수신  |  Firebase 클라우드 메시징

Google I/O 2023에서 Firebase의 주요 소식을 확인하세요. 자세히 알아보기 의견 보내기 Flutter 앱에서 메시지 수신 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.

firebase.google.com

 

 

1. firebase_messaging, flutter_local_notifications 패키지 추가

 

 

firebase_messaging | Flutter Package

Flutter plugin for Firebase Cloud Messaging, a cross-platform messaging solution that lets you reliably deliver messages on Android and iOS.

pub.dev

 

 

flutter_local_notifications | Flutter Package

A cross platform plugin for displaying and scheduling local notifications for Flutter applications with the ability to customise for each platform.

pub.dev

 

 

2. 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 ...

 

 

3. IOS 권한 받기

 

import 'package:firebase_messaging/firebase_messaging.dart';

Future<void> requestPermission() async {
  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}');
}

 

settings.authorizationStatus 값으로 권한 상태 확인 가능하다.

  • authorized: 권한 부여
  • denied: 권한을 거부
  • notDetermined: 아직 권한 선택하지 않함
  • provisional: 임시 권한

 

 

4. fcm토큰값 발행 코드 추가

해당 토큰을 저장해서 사용해야 한다. 백엔드에서 저장하는 로직이 필요하다.

 

void main() async {
  
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );

  final fcmToken = await FirebaseMessaging.instance.getToken();
  log("fcmToken: $fcmToken");

  runApp(const MyApp());
}

 

 

5. 백그라운드 상태에서 메세지 수신 코드 추가

 

@pragma('vm:entry-point') // Flutter 3.3 이상인 경우 @pragma 달기
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() async {
  
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); // 추가

  final fcmToken = await FirebaseMessaging.instance.getToken();
  log("fcmToken: $fcmToken");

  runApp(const MyApp());
}

 

 

6. 포그라운드 상태에서 메세지 수신 코드 추가

 

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}');
  }
});

 

 

7. 메세지 수신 핸들링

 

이러한 이유로 안드로이드는 채널을 만들고 알림을 위해 flutter_local_notifications 패키지의 flutterLocalNotificationsPlugin을 사용해야 한다. 

 

var channel = const AndroidNotificationChannel(
  'high_importance_channel', // id
  'High Importance Notifications', // name
  description: 'This channel is used for important notifications.', // description
  importance: Importance.high,
);

 

 var flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
  await flutterLocalNotificationsPlugin
    .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
    ?.createNotificationChannel(channel);

  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}');
      flutterLocalNotificationsPlugin.show(
        message.hashCode,
        message.notification?.title,
        message.notification?.body,
        NotificationDetails(
          android: AndroidNotificationDetails(
            channel.id,
            channel.name,
            channelDescription: channel.description,
            icon: '@mipmap/ic_launcher',
          ),
          iOS: const DarwinNotificationDetails(
            badgeNumber: 1,
            subtitle: 'subtitle',
            sound: 'slow_spring_board.aiff',
          )
        )
      );
    }
  });

 

 

 

 

 

8. fcm 푸시 내용 작성

 

캠페인 만들기

 

 

 

9. 기기로 발급받은 fcm 토큰 등록

 

 

 

10. 푸시 확인

 

 

 


클라우드 메세징 캠페인을 만들어서 푸시를 보내면 시간차가 조금 있는 듯하다.

개발할 때는 캠페인 만들기에서 테스트를 사용하는게 빠를 것 같다.

 

 


 

// main.dart
import 'dart:developer';

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_notification/firebase_options.dart';
import 'package:flutter_notification/firebase_setting.dart';

void main() async {

  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(
    options: DefaultFirebaseOptions.currentPlatform,
  );
  FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);

  final fcmToken = await FirebaseMessaging.instance.getToken();
  log("fcmToken: $fcmToken");

  setNotification();
  
  runApp(const MyApp());
}


// firebase_setting.dart
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

@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}");
}

Future<void> setNotification() async {

  // 채널 생성
  var channel = const AndroidNotificationChannel(
    'high_importance_channel', // id
    'High Importance Notifications', // name
    description: 'This channel is used for important notifications.', // description
    importance: Importance.high,
  );

  var flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
  await flutterLocalNotificationsPlugin
    .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
    ?.createNotificationChannel(channel);


  // 포그라운드 메세지 수신
  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}');
      flutterLocalNotificationsPlugin.show(
        message.hashCode,
        message.notification?.title,
        message.notification?.body,
        NotificationDetails(
          android: AndroidNotificationDetails(
            channel.id,
            channel.name,
            channelDescription: channel.description,
            icon: '@mipmap/ic_launcher',
          ),
          iOS: const DarwinNotificationDetails(
            badgeNumber: 1,
            subtitle: 'subtitle',
            sound: 'slow_spring_board.aiff',
          )
        )
      );
    }
  });
}