无付费Firebase账户时,Flutter聊天应用后台/关闭状态消息通知实现咨询
Flutter Firebase聊天应用后台/离线通知实现方案(无需Cloud Functions)
优先方案:FCM设备到设备推送(免费且可靠)
不用Cloud Functions也能实现跨设备实时通知,通过FCM的设备到设备推送,由发送消息的客户端直接向接收方的设备令牌推送系统通知,不受应用前台/后台/关闭状态限制。
步骤1:获取并存储设备令牌
初始化Firebase Messaging,获取当前用户的设备令牌,并存入Firebase数据库(比如用户文档):
final fcmToken = await FirebaseMessaging.instance.getToken(); // 将令牌更新到用户文档中 await FirebaseFirestore.instance.collection('users').doc(currentUserId).update({ 'fcmTokens': FieldValue.arrayUnion([fcmToken]) });
步骤2:发送消息时触发FCM推送
用户发送新消息时,从数据库中获取接收方的设备令牌,调用FCM API直接推送通知:
import 'package:http/http.dart' as http; import 'dart:convert'; Future<void> sendNotification(String receiverToken, String messageContent) async { const fcmUrl = 'https://fcm.googleapis.com/fcm/send'; final headers = { 'Content-Type': 'application/json', 'Authorization': 'key=YOUR_FCM_SERVER_KEY', // 从Firebase控制台获取 }; final requestBody = jsonEncode({ 'to': receiverToken, 'notification': { 'title': '新消息', 'body': messageContent, 'sound': 'default' }, 'data': { 'chatId': '目标聊天ID', // 可选,用于点击通知跳转对应聊天 } }); await http.post(Uri.parse(fcmUrl), headers: headers, body: requestBody); }
注:
YOUR_FCM_SERVER_KEY可从Firebase控制台「项目设置」→「云消息传递」中获取,免费账户完全支持使用。
步骤3:平台配置
- Android:确保
android/app/src/main/AndroidManifest.xml已包含FCM相关配置(FlutterFire初始化时通常自动添加),并申请POST_NOTIFICATIONS权限。 - iOS:在
ios/Runner/Info.plist中添加推送权限配置,同时在Xcode中开启「推送通知」和「后台模式-远程通知」选项。
备选方案:客户端后台数据监听(适配平台限制)
如果必须通过监听Firebase数据变化触发通知,需针对Android和iOS的后台限制分别适配:
Android 实现
- 开启数据持久化:保证离线状态下数据同步能力
// Realtime Database FirebaseDatabase.instance.setPersistenceEnabled(true); // Firestore FirebaseFirestore.instance.enablePersistence(); - 创建前台服务维持监听:Android后台限制严格,普通后台任务易被回收,需用前台服务保持监听存活:
需在import 'package:flutter_background_service/flutter_background_service.dart'; void initBackgroundService() async { final service = FlutterBackgroundService(); await service.configure( androidConfiguration: AndroidConfiguration( onStart: backgroundServiceCallback, autoStart: true, isForegroundMode: true, // 开启前台模式,避免被系统杀死 ), iosConfiguration: IosConfiguration( autoStart: true, onForeground: backgroundServiceCallback, ), ); } @pragma('vm:entry-point') void backgroundServiceCallback(ServiceInstance service) async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); // 监听未读新消息 FirebaseFirestore.instance.collection('messages') .where('receiverId', isEqualTo: currentUserId) .where('isRead', isEqualTo: false) .snapshots() .listen((snapshot) { for (var docChange in snapshot.docChanges) { if (docChange.type == DocumentChangeType.added) { // 调用本地通知插件发送通知 showLocalNotification(docChange.data()['content']); } } }); }AndroidManifest.xml中添加权限:<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
iOS 实现
iOS后台限制更严格,只能通过定期后台刷新实现近似实时的消息检测:
- 开启后台模式:在
ios/Runner/Info.plist中添加:<key>UIBackgroundModes</key> <array> <string>fetch</string> <string>remote-notification</string> </array> - 定期触发数据检查:使用
background_fetch插件每隔15分钟(iOS允许的最小间隔)检查一次未读消息:
注:iOS后台刷新的执行时机由系统控制,无法保证实时性。import 'package:background_fetch/background_fetch.dart'; void initBackgroundFetch() async { BackgroundFetch.configure( BackgroundFetchConfig( minimumFetchInterval: 15, ), (String taskId) async { // 查询未读消息 final unreadMessages = await FirebaseFirestore.instance .collection('messages') .where('receiverId', isEqualTo: currentUserId) .where('isRead', isEqualTo: false) .get(); if (unreadMessages.docs.isNotEmpty) { showLocalNotification('您有${unreadMessages.docs.length}条未读消息'); } BackgroundFetch.finish(taskId); }, ); }
总结
优先选择FCM设备到设备推送,免费、实时且跨平台可靠;客户端后台监听仅作为备选方案,受限于平台后台限制,实时性和稳定性较差。
内容的提问来源于stack exchange,提问作者Yash Sahu
相关产品推荐
相关产品推荐

