Flutter实现后台/关闭状态下自动获取FCM推送并存储
解决Flutter FCM后台/关闭状态下自动保存推送消息到通知中心的问题
核心问题原因
你当前的问题本质是FCM消息类型的限制:
- 如果推送的是纯通知消息(仅包含
notification字段),当App处于后台或关闭状态时,消息会被系统接管,只有用户点击通知后才会传递给App,不会触发firebaseMessagingBackgroundHandler。 - 只有数据消息(仅包含
data字段)或通知+数据混合消息,才能在后台/关闭状态下触发firebaseMessagingBackgroundHandler,让App自动处理消息内容。
解决方案步骤
1. 调整FCM推送消息格式(关键)
必须发送数据消息或混合消息,示例如下:
// 纯数据消息(后台/关闭状态下直接触发Handler) { "to": "DEVICE_TOKEN", "data": { "title": "产品更新", "body": "全新功能上线", "cta": "查看详情", "news_id": "123" } } // 混合消息(系统展示通知,同时Handler接收data字段) { "to": "DEVICE_TOKEN", "notification": { "title": "产品更新", "body": "全新功能上线" }, "data": { "cta": "查看详情", "news_id": "123" } }
2. 修复Android配置
- 确认
AndroidManifest.xml中已配置FCM后台服务(Flutter插件通常自动配置,可手动检查):
<service android:name="com.google.firebase.messaging.FirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
- 确保已申请Android 12+所需的
POST_NOTIFICATIONS权限,在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
3. 完善iOS配置
- 补全
AppDelegate.swift的UNUserNotificationCenterDelegate实现,确保后台消息能被正确处理:
import UIKit import Flutter import flutter_local_notifications import Firebase @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) FirebaseApp.configure() if #available(iOS 10.0, *) { UNUserNotificationCenter.current().delegate = self } // 请求通知权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in if granted { DispatchQueue.main.async { application.registerForRemoteNotifications() } } } return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } @available(iOS 10.0, *) extension AppDelegate: UNUserNotificationCenterDelegate { // 前台收到通知时的处理 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.banner, .sound]) } // 点击通知后的处理 func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { completionHandler() } }
- 开启iOS后台刷新权限:在
Info.plist中添加:
<key>UIBackgroundModes</key> <array> <string>remote-notification</string> </array>
- 在Xcode的
Signing & Capabilities中,勾选Background Modes下的Remote notifications选项。
4. 优化Flutter后台Handler代码
移除不必要的Isolate通信逻辑,直接在后台Handler中完成消息保存(后台Isolate可直接使用SharedPreferences):
static Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async { // 必须初始化Firebase,后台Isolate不会自动初始化 await Firebase.initializeApp(); final prefs = await SharedPreferences.getInstance(); List<String> notificationList = prefs.getStringList('notification') ?? []; // 提取消息数据,无论是纯数据消息还是混合消息的data字段 final messageData = message.data; final notificationContent = jsonEncode({ 'title': messageData['title'] ?? '', 'body': messageData['body'] ?? '', 'cta': messageData['cta'] ?? '', 'timestamp': DateTime.now().millisecondsSinceEpoch.toString() }); notificationList.add(notificationContent); await prefs.setStringList('notification', notificationList); }
5. 验证触发逻辑
- 后台/关闭状态下发送数据消息,
firebaseMessagingBackgroundHandler会自动触发,消息直接保存到SharedPreferences。 - 用户打开App后,通知中心模块读取SharedPreferences即可展示所有未读消息。
常见坑点
- 不要发送纯通知消息,否则后台/关闭状态下无法触发Handler。
- iOS后台消息处理时间限制在30秒内,Handler中避免耗时操作。
- 确保
firebaseMessagingBackgroundHandler是顶级静态函数,不能包含上下文或类成员引用。
内容的提问来源于stack exchange,提问作者Renato Florencia
相关产品推荐
相关产品推荐

