Flutter中Awesome Notifications后台/终止状态下不显示问题排查
问题根源分析
你的核心问题是:客户端Firebase实时数据库监听仅在APP前台进程存活时有效,当APP进入后台或被终止时,进程被系统挂起/杀死,监听停止运行,无法触发通知生成逻辑。重新打开APP时,监听重启,会一次性拉取之前所有未处理的数据库变更事件,导致通知批量弹出。
Awesome Notifications本身只是本地通知展示工具,它无法让你的APP在后台/终止状态下持续运行数据库监听——这是移动平台的进程限制导致的。
解决方案:改用FCM推送+本地通知展示
最可靠的方式是通过Firebase Cloud Messaging(FCM) 实现跨状态通知,由服务器端(而非客户端)监听数据库变更并触发推送,系统级推送服务能确保APP在后台/终止状态下也能收到通知。
步骤1:集成FCM并获取设备令牌
- 在
pubspec.yaml添加依赖:
dependencies: firebase_core: ^2.15.0 firebase_messaging: ^14.6.5 awesome_notifications: ^0.7.4
- 在
main.dart初始化FCM并保存设备令牌到Firebase数据库(关联用户ID):
void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); // 初始化Awesome Notifications通道 await AwesomeNotifications().initialize( null, [ NotificationChannel( channelKey: 'basic_channel', channelName: '订单通知', channelDescription: '订单状态更新通知', defaultColor: Colors.orange, importance: NotificationImportance.High, channelShowBadge: true, ) ] ); // 请求通知权限 await AwesomeNotifications().isNotificationAllowed().then((isAllowed) { if (!isAllowed) { AwesomeNotifications().requestPermissionToSendNotifications(); } }); // 获取并保存FCM令牌到用户数据中 String? fcmToken = await FirebaseMessaging.instance.getToken(); if (fcmToken != null && loggedInUserID != null) { await FirebaseDatabase.instance.ref('Users/$loggedInUserID/fcmToken').set(fcmToken); } runApp(const MyApp()); }
步骤2:编写Firebase Functions触发器(服务器端)
创建Firebase Functions,监听数据库订单状态变更,向对应用户发送FCM推送:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); // 监听订单接受/拒绝事件 exports.sendOrderStatusNotification = functions.database.ref('/ManagedOrders/{orderId}') .onCreate(async (snapshot, context) => { const orderData = snapshot.val(); const customerID = orderData.customerID; const orderNum = orderData.orderNum; const status = orderData.status; // 获取用户的FCM令牌 const userSnapshot = await admin.database().ref(`/Users/${customerID}/fcmToken`).once('value'); const fcmToken = userSnapshot.val(); if (!fcmToken) return; let title, body; switch(status) { case 'accepted': title = "👍 你的订单(订单号:" + orderNum + ")已接受!"; body = "Nandos正在准备你的餐品"; break; case 'rejected': title = "👎 你的订单(订单号:" + orderNum + ")已被拒绝!"; body = "Nandos目前无法处理你的订单"; break; default: return; } // 发送FCM推送 const message = { notification: {title, body}, token: fcmToken, data: {orderNum, status} }; await admin.messaging().send(message); }); // 监听订单完成事件 exports.sendCompletedOrderNotification = functions.database.ref('/CompleteOrders/{orderId}') .onCreate(async (snapshot, context) => { const orderData = snapshot.val(); const customerID = orderData.customerID; const orderNum = orderData.orderNum; const userSnapshot = await admin.database().ref(`/Users/${customerID}/fcmToken`).once('value'); const fcmToken = userSnapshot.val(); if (!fcmToken) return; const title = "🎆 你的订单(订单号:" + orderNum + ")已准备好可取餐!"; const body = "请前往Nandos取餐"; const message = { notification: {title, body}, token: fcmToken, data: {orderNum, status: 'completed'} }; await admin.messaging().send(message); });
步骤3:客户端处理FCM消息并展示通知
在main.dart中添加FCM消息监听,用Awesome Notifications展示:
void main() async { // ... 前面的初始化代码 ... // 处理前台收到的FCM消息 FirebaseMessaging.onMessage.listen((RemoteMessage message) { if (message.notification != null) { AwesomeNotifications().createNotification( content: NotificationContent( id: DateTime.now().millisecondsSinceEpoch ~/ 1000, channelKey: 'basic_channel', title: message.notification!.title, body: message.notification!.body, payload: message.data, ), ); } }); // 处理点击通知打开APP的逻辑 FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) { // 这里可以跳转到订单详情页,示例: // Navigator.push(context, MaterialPageRoute(builder: (_) => OrderDetailPage(orderNum: message.data['orderNum']))); }); runApp(const MyApp()); }
步骤4:移除客户端数据库监听
删除AuthenticationWrapper中的listenForAcceptedOrders、listenForRejectedOrders、listenForCompletedOrders调用,现在由服务器端触发器处理通知逻辑,无需客户端持续监听。
关键注意事项
- iOS需配置APNs证书,确保推送能正常送达;
- Android需关闭APP的电池优化限制,避免系统拦截后台推送;
- Awesome Notifications的
NotificationImportance需设为High,确保通知在后台能弹出。
内容的提问来源于stack exchange,提问作者Lex
相关产品推荐
相关产品推荐

