상세 컨텐츠

본문 제목

FCM(firebase cloud messaging) 에서 받은 알림 메세지 앱에서 수신세팅 방법입니다.

firebase

by carecat 2025. 7. 5. 20:56

본문

반응형

우선, FCM 서버에서 알림메세지 전송 구현이 미리 셋팅되어있어야 합니다.

   cloud function 내에 트리거를 이용하는 방법, 콘솔을 이용해 직접 발송 가능합니다.

   (공통적으로 단말기 토큰으로 식별해서 전송됩니다.)

 

1. 내 앱에서 필요한 패키지를 추가합니다.

dev_dependencies:
  flutter_test:
    sdk: flutter
  firebase_core:
  firebase_messaging:
  firebase_analytics:
  firebase_cloud_firestore:
  flutter_local_notifications:

  위 패키지중 firebase_messaging 과 flutter_local_notification 패키지가 직접적으로 해당 역할을 수행합니다.

 -firebase_messaging: fmc 서버에서 수신받은 알람,메세지를 리스닝합니다.

 -flutter_local_notifications : 포그라운드 실행중일때 (해당 앱이 실행중) 알람 메세지 구현을 위해 필요합니다.

 

2. flutter_local_notificatons 관련한 환경설정을 진행합니다.

  테스트 환경: Flutter 3.32.4 
  Framework • revision 6fba2447e9 
  Engine • revision 8cd19e509d 
   Tools • Dart 3.8.1 • DevTools 2.45.1

 

   2-1.  AndroidMainifext.xml 보완 셋팅 (위치: app -> main -> 안에 위치함.    

<!-- 퍼미션 셋팅 시작-->
 <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" />
<!-- 퍼미션 셋팅 종료 -->

 

<UI 관련한  activity 안에 추가..

android:showWhenLocked="true"
android:turnScreenOn="true">
<!-- 리시버 등록 시작 -->
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" 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>
<!-- 리시버 등록끝 -->

 

  전처젝인 참고 페이지(출처) https://developer.android.com/guide/topics/manifest/uses-permission-element?hl=ko&_gl=1*r065ke*_up*MQ..*_ga*MTQyNzI0Njk3Ny4xNzUxNzE2NDY1*_ga_6HH9YJMN9M*czE3NTE3MTY0NjUkbzEkZzAkdDE3NTE3MTY0NjUkajYwJGwwJGg1NzA1MTE5MDc.

 

 

   2.-2. buid.gradle.kts 보완 셋팅  (app 하위 위치)

android {
    namespace = "com.example.message_firest"
    // 수정시작
    compileSdk = 35
    // 수정종료
    ndkVersion = "27.0.12077973"

    compileOptions {
        // 수정시작
        isCoreLibraryDesugaringEnabled = true
        // 수정종료
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }
defaultConfig {
    // 수정시작
    multiDexEnabled = true
    // 수정종료
// 수정시작
dependencies {
    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
    implementation("androidx.window:window:1.0.0")
    implementation("androidx.window:window-java:1.0.0")
}

buildscript {
    dependencies {

        classpath("com.android.tools.build:gradle:8.6.0")

    }
}

// 수정 종료

 

3.코딩 구현

3-1. main.dart 파일에 아래와 같이 구현

 

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options:DefaultFirebaseOptions.currentPlatform);
  runApp(MyApp());
}

 firebase cli 통해  firebase_options.dart 파일이 생성되고 상기와 같이 보완 코딩합니다.

void initState() {
  super.initState();
  //flutter_local_notification 초기화
  FlutterLocalNotification.init();
  //terminate 시 활용
  FlutterLocalNotification.onBackgroundNotificationResponse();
  //firebase-massaging 리스너 실행
  msgListner();

 - FultterlocalNotification.init() 

  => flutter_local_notification 패키지 초기화 기능입니다.  여기 초기화 내용에는 안드로이드, ios 관련 초기화가 세팅이 되고 

       아래와 같습니다.

class FlutterLocalNotification {
  FlutterLocalNotification._();  //private 생성자

  //절차적 초기화시작
  static init() async {
    AndroidInitializationSettings androidInitializationSettings =
    const AndroidInitializationSettings('mipmap/ic_launcher');

    DarwinInitializationSettings iosInitializationSettings =
    const DarwinInitializationSettings(
      requestAlertPermission: false,
      requestBadgePermission: false,
      requestSoundPermission: false,
    );

    InitializationSettings initializationSettings = InitializationSettings(
      android: androidInitializationSettings,
      iOS: iosInitializationSettings,
    );

    //플러그인 초기화-
    await flutterLocalNotificationsPlugin.initialize(
      initializationSettings,
      //어플이 실행중일때와 백그라운드에 있을때..
      onDidReceiveNotificationResponse: onDidReceiveNotificationResponse,
        //카타고리 알림사용시 당장 필요없슴.!
        // onDidReceiveBackgroundNotificationResponse:  notificationTapBackground
    );
  }

  //local_notification 권한 알림,뱃지,사운드 옵션
  static requestNotificationPermission() {
    flutterLocalNotificationsPlugin
        .resolvePlatformSpecificImplementation<
        IOSFlutterLocalNotificationsPlugin>()
        ?.requestPermissions(
      alert: true,
      badge: true,
      sound: true,
    );
  }
//절차적 코드 종료

 

- FlutterLocalNotification.onBackgroudNotificationResponse()

  =>알림메세지 터치(클릭)이후 앱이 열렸다면 true 반환   

/앱이 푸시알림을 통해 시작되었는지? 푸시알림 페이로드 데이터 갖고옴!
  static void onBackgroundNotificationResponse() async {
    final NotificationAppLaunchDetails? notificationAppLaunchDetails =
    await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
// 앱이 푸시알람을 통해 열렸다면,true 페이로드를 갖고와 표시해줌!
    if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
      String payload =
          notificationAppLaunchDetails!.notificationResponse?.payload ?? "";
      print("BACKGROUND PAYLOAD: $payload");
      selectNotificationStream.add(notificationAppLaunchDetails.notificationResponse!);

    }
  }

 

-msgLinstner()

 => firebase-messaging 패키지를 활용하여 리스너 등록(앱이 포그라운드일때) / 아래 코드가 없어도 앱이 백그라운드 이거나

      종료되어도 알림메세지 받는데는 문제없습니다.

//firebase-messaging 리스너 등록
Future<void>  msgListner() async {
  FirebaseMessaging.onMessage.listen((RemoteMessage message) {
    String payloadData = jsonEncode(message.data);
    if(message.notification != null) {
      if (kDebugMode) {
        print('포그라운드나 백그라운드 상태에서 수신됨!');
        print('Message data: ${message.data}');
      }
      FlutterLocalNotification.showSimpleNotification(
          title: message.notification!.title!, body: message.notification!.body!, payload: payloadData);
    }

  });
}

 

3-2. 어플이 실행중(포그라운드) 알림수신시

//앱이 포그라운드 일때 알림을 터치하면 타 페이지로 이동구현.
static void onDidReceiveNotificationResponse(
    NotificationResponse notificationResponse) async {
  // final String payload = notificationResponse.payload ?? "";
  if (notificationResponse.payload != null ||
      notificationResponse.payload!.isNotEmpty) {
    print('수신 데이타 PAYLOAD: ${notificationResponse.payload.toString()}');
    //스트림에 수신된 데이타 리슨기능을 부여함!
    selectNotificationStream.add(notificationResponse);
    print("===>화면이동1");
  }

}

 

3-3. 푸시알람을 통해 앱이 실행되었는지 확인.

    실행된 앱의 알림메세지의 상세정보를 "getNotificationAppLaunchDetails()" 함수를 통해 bool 형태로 얻어옴

//앱이 푸시알림을 통해 시작되었는지? 푸시알림 페이로드 데이터 갖고옴!
  static void onBackgroundNotificationResponse() async {
    final NotificationAppLaunchDetails? notificationAppLaunchDetails =
    await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
// 앱이 푸시알람을 통해 열렸다면,true 페이로드를 갖고와 표시해줌!
    if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
      String payload =
          notificationAppLaunchDetails!.notificationResponse?.payload ?? "";
      print("BACKGROUND PAYLOAD: $payload");
      selectNotificationStream.add(notificationAppLaunchDetails.notificationResponse!);

    }
  }

 

3-4. 아래 객체는 스트림 컨트롤러 형태로 받는다.

final StreamController<NotificationResponse> NStream =
StreamController<NotificationResponse>.broadcast();

 

4.전체적인 흐름 요약

 FCM 서버에서 수신된 알림 메세지(Notification) 는 앱의 상태에 따라 수신 방법이 정해져(구분되어) 있습니다.

 

 4-1.앱이 실행중일때(foreground)

    이때, 알림 메세지(Notification)가 도착하면  firebase-messaging 패키지를 통해 수신합니다.

    더불어 이곳에서 알림메세지 (Notification) 가  show () 함수를 통해 화면에 보여집니다.

 

 4-2.앱이 백그라운드일때 (background) 

   이때, 알림 메세지(Notification)가 도착하면 firebase-messaging 패키지 도움을 받지 않고 바로 

  "fluuter_local_notification" 패키지를 통해서 화면에 보여집니다.

 

 4-3.앱이 종료되었을때 (terminate)

이때, 알림 메세지(Notification)가 도착하면 firebase-messaging 패키지 도움을 받지 않고  

  앱이 백그라운드 일때와 마찬가지로  "fluuter_local_notification" 패키지를 통해서 화면에 보여집니다.

 

 이외, 도착한 알림 메세지(Notification) 터치이후  동작 구현 방법은 아래와 같습니다.

 

  -앱이 실행중일때(forground)

    페이로드(payload) 갖고 타 원하는 페이지로 이동을 할수있습니다.

 

  [main에 아래와 같이 코딩]

final navigatorKy = GlobalKey<NavigatorState>();
Widget build(BuildContext context) {
  return MaterialApp(
      navigatorKey: navigatorKy,
      routes: {
        '/': ((context) => Home1()),
        '/message': ((context) => NpAge()),
      },
  );
}

   '/message' => 나중에 페이지 라우팅할때 사용할 네임(임의로 정함)

 

[호출하는 클래스내에]

 NotificationResponse 클래스를 콜백으로 받는 함수.

navigatorKy.currentState!.pushNamed('/message', arguments:notificationResponse.payload);

  arguments: => 전달하고자 하는 수신알람 메세지

 

[최종 열리는 클래스(페이지)]

Widget build(BuildContext context) {
  final data = ModalRoute.of(context)!.settings.arguments;
  return Scaffold(
    appBar: AppBar(title: Text("npage"),),
    body: data != null?Text(data.toString()):Text("nodata"),


  );

 

 

-앱이 백그라운드일때 (background) 일때와 앱이 종료되었을때 (terminate) 는 항상 최초 실행된 메인 페이지로 이동

    됩니다. => " fluuter_local_notification" 패키지내"getNotificationAppLaunchDetails()" 함수로 확인하고

    메인 앱화면을 다시 열지 기존꺼(백그라운드 앱) 열지 판단합니다.

 

 

 

 

반응형

관련글 더보기