우선, 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>
<!-- 리시버 등록끝 -->
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. 아래 객체는 스트림 컨트롤러 형태로 받는다.
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()" 함수로 확인하고
메인 앱화면을 다시 열지 기존꺼(백그라운드 앱) 열지 판단합니다.
'firebase' 카테고리의 다른 글
| cloud functions functions.config() 사용 중단.. (2) | 2025.08.05 |
|---|---|
| firebase 에서 추출한 데이타를 flutter 위젯에 셋팅하는 방법입니다. (0) | 2025.07.15 |
| firebase-admin 을 활용해 cloud function 배포 방법입니다. (firebase deploy) (0) | 2025.06.30 |
| FCM 에서 사용할 토큰을 구하는 방법입니다. (0) | 2025.06.30 |
| FCM 메세지 유형 /셋팅(firebase cloud messaging)중 앱에서 작성,fcm중계되어서 수신앱에 도착 (0) | 2025.06.26 |