<aside>
💡 파이어베이스 유틸 클래스의 경우 메인화면에서 사전에 작동되는게 아니기 때문에 컴파일러가 해당 클래스를 미사용 클래스로 판단하고 삭제한다.
이를 방지하기 위해 백그라운드 핸들러 메서드에 @pragma('vm:entry-point')
코드를 적용해서 런타임에 실행하는 메서드임을 컴파일러에게 확실히 알려서 해당 부분을 최적화하지 않게 해야한다.
</aside>
WidgetsFlutterBinding.ensureInitialized();
함수를 main함수 시작부분에 정의해두는게 좋다.await FirebaseUtils.setUpFlutterNotifications();
와 await setUpFlutterNotifications();
은 main함수 부분과 백그라운드 핸들러 두 부분 모두 구현해야 한다.Notifications overview | Android Developers
Create and manage notification channels | Android Developers
import 'dart:async';
import 'package:bosanjin_protector_m2s/firebase_options.dart';
import 'package:bosanjin_protector_m2s/retrofit/service/login_service.dart';
import 'package:dio/dio.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart';
class FirebaseUtils {
FirebaseUtils._();
static bool _isFlutterLocalNotificationsInitialized = false;
static late final String fcmToken;
static late final AndroidNotificationChannel channel;
static late final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
@pragma('vm:entry-point')
static Future<void> firebaseMessagingBackgroundHandler(
final RemoteMessage message,
) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await setUpFlutterNotifications();
showFlutterNotification(message);
}
static Future<void> setUpFlutterNotifications() async {
if (_isFlutterLocalNotificationsInitialized) {
return;
}
final fcmInstance = FirebaseMessaging.instance;
channel = const AndroidNotificationChannel(
'high_importance_channel',
'알람',
description: '응급상황 발생 시 전송을 위한 알람 채널입니다.',
importance: Importance.max,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
// 아이폰용 설정
// await fcmInstance.setForegroundNotificationPresentationOptions(
// alert: true,
// badge: true,
// sound: false,
// );
// 플러터파이어 홈페이지 예시 코드지만 해당 코드로 구현할 경우 flutterLocalNotificationsPlugin이 초기화되지 않았다는 오류가 발생한다.
// await flutterLocalNotificationsPlugin
// .resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
// ?.createNotificationChannel(channel);
await flutterLocalNotificationsPlugin.initialize(
InitializationSettings(
android: AndroidInitializationSettings(
'@mipmap/ic_launcher',
),
),
);
fcmInstance.onTokenRefresh.listen(
(final String event) {
sendFcmToken(event);
_setPref(event);
},
);
fcmToken = await fcmInstance.getToken() ?? '';
// fcmInstance.getInitialMessage().then((final RemoteMessage? value) {
// final a = value;
// });
_isFlutterLocalNotificationsInitialized = true;
}
static void showFlutterNotification(final RemoteMessage message) {
final data = message.data;
// final android = message.notification?.android;
// if (data != null && android != null) {
if (data.isNotEmpty) {
flutterLocalNotificationsPlugin.show(
data.hashCode,
data['title'],
data['body'],
NotificationDetails(
android: AndroidNotificationDetails(
channel.id, channel.name, channelDescription: channel.description, importance: Importance.max,
// icon: Assets.imagesSplashIcon2,
),
),
);
}
}
static Future<void> _setPref(final String fcmToken) async {
final pref = await SharedPreferences.getInstance();
unawaited(pref.setString('fcmToken', fcmToken));
}
static Future<void> sendFcmToken(final String fcmToken) async {
final login_service = await Login_Service(
Dio(),
).fcm_token_send(fcmToken);
}
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
await FirebaseUtils.setUpFlutterNotifications();
FirebaseMessaging.onMessage.listen(FirebaseUtils.showFlutterNotification);
FirebaseMessaging.onBackgroundMessage(FirebaseUtils.firebaseMessagingBackgroundHandler);
runApp(const MyApp());
}
웹에서 FCM 적용하려면 참고
FlutterFire Push Notifications via FCM — Flutter Web
config 관련 정보는 파이어베이스 프로젝트 설정 - 일반 - 웹 앱 선택하면 나온다.
프로젝트 설정 - 클라우드 메시징에 들어가서 웹 앱 구성에서 키를 생성해야 한다.