iOS端已终止Flutter App接收静默推送时调用方法的问题
iOS端应用终止时静默推送触发本地通知解决方案
针对你遇到的Flutter应用在iOS终止状态下无法触发静默推送处理逻辑的问题,核心原因是iOS对后台/终止状态下的推送机制有严格限制,且FirebaseMessaging.onBackgroundMessage仅在应用处于后台(未终止)时有效,应用终止时Flutter引擎未启动,无法执行Dart层代码。以下是具体解决步骤:
1. 确保推送Payload格式正确
静默推送必须满足iOS APNs的要求,同时适配Firebase的格式:
- 必须包含
content_available: true(Firebase字段,会自动转换为APNs的content-available: 1) - 不能包含
alert、sound、badge等触发系统默认通知的字段(否则会被识别为普通通知,而非静默推送) - 推送示例(通过Firebase HTTPv1 API发送):
{ "message": { "token": "你的FCM_TOKEN", "content_available": true, "priority": "high", "data": { "title": "本地通知标题", "body": "本地通知内容", "custom_key": "自定义数据" } } }
2. 配置iOS后台权限
在Xcode中开启必要的后台模式:
- 打开项目的
Signing & Capabilities标签 - 添加
Background Modes权限,勾选Remote notifications和Background fetch - 确保
Info.plist中FirebaseAppDelegateProxyEnabled值为YES(默认已配置,若修改过需恢复)
3. 原生层处理应用终止状态的静默推送
应用终止时,Flutter引擎未启动,需在iOS原生代码中处理推送并发送本地通知:
修改AppDelegate.swift:
import UIKit import Flutter import Firebase import UserNotifications @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { FirebaseApp.configure() UNUserNotificationCenter.current().delegate = self GeneratedPluginRegistrant.register(with: self) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } // 处理终止/后台状态下的静默推送 override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // 验证是否为静默推送 if let contentAvailable = userInfo["content-available"] as? String, contentAvailable == "1" { // 从推送data中提取通知内容 if let data = userInfo["data"] as? [String: Any], let title = data["title"] as? String, let body = data["body"] as? String { // 创建并发送本地通知 let content = UNMutableNotificationContent() content.title = title content.body = body content.sound = UNNotificationSound.default let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) UNUserNotificationCenter.current().add(request) { error in if let error = error { print("本地通知发送失败: \(error.localizedDescription)") } } } } completionHandler(.newData) } // 前台收到通知时的展示配置(可选) override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.alert, .sound, .badge]) } }
4. Dart层处理后台(非终止)状态的静默推送
对于应用处于后台(未终止)的情况,使用flutter_local_notifications发送本地通知,配合FirebaseMessaging.onBackgroundMessage:
步骤1:添加依赖
在pubspec.yaml中添加:
dependencies: flutter_local_notifications: ^16.1.0
步骤2:初始化本地通知并修改处理逻辑
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; final FlutterLocalNotificationsPlugin _localNotifications = FlutterLocalNotificationsPlugin(); // 初始化本地通知 Future<void> _initLocalNotifications() async { const AndroidInitializationSettings androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher'); final DarwinInitializationSettings iosSettings = DarwinInitializationSettings( requestAlertPermission: true, requestBadgePermission: true, requestSoundPermission: true, ); final InitializationSettings settings = InitializationSettings( android: androidSettings, iOS: iosSettings, ); await _localNotifications.initialize(settings); } // 后台消息处理逻辑 Future<void> handleBackgroundMessage(RemoteMessage message) async { print("Handling background message: ${message.messageId}"); // 发送本地通知 const AndroidNotificationDetails androidDetails = AndroidNotificationDetails( 'silent_push_channel', '静默推送频道', channelDescription: '由静默推送触发的本地通知', importance: Importance.max, priority: Priority.high, ); const DarwinNotificationDetails iosDetails = DarwinNotificationDetails(); const NotificationDetails notificationDetails = NotificationDetails( android: androidDetails, iOS: iosDetails, ); await _localNotifications.show( 0, message.data['title'], message.data['body'], notificationDetails, payload: message.data['custom_key'], ); } class FirebaseApi { final _firebaseMessaging = FirebaseMessaging.instance; Future<String?> initNotifications() async { await _firebaseMessaging.requestPermission(); await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true, ); // 初始化本地通知 await _initLocalNotifications(); FirebaseMessaging.onBackgroundMessage(handleBackgroundMessage); final fcmToken = await _firebaseMessaging.getToken(); print('FCM Token: $fcmToken'); return fcmToken; } }
注意事项
- iOS静默推送有频率限制,苹果会限制过于频繁的推送请求,避免设备耗电
- 测试时需先通过Xcode安装应用,手动打开后再终止,再发送推送(直接从Xcode终止应用可能无法触发推送逻辑)
- 若使用Firebase控制台发送推送,需在「高级选项」中开启「内容可用」,且不要填写通知标题/内容,否则会转为普通通知
内容的提问来源于stack exchange,提问作者B. Bogdan
相关产品推荐
相关产品推荐

