플러터 프로젝트에 Firebase에서 제공하는 FCM을 설정해 보겠습니다.
공식문서: https://firebase.google.com/docs/cloud-messaging?hl=ko
Firebase 클라우드 메시징
Firebase 클라우드 메시징(FCM)은 무료로 메시지를 안정적으로 전송할 수 있는 크로스 플랫폼 메시징 솔루션입니다.
firebase.google.com
앱에서 특정 조건이 만족할 때 사용자 앱에서 FCM 서버로 Messaging API(HTTP V1)를 이용해서 send 요청을 하면 FCM서버에서 다시 사용자 앱으로 푸시 알림을 보내주는 기능을 만들어보겠습니다.
원래는 사용자 단에서 직접적으로 FCM 서버로 요청을 하는 것보다는 중간다리 역할을 하는 서버를 만들고 서버에서 FCM으로 가는 것을 권장하는데요.
지금은 사용자 앱 단에서 직접적으로 Messaging API(HTTP V1) 발송 요청을 해보도록 하겠습니다.
(하지 말라면 더 하고 싶은 오기가 발동...😂)
서버는 node.js나 자바, 물론 다트 언어로도 개발을 할 수 있습니다.
우선 프로젝트에 파이어베이스 플러그인이 연동이 되어있어야 Firebase Cloud Messaging를 설정할 수가 있는데요.
파이버베이스 프로젝트를 설정하는 만드는 법은 아래 링크를 참조해 주세요. 😄
https://zzingonglog.tistory.com/36
[Firebase] 플러터 프로젝트에 Firebase 연동하기
새 프로젝트를 만들려고 하니 이것저것 환경 설정하는 부분이 전혀 기억이 안 나요. 하하... 블로그에 적어두는 습관을 갖도록 해야겠습니다. 😂😂😂 1. Vscode에 플러터 프로젝트 새로 만들기 Vs
zzingonglog.tistory.com
1. 패키지 추가
1) firebase_messaging 패키지 추가
패키지들을 추가해 주시고 앱을 정지하고 재빌드 해주세요.
flutter pub add firebase_messaging
2) googleapis_auth 패키지 추가
API를 통해 푸시 메시지를 보내려면 Google Api Auth 라이브러리가 필요합니다.
flutter pub add googleapis_auth
3) flutter_local_notifications 패키지 추가
FCM에서는 백그라운드와는 다르게 포그라운드 상태일 때는 푸시 알림이 상단에 나타나지 않아요.
포그라운드 상태일 때에도 푸시 알림이 나타나게 하려면 flutter_local_notifications 패키지의 도움을 받아야 하는데 이를 설치해 줍니다.
flutter pub add flutter_local_notifications
2. Firebase Messages API (HTTP V1) 설정
1) Firebase Messages API (HTTP V1) 비공개 키 만들기
좌측 상단의 프로젝트 개요에서 톱니바퀴를 누르고, 클라우드 메시징 탭으로 진입합니다.
아래 화면에서 발신자 ID는 발신 코드에서 사용해야하니 어딘가에 카피해 주세요.
서비스 계정 관리 링크를 클릭합니다.
그러면 아래 화면처럼 출력이 됩니다. 이메일 링크를 클릭하세요.
그리고 키 탭 화면에 진입한 후에, 키 추가 버튼을 이용하여 새 키를 만들어주세요.
json 파일을 선택하고 컴퓨터에 파일을 내려받은 후 원하는 이름으로 파일명을 변경해 줍니다.
저는 auth.json으로 수정했어요.
2) asset 설정
아까 클라우드 콘솔에서 내려받은 json 키 파일을 프로젝트의 assets/data 폴더에 넣어줍니다.
pubspec.yaml 파일에 assets 설정도 추가합니다.
3) AndroidManifest.xml 자동 초기화 중지 설정 (생략가능-참고)
등록 토큰은 사용자들마다 생성되는데 보통 서버에서 사용자 개별에게 푸시 알림을 보낼 때 사용되기 때문에 토큰을 따로 관리합니다.
그런데 앱 삭제, 재설치 등과 같은 이유로 인해 서버에 저장된 토큰과 사용자 기기의 등록 토큰이 달라지게 되면 토큰 업데이트를 주기적으로 해야 하는데 이 기능도 지원하고 있습니다. 사용자 등록 토큰이 업데이트될 때마다 알림을 받으려면 아래와 같이 onTokenRefresh 스트림을 리슨 하면 됩니다.
FirebaseMessaging.instance.onTokenRefresh
.listen((fcmToken) {
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new
// token is generated.
})
.onError((err) {
// Error getting token.
});
또한 토큰이 생성되면 그 즉시 Firebase SDK가 자동으로 업로드하는 것을 원하지 않는 경우 자동초기화를 방지할 수 있습니다.
어떤 이유로든 디바이스의 사용량을 추적할 수 없는 경우 이 문제가 발생할 수 있습니다. 이로 인해 일부 Firebase 제품이 올바르게 작동하는 데 영향을 미칠 수 있어요.
저는 초기화 중지 설정은 하지 않았으나 나중에 참고하기 위해 정리해 두었습니다.
FCM 등록 토큰이 생성되면 라이브러리는 식별자와 구성 데이터를 Firebase에 업로드합니다. 토큰 자동 생성을 방지하려면 빌드 시간에 자동 초기화를 중지합니다.
Android에서는 다음 메타데이터 값을 AndroidManifest.xml에 추가하여 애널리틱스 수집과 FCM 자동 초기화를 중지합니다. (둘 다 중지해야 함).
파일 경로: android/app/src/main/AndroidManifest.xml
<meta-data
android:name="firebase_messaging_auto_init_enabled"
android:value="false" />
<meta-data
android:name="firebase_analytics_collection_enabled"
android:value="false" />
3. 푸시 알림 코드 작성
1) main.dart
백그라운드 핸들러 함수와 메시지 상호작용을 정의하는 함수 setupInteractedMessage가 main 함수 밖에 정의되어 있어요.
그리고 main 함수 안에서는 백그라운드와 포그라운드 리스너를 등록해 주고, 메시지 상호작용 함수 호출, 푸시 알림의 발신과 수신을 담당할 PushNotification 클래스의 초기화가 보입니다.
main.dart 파일의 전체 내용은 아래와 같습니다.
final navigatorKey = GlobalKey<NavigatorState>();
//반드시 main 함수 외부에 작성합니다. (= 최상위 수준 함수여야 함)
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
if (message.notification != null) {
print("Notification Received!");
}
}
//푸시 알림 메시지와 상호작용을 정의합니다.
Future<void> setupInteractedMessage() async {
//앱이 종료된 상태에서 열릴 때 getInitialMessage 호출
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
_handleMessage(initialMessage);
}
//앱이 백그라운드 상태일 때, 푸시 알림을 탭할 때 RemoteMessage 처리
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
//FCM에서 전송한 data를 처리합니다. /message 페이지로 이동하면서 해당 데이터를 화면에 보여줍니다.
void _handleMessage(RemoteMessage message) {
Future.delayed(const Duration(seconds: 1), () {
navigatorKey.currentState!.pushNamed("/message", arguments: message);
});
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
//FCM 푸시 알림 관련 초기화
PushNotification.init();
//flutter_local_notifications 패키지 관련 초기화
PushNotification.localNotiInit();
//백그라운드 알림 수신 리스너
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
//포그라운드 알림 수신 리스너
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
String payloadData = jsonEncode(message.data);
print('Got a message in foreground');
if (message.notification != null) {
//flutter_local_notifications 패키지 사용
PushNotification.showSimpleNotification(
title: message.notification!.title!,
body: message.notification!.body!,
payload: payloadData);
}
});
//메시지 상호작용 함수 호출
setupInteractedMessage();
runApp(
....
);
}
아래부터는 조금 더 자세히 main 코드 부분에 대해 정리했어요.
(1) Background 리스너 등록
앱이 백그라운드 상태에 있을 때 푸시 알림을 캐치하기 위해 리스너를 등록해 줍니다. 리스너 등록은 메인함수 안에서 작성해 주시면 되고요.
단 _firebaseMessagingBackgroundHandler 핸들러 함수 정의는 메인 함수 외부에 해주어야 합니다.
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
아래는 백그라운드 핸들러에 대한 주의사항이 있는데 공식문서 설명이 잘 되어 있길래 가져와보았어요.
onBackgroundMessage 핸들러를 등록하여 백그라운드 메시지를 처리합니다. 메시지가 수신되면 격리가 생성됩니다(Android 전용, iOS/macOS에는 별도의 격리가 필요 없음). 이를 통해 애플리케이션이 실행되지 않고 있더라도 메시지를 처리할 수 있습니다.
백그라운드 메시지 핸들러와 관련하여 유의해야 할 몇 가지 사항이 있습니다.
1. 익명 함수가 아니어야 합니다.
2. 최상위 수준 함수여야 합니다(예: 초기화가 필요한 클래스 메서드가 아님).
3. Flutter 버전 3.3.0 이상을 사용하는 경우 메시지 핸들러는 함수 선언 바로 위에 @pragma('vm:entry-point')로 주석을 달아야 합니다(그렇지 않으면 출시 모드의 경우 트리 쉐이킹 중에 삭제될 수 있음).
핸들러는 애플리케이션 콘텍스트 외부에서 독립적으로 실행되므로 애플리케이션 상태를 업데이트하거나 UI에 영향을 주는 로직을 실행할 수 없습니다. 그러나 HTTP 요청과 같은 로직을 수행하고 IO 작업(예: 로컬 스토리지 업데이트)을 수행하며 다른 플러그인과 통신할 수 있습니다.
(2) Foreground 리스너 등록
화면이 현재 활성화 상태인 포그라운드에 있을 때 알림을 캐치하려면 포그라운드 리스너를 등록해 주고 flutter_local_notifications 패키지 기능을 이용하여 푸시 알람을 보내주어야 합니다.
flutter_local_notifications에 대한 초기화와 설정은 PushNotification 클래스에 작성하였습니다.
포그라운드 상태에서 푸시 알림이 오면 flutter_local_notifications의 푸시 알림 기능을 이용하여 메시지를 보여주도록 합니다.
//포그라운드 화면에서 알림 수신 리스너
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
String payloadData = jsonEncode(message.data);
print('Got a message in foreground');
if (message.notification != null) {
PushNotification.showSimpleNotification(
title: message.notification!.title!,
body: message.notification!.body!,
payload: payloadData);
}
});
(3) setupInteractedMessage 메시지 상호작용 함수
단순히 푸시 알림이 오면 보고 끝나는 것이 아니라 사용자가 터치를 했을 때 어떤 액션이 있어야 할 수 있어요.
공식문서에서는 앱이 종료된 상태와 백그라운드 상태에서 탭 하여 열릴 때 두 가지 시나리오를 모두 처리하는 게 좋다고 합니다.
알림은 시각적인 신호이므로 사용자는 일반적으로 알림을 눌러 상호작용합니다. Android 및 iOS의 기본 동작은 애플리케이션을 여는 것입니다. 애플리케이션이 종료된 상태라면 시작되고, 백그라운드에 있다면 포그라운드로 전환됩니다.
알림의 콘텐츠에 따라 애플리케이션이 열릴 때 사용자의 상호작용을 처리하려고 할 수도 있습니다. 예를 들어 새 채팅 메시지가 알림을 통해 전송되고 사용자가 알림을 누르면 애플리케이션이 열릴 때 특정 대화를 열어야 합니다.
firebase-messaging 패키지는 이 상호작용을 처리하는 두 가지 방법을 제공합니다.
getInitialMessage(): 애플리케이션이 종료된 상태에서 열리면 RemoteMessage가 포함된 Future가 반환됩니다. 소비되면 RemoteMessage가 삭제됩니다.
onMessageOpenedApp: 애플리케이션이 백그라운드 상태에서 열릴 때 RemoteMessage를 게시하는 Stream입니다.
사용자의 원활한 UX를 위해 두 시나리오를 모두 처리하는 것이 좋습니다.
이 함수는 메인 외부에 선언하였고, 메인 함수에서 호출해 줍니다.
앱이 종료된 상태에서 푸시 알림을 텝하거나, 앱이 백그라운드 상태에서 푸시 알림을 탭할 경우 앱이 열리면서 /message 화면으로 이동시키도록 하겠습니다.
//푸시 알림 메시지와 상호작용을 정의합니다.
Future<void> setupInteractedMessage() async {
//앱이 종료된 상태에서 열릴 때 getInitialMessage 호출
RemoteMessage? initialMessage =
await FirebaseMessaging.instance.getInitialMessage();
if (initialMessage != null) {
_handleMessage(initialMessage);
}
//앱이 백그라운드 상태일 때, 푸시 알림을 탭할 때
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
//FCM에서 전송한 data를 처리합니다. /message 페이지로 이동하면서 해당 데이터를 화면에 보여줍니다.
void _handleMessage(RemoteMessage message) {
Future.delayed(const Duration(seconds: 1), () {
navigatorKey.currentState!.pushNamed("/message", arguments: message);
});
}
(4) navigatorKey 추가 설명
navigatorKey는 MaterialApp의 navigatorKey 속성에 설정했습니다.
때문에 Navigator.of를 통해 BuildContext에서 Navigator를 가져올 필요 없이 navigatorKey.currentState로 직접 Navigator를 조작할 수 있습니다. 따라서 BuildContext에서 가져올 수 없는 상황에서 navigatorKey를 이용하여 페이지 이동을 할 수 있습니다.
return MaterialApp(
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
routes: {
...
'/message': (context) => const Message(),
},
....
2) PushNotification class
PushNotification에는 권한 요청이나, 패키지 초기화 작업을 진행하고, 실제 푸시 알림 발송을 담당합니다.
포그라운드에서 받은 푸시 알림이 화면 상단에 나타나지 않는 부분을 해결하기 위해 패키지를 이용하여 발송하는 showSimpleNotification 함수와, HTTP API V1를 이용하여 발송하는 send 함수가 있습니다.
import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:googleapis_auth/auth_io.dart' as auth;
import 'const/app.dart';
class PushNotification {
static final _firebaseMessaging = FirebaseMessaging.instance;
static final FlutterLocalNotificationsPlugin
_flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
static String? _token;
//권한 요청
static Future init() async {
await _firebaseMessaging.requestPermission(
alert: true,
announcement: true,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
//get the device fcm token
_token = await _firebaseMessaging.getToken(); //토큰 얻기
print("device token: $_token");
}
//flutter_local_notifications 패키지 관련 초기화
static Future localNotiInit() async {
// initialise the plugin. app_icon needs to be a added as a drawable resource to the Android head project
const AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
final DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings(
onDidReceiveLocalNotification: (id, title, body, payload) => null,
);
final LinuxInitializationSettings initializationSettingsLinux =
LinuxInitializationSettings(defaultActionName: 'Open notification');
final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
linux: initializationSettingsLinux);
_flutterLocalNotificationsPlugin.initialize(initializationSettings,
onDidReceiveNotificationResponse: onNotificationTap,
onDidReceiveBackgroundNotificationResponse: onNotificationTap);
}
//포그라운드로 알림을 받아서 알림을 탭했을 때 페이지 이동
static void onNotificationTap(NotificationResponse notificationResponse) {
App.navigatorKey.currentState!
.pushNamed('/message', arguments: notificationResponse);
}
//포그라운드에서 푸시 알림을 전송받기 위한 패키지 푸시 알림 발송
static Future showSimpleNotification({
required String title,
required String body,
required String payload,
}) async {
const AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails('pomo_timer_alarm_1', 'pomo_timer_alarm',
channelDescription: '',
importance: Importance.max,
priority: Priority.high,
ticker: 'ticker');
const NotificationDetails notificationDetails =
NotificationDetails(android: androidNotificationDetails);
await _flutterLocalNotificationsPlugin
.show(0, title, body, notificationDetails, payload: payload);
}
//API를 이용한 발송 요청
static Future<void> send({required String title, required String message}) async {
final jsonCredentials =
await rootBundle.loadString('assets/data/auth.json');
final creds = auth.ServiceAccountCredentials.fromJson(jsonCredentials);
final client = await auth.clientViaServiceAccount(
creds,
['https://www.googleapis.com/auth/cloud-platform'],
);
final notificationData = {
'message': {
'token': _token, //기기 토큰
'data': { //payload 데이터 구성
'via': 'FlutterFire Cloud Messaging!!!',
},
'notification': {
'title': title, //푸시 알림 제목
'body': message, //푸시 알림 내용
}
},
};
final response = await client.post(
Uri.parse(
'https://fcm.googleapis.com/v1/projects/${App.senderId}/messages:send'),
headers: {
'content-type': 'application/json',
},
body: jsonEncode(notificationData),
);
client.close();
if (response.statusCode == 200) {
debugPrint(
'FCM notification sent with status code: ${response.statusCode}');
} else {
debugPrint(
'${response.statusCode} , ${response.reasonPhrase} , ${response.body}');
}
}
}
주의사항은 post 발송 요청 시 앞서 Messaging API(HTTP V1) 설정할 때 복사해 두었던 발신자 ID를 넣어주어야 합니다.
POST https://fcm.googleapis.com/v1/projects/[senderId]/messages:send
3) Message 위젯
푸시 알림 발송 시 payload로 넘겨준 데이터를 화면에 보여주기 위해 만든 위젯입니다.
백그라운드에서 FCM 푸시 알림을 받고 푸시 알림을 탭할 때 onMessageOpenedApp가 리슨 하면서 arguments에 RemoteMessage 객체를 전달했었고요.
//main.dart
Future<void> setupInteractedMessage() async {
...
FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
}
void _handleMessage(RemoteMessage message) {
Future.delayed(const Duration(seconds: 1), () {
App.navigatorKey.currentState!.pushNamed("/message", arguments: message);
});
}
포그라운드에서는 flutter_local_notifications 패키지를 이용해 FCM 푸시 알림을 받고, 푸시 알림을 탭할 때 onNotificationTap함수가 호출되면서 arguments로 NotificationResponse를 전달했습니다.
//PushNotification.dart
static Future localNotiInit() async {
...
_flutterLocalNotificationsPlugin.initialize(initializationSettings,
onDidReceiveNotificationResponse: onNotificationTap,
onDidReceiveBackgroundNotificationResponse: onNotificationTap);
}
static void onNotificationTap(NotificationResponse notificationResponse) {
App.navigatorKey.currentState!
.pushNamed('/message', arguments: notificationResponse);
}
두 가지 방식 다 푸시 알림을 탭할 때 /message 화면으로 이동되도록 설정이 되어있으므로, 이전 화면에서 전달된 인수를 가져와야 합니다.
따라서 arguments를 아래 코드처럼 처리를 해주었습니다.
import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class Message extends StatefulWidget {
const Message({super.key});
@override
State<Message> createState() => _MessageState();
}
class _MessageState extends State<Message> {
@override
Widget build(BuildContext context) {
Map payload = {};
final data = ModalRoute.of(context)!.settings.arguments;
if (data is RemoteMessage) { //백그라운드에서 푸시 알람을 탭할 때 처리
payload = data.data;
}
if (data is NotificationResponse) { //포그라운드에서 푸시 알람을 탭할 때 처리
payload = jsonDecode(data.payload!);
}
return Scaffold(
appBar: AppBar(title: Text('Push Alarm Message')),
body: Center(child: Text(payload.toString())),
);
}
}
4. 푸시 알림 발송 테스트 하기
FCM 푸시 알림 발송하는 방법은 2가지가 있는데요.
Firebase 콘솔 발신과 코드에서 직접 API 요청을 통한 발송으로 나뉩니다.
그리고 각각의 발송에서 포그라운드 발송과 백그라운드 발송 테스트를 전부 진행해주어야 합니다.
1) Firebase 콘솔 테스트 설정 하기
코드 작성이 따로 필요 없고 Firebase 콘솔에서 바로 발송을 진행해 주시면 됩니다.
https://console.firebase.google.com/
로그인 - Google 계정
이메일 또는 휴대전화
accounts.google.com
현재 파이어베이스 콘솔을 접속해 보면 플러터와 연동한 것이 전부이기 때문에 아래화면처럼 보입니다.
여기서 왼쪽 하단의 참여메뉴에서 Messaging을 클릭합니다.
첫 번째 캠페인 만들기를 클릭하면 아래 화면과 같은 창이 뜨는데 Firebase 알림 메시지를 선택하고 만들기를 클릭합니다.
알림 제목과 텍스트를 입력합니다.
타깃에서 안드로이드를 선택해 주고 다음을 클릭합니다.
예약은 지금 보내기로 지정합니다.
추가 옵션에서 payload를 통해 전달할 데이터를 테스트로 넣어주고 알림음은 사용 설정됨으로 설정하고 검토를 클릭합니다.
게시 버튼을 클릭하면 바로 푸시 알람이 전송됩니다.
테스트할 때에는 백그라운드 상태와 포그라운드 상태 둘 다 진행해야 합니다.
방금 만든 캠페인 목록에 커서를 두면 우측의 점 3개가 보입니다. 클릭하여 복제를 선택합니다.
테스트 메시지 전송을 클릭합니다.
코드에서 알아낸 토큰을 복사하여 추가한 후 테스트를 반복 진행하면 됩니다.
2) 테스트 결과 화면
각각의 푸시 알림을 탭 하면 아래의 화면처럼 Message 위젯 페이지로 이동하게 되고 화면에는 payload에 실어 날랐던 데이터값이 보입니다.
2) API 발송 테스트
간단하게 버튼을 하나 만들어서 버튼을 클릭하면 3초간의 딜레이를 두고 푸시 알림 테스트를 진행해 보겠습니다.
이미 코드를 다 작성했기 때문에 매우 간단하게 구현할 수 있습니다.
ElevatedButton(onPressed: sendMessage, child: Text('Push Message test')),
void sendMessage() {
Future.delayed(Duration(seconds: 3), () {
PushNotification.send(title: '알림!', message: '쉬는 시간입니다. 휴식을 취해주세요!');
});
}
API로 발송하는 푸시 알람은 PushNotification에서 send 함수를 작성할 때 아래와 같이 작성했었는데요.
//PushNotification class
static Future<void> send({required String title, required String message}) async {
...
final notificationData = {
'message': {
'token': _token,
'data': { //payload data
'via': 'FlutterFire Cloud Messaging!!!',
},
'notification': {
'title': title,
'body': message,
}
},
};
...
}
다시 정리해 보자면 백그라운드 리스너에서는 Message 화면 위젯으로 이동할 때 RemoteMessage 객체를 그대로 전달해서 Message 위젯에서는 data로 접근을 했고요.
//Message 위젯
...
final data = ModalRoute.of(context)!.settings.arguments; //인자값 추출
if (data is RemoteMessage) { //백그라운드에서 받은 푸시 알림의 데이터
payload = data.data;
}
if (data is NotificationResponse) { //포그라운드에서 받은 푸시 알림의 데이터
payload = jsonDecode(data.payload!);
}
포그라운드 리스너에서는 RemoteMessage 객체의 data값을 구해놓고 그 값을 payload 속성에 전달해서 위의 Message 위젯에서는 바로 payload값을 추출해 내서 출력했기 때문에 동일한 결과가 나타납니다.
//main.dart
//포그라운드 화면에서 알림 수신 리스너
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
String payloadData = jsonEncode(message.data);
...
if (message.notification != null) {
PushNotification.showSimpleNotification(
...
payload: payloadData);
}
});
여기까지 FCM을 이용하여 푸시 알람을 구현해 보았습니다.
막상 힘들게 글을 정리하고 나니, 현재 만들고 있는 타이머 앱에서 굳이 FCM 서버 API까지 필요없을 것 같다...? 라는 생각이 스쳤어요...
flutter_local_notifications 패키지로도 충분하겠다라는 생각이 들었고요.
그래서 다음 글은 아예 FCM을 사용하지 않고 flutter_local_notifications 패키지만을 이용하여 안드로이드와 ios까지 푸시 알림 방법을 작성해 보도록 할게요.🙃
'Programming > Dart & Flutter' 카테고리의 다른 글
플러터 앱 이름, 아이콘 변경하기 (0) | 2024.04.04 |
---|---|
플러터 앱에 flutter_local_notifications 패키지 이용하여 푸시 알림 설정하기 (6) | 2024.04.01 |
플러터 앱에 구글 폰트 설정하기 (0) | 2024.03.06 |
플러터 앱에 flex_color_scheme 테마 설정하기 (Hive 연동) (0) | 2024.03.05 |