Flutter iOS应用终止时如何实现FCM数据消息推送通知?
解决Flutter iOS应用终止后无法接收FCM Data消息的问题
核心原因说明
iOS系统对纯FCM Data消息的处理有严格限制:当APP处于终止状态时,纯Data消息不会触发系统唤醒APP,也不会显示通知。只有同时包含notification和data字段的混合推送消息,才会由APNs在通知栏展示,用户点击后才会将data传递给APP。这是iOS系统的原生限制,第三方插件无法绕过。
方案一:Flutter纯FCM配置优化
1. 调整推送消息结构
发送推送时必须同时包含notification和data字段,示例Payload:
{ "to": "/topics/your_topic", "notification": { "title": "通知标题", "body": "通知内容" }, "data": { "key1": "value1", "key2": "value2" }, "apns": { "payload": { "aps": { "content-available": 1 } } } }
content-available: 1用于触发后台刷新,确保后台状态下能正常接收数据。
2. 完善FCM插件配置
使用官方firebase_messaging插件,确保以下配置正确:
- 在
Info.plist中添加后台权限配置:<key>UIBackgroundModes</key> <array> <string>remote-notification</string> </array> <key>FirebaseAppDelegateProxyEnabled</key> <false/> - 配置后台消息处理器与初始化逻辑:
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await Firebase.initializeApp(); print('收到后台消息: ${message.data}'); // 这里添加自定义消息处理逻辑 } void main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); // 请求完整推送权限(必须包含alert) NotificationSettings settings = await FirebaseMessaging.instance.requestPermission( alert: true, badge: true, sound: true, ); // 订阅目标主题 await FirebaseMessaging.instance.subscribeToTopic('your_topic'); runApp(MyApp()); } - 监听APP从终止状态被通知唤醒的情况:
@override void initState() { super.initState(); FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) { if (message != null) { print('终止状态启动收到数据: ${message.data}'); // 跳转对应页面或执行业务逻辑 } }); }
方案二:Swift原生结合Method Channel实现
如果插件配置后仍存在问题,可通过原生代码直接处理推送,再将数据传递给Flutter:
1. 原生端配置(Swift)
修改AppDelegate.swift
import UIKit import Flutter import FirebaseMessaging import UserNotifications @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { FirebaseApp.configure() // 请求推送权限 UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in if granted { DispatchQueue.main.async { application.registerForRemoteNotifications() } } } // 处理APP终止状态下由通知启动的情况 if let remoteNotification = launchOptions?[.remoteNotification] as? [String: Any] { let channel = FlutterMethodChannel(name: "com.example.push_handler", binaryMessenger: window?.rootViewController as! FlutterBinaryMessenger) channel.invokeMethod("receivePushData", arguments: remoteNotification) } GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } // 处理后台/前台收到的推送 override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { let channel = FlutterMethodChannel(name: "com.example.push_handler", binaryMessenger: window?.rootViewController as! FlutterBinaryMessenger) channel.invokeMethod("receivePushData", arguments: userInfo) completionHandler(.newData) } // 绑定APNs Token到FCM并订阅主题 override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Messaging.messaging().apnsToken = deviceToken Messaging.messaging().subscribe(toTopic: "your_topic") { error in if let error = error { print("订阅主题失败: \(error.localizedDescription)") } else { print("订阅主题成功") } } } }
2. Flutter端监听Method Channel
class _MyAppState extends State<MyApp> { late MethodChannel _pushChannel; @override void initState() { super.initState(); _pushChannel = MethodChannel('com.example.push_handler'); _pushChannel.setMethodCallHandler((MethodCall call) async { if (call.method == 'receivePushData') { Map<String, dynamic> pushData = Map<String, dynamic>.from(call.arguments as Map); print('原生传递的推送数据: $pushData'); // 这里添加Flutter端的消息处理逻辑 } }); } @override Widget build(BuildContext context) { return MaterialApp(home: Scaffold(body: Center(child: Text('Push Demo')))); } }
关键注意事项
- 必须使用真实iOS设备测试,模拟器无法接收APNs推送。
- 确保APNs证书和FCM的
GoogleService-Info.plist已正确配置到Xcode项目中。 - 推送权限必须请求到
alert权限,provisional权限在终止状态下不会触发通知展示。
内容的提问来源于stack exchange,提问作者Sanket Vanani
相关产品推荐
相关产品推荐

