| import 'dart:developer';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
class MessagingService {
static String? fcmToken; // Variable to store the FCM token
static final MessagingService _instance = MessagingService._internal();
factory MessagingService() => _instance;
MessagingService._internal();
final FirebaseMessaging _fcm = FirebaseMessaging.instance;
Future<void> init(BuildContext context) async {
// Requesting permission for notifications
NotificationSettings settings = await _fcm.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
debugPrint(
'User granted notifications permission: ${settings.authorizationStatus}');
// Retrieving the FCM token
fcmToken = await _fcm.getToken();
log('fcmToken: $fcmToken');
// Handling background messages using the specified handler
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
// Listening for incoming messages while the app is in the foreground
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
debugPrint('Got a message whilst in the foreground!');
debugPrint('Message data: ${message.notification!.title.toString()}');
if (message.notification != null) {
if (message.notification!.title != null &&
message.notification!.body != null) {
_showNotificationDialog(context, message);
}
}
});
// Handling the initial message received when the app is launched from dead (killed state)
// When the app is killed and a new notification arrives when user clicks on it
// It gets the data to which screen to open
_fcm.getInitialMessage().then((message) {
if (message != null) {
_handleNotificationClick(context, message);
}
});
// Handling a notification click event when the app is in the background
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
debugPrint(
'onMessageOpenedApp: ${message.notification!.title.toString()}');
_handleNotificationClick(context, message);
});
}
// Handling a notification click event by navigating to the specified screen
void _handleNotificationClick(BuildContext context, RemoteMessage message) {
final notificationData = message.data;
if (notificationData.containsKey('screen')) {
final screen = notificationData['screen'];
Navigator.of(context).pushNamed(screen);
}
}
// Show a dialog when a notification is received
void _showNotificationDialog(BuildContext context, RemoteMessage message) {
final notificationData = message.data;
final screen = notificationData['screen'];
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return PopScope(
canPop: false,
child: AlertDialog(
title: Text(message.notification!.title!),
content: Text(message.notification!.body!),
actions: [
if (notificationData.containsKey('screen'))
TextButton(
onPressed: () {
Navigator.pop(context);
Navigator.of(context).pushNamed(screen);
},
child: const Text('Open Screen'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Dismiss'),
),
],
),
);
},
);
}
}
// Handler for background messages
@pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
debugPrint('Handling a background message: ${message.notification!.title}');
}
|
這段程式碼定義了一個名為 MessagingService 的類別,該類別用於處理 Firebase Cloud Messaging(FCM)的相關操作。FCM 是一種允許您向應用程式用戶發送通知的服務。
在 MessagingService 類別中,我們首先定義了一個靜態變數 fcmToken 來存儲 FCM token,以及一個私有的 FirebaseMessaging 實例 _fcm。
init 方法是用來初始化 FCM 的。在這個方法中,我們首先請求用戶允許接收通知,然後獲取並存儲 FCM token。接著,我們設定了一個背景消息處理器,並開始監聽前台和背景的消息。如果收到消息,我們會顯示一個對話框,並在用戶點擊通知時導航到指定的螢幕。
_handleNotificationClick 方法是用來處理用戶點擊通知的事件。在這個方法中,我們檢查消息數據中是否包含 ‘screen’ 鍵,如果包含,我們就導航到該鍵對應的螢幕。
_showNotificationDialog 方法是用來顯示一個包含通知標題和內容的對話框。如果消息數據中包含 ‘screen’ 鍵,對話框中還會有一個 ‘Open Screen’ 按鈕,用戶點擊這個按鈕會導航到該鍵對應的螢幕。
最後,我們定義了一個背景消息處理器 _firebaseMessagingBackgroundHandler。這個處理器會在應用程式在背景運行時接收到消息時被調用。在這個處理器中,我們只是簡單地打印出了消息的標題。如果您需要在背景中使用其他 Firebase 服務,例如 Firestore,您需要在使用這些服務之前調用 initializeApp 方法。
需加入final _messagingService = MessagingService();於Stste裡
需修改initSate()
| void initState() {
super.initState();
_messagingService.init(context);
}
|