FlutterFire CLI로 Android, iOS 세팅을 하고 백그라운드, 포그라운드, 터미네이티드 상태에서 메세지를 보내는 앱을 작성한다.
import 'package:eqms_test/firebase/firebase_api.dart';
import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform
);
await FirebaseApi().initNotifications();
runApp(MaterialApp(
home: MyApp(),
));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Hello World'),
),
);
}
}
import 'dart:convert';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
Future<void> handleBackgroundMessage(RemoteMessage message) async {
print('Title: ${message.notification?.title}');
print('Body: ${message.notification?.body}');
print('Payload: ${message?.data}');
}
class FirebaseApi {
final _firebaseMessaging = FirebaseMessaging.instance;
final _localNotifications = FlutterLocalNotificationsPlugin();
void handleMessage(RemoteMessage? message){
if (message == null ) return;
print('Title: ${message.notification?.title}');
print('Body: ${message.notification?.body}');
print('Payload: ${message?.data}');
}
final _androidChannel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description: 'This channel is used for important notifications.', // description
importance: Importance.max,
);
Future initLocalNotification() async {
const iOS = DarwinInitializationSettings();
const android = AndroidInitializationSettings('@drawable/ic_launcher');
const settings = InitializationSettings(android: android, iOS: iOS);
await _localNotifications.initialize(
settings,
onDidReceiveNotificationResponse: (payload) {
final message = RemoteMessage.fromMap(jsonDecode(payload.toString()));
handleMessage(message);
}
);
final platform = _localNotifications.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
await platform?.createNotificationChannel(_androidChannel);
}
Future initPushNotifications() async {
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
badge: true,
sound: true,
);
FirebaseMessaging.instance.getInitialMessage().then(handleMessage);
FirebaseMessaging.onMessageOpenedApp.listen(handleMessage);
FirebaseMessaging.onBackgroundMessage(handleBackgroundMessage);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
final notification = message.notification;
if (notification == null) return;
_localNotifications.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
_androidChannel.id,
_androidChannel.name,
channelDescription: _androidChannel.description,
icon: '@drawable/ic_launcher',
// other properties...
),
),
payload: jsonEncode(message.toMap()),
);
});
}
Future<void> initNotifications() async {
await _firebaseMessaging.requestPermission();
final fCMToken = await _firebaseMessaging.getToken();
print('Token: ${fCMToken}');
initPushNotifications();
}
}
Future initLocalNotification() async {
const iOS = DarwinInitializationSettings();
const android = AndroidInitializationSettings('@drawable/ic_launcher');
const settings = InitializationSettings(android: android, iOS: iOS);
await _localNotifications.initialize(
settings,
onDidReceiveNotificationResponse: (payload) {
final message = RemoteMessage.fromMap(jsonDecode(payload.toString()));
handleMessage(message);
}
);
final platform = _localNotifications.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
await platform?.createNotificationChannel(_androidChannel);
}
Future initPushNotifications() async {
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true, // Required to display a heads up notification
badge: true,
sound: true,
);
FirebaseMessaging.instance.getInitialMessage().then(handleMessage);
FirebaseMessaging.onMessageOpenedApp.listen(handleMessage);
FirebaseMessaging.onBackgroundMessage(handleBackgroundMessage);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
final notification = message.notification;
if (notification == null) return;
_localNotifications.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
_androidChannel.id,
_androidChannel.name,
channelDescription: _androidChannel.description,
icon: '@drawable/ic_launcher',
// other properties...
),
),
payload: jsonEncode(message.toMap()),
);
});
}
initLocalNotification이 언제 호출되는가 했는데, _localNotifications.show를 사용할 때 초기화를 사용하기 위해 호출된다고 하더라.
Future<void> initNotifications() async {
await _firebaseMessaging.requestPermission();
final fCMToken = await _firebaseMessaging.getToken();
print('Token: ${fCMToken}');
initPushNotifications();
}
모두 다 정상작동된다! 잘 안되면 ADK 문제니 잘 기다려보자...
여담: Flutterfire로 설정하는 거 너무 빠르고 편하다... 둘 다 자동으로 등록해주니까 오류 걱정없이 맘 편히 사용할 수 있다. 진작에 쓸 걸...
출처
https://velog.io/@kyj5394/WidgetsFlutterBinding.ensureInitialized-%EC%82%AC%EC%9A%A9-%EC%9D%B4%EC%9C%A0
https://firebase.flutter.dev/docs/messaging/notifications/
https://www.youtube.com/watch?v=k0zGEbiDJcQ&t=365s