Flutter推送插件中application:didReceiveRemoteNotification:fetchCompletionHandler:未触发求助
我之前也碰到过类似的iOS推送回调触发问题,结合Flutter插件的开发场景,咱们来拆解下原因和可行的解决办法:
问题根源分析
首先得明确:application:didReceiveRemoteNotification:fetchCompletionHandler:是iOS专门用于**后台处理推送(含静默推送)**的回调,苹果对它的触发有严格的规则,不是所有通知都会走这个方法。你遇到的两种情况刚好对应了它不触发的核心原因:
- 旧回调回退:
application:didReceiveRemoteNotification:是iOS 10之前的旧回调,当你的代码没适配新的UNUserNotificationCenter框架时,系统会回退到这个旧方法,但它不支持后台处理的完成回调机制。 - 仅满足部分静默推送条件:
content_available: true是触发后台回调的必要条件,但不是充分条件,还有其他配置和负载格式要求没满足,导致只有加了这个字段时才偶尔触发。
具体来说,可能的触发障碍包括:
- 未开启iOS后台刷新权限
- 未适配iOS 10+的
UserNotifications框架 - 推送负载的格式/类型不符合苹果要求
- Flutter插件的原生回调注册不完整
- 测试环境的限制(比如Xcode运行时的后台行为和正式环境不一致)
解决步骤
1. 先确认iOS后台权限配置
这是基础中的基础,没开权限一切都是白搭:
- 打开Xcode项目,进入
Signing & Capabilities页面 - 添加
Background Modes能力,勾选Remote notifications选项
2. 适配iOS 10+的通知框架
从iOS 10开始,苹果官方推荐使用UNUserNotificationCenter来处理通知,旧的UIApplicationDelegate回调优先级会降低。在Flutter插件的iOS原生代码里,需要同时兼容新老框架:
// 插件注册时的代码(registerWithRegistrar:方法内) - (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { // 注册UNUserNotificationCenter代理 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; // 注册远程通知权限 [[UIApplication sharedApplication] registerForRemoteNotifications]; // 初始化MethodChannel用于和Flutter侧通信 self.channel = [FlutterMethodChannel methodChannelWithName:@"your_notification_channel" binaryMessenger:[registrar messenger]]; } // 实现后台推送回调,务必调用completionHandler - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // 将通知数据传递给Flutter侧 [self.channel invokeMethod:@"onRemoteNotificationReceived" arguments:userInfo]; // 必须调用这个回调,告诉苹果处理完成,否则会被限制推送频率 completionHandler(UIBackgroundFetchResultNewData); } // 兼容前台收到通知的情况(可选) - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { // 可自定义前台通知的展示方式,比如显示横幅 completionHandler(UNNotificationPresentationOptionBanner); }
3. 严格按照苹果要求构造推送负载
根据你的需求,分两种情况调整推送内容:
情况1:纯静默推送(不显示通知,仅后台处理)
负载必须满足:
{ "aps": { "content-available": 1, "sound": "" // 空字符串避免播放声音 }, "custom_data": { "key": "your_custom_content" } }
同时推送请求的HTTP头必须设置:
apns-push-type: background(iOS 13+强制要求)apns-priority: 5(后台推送用低优先级,苹果推荐)
情况2:显示通知+后台处理
此时负载需要包含UI字段,同时补充后台处理所需参数:
{ "aps": { "alert": { "title": "通知标题", "body": "通知内容" }, "content-available": 1, "mutable-content": 1, // 可选,如需修改通知内容则添加 "sound": "default" }, "custom_data": { "key": "your_custom_content" } }
对应的HTTP头设置:
apns-push-type: alertapns-priority: 10
4. 检查Flutter侧的桥接逻辑
确保Dart代码正确监听原生传递的通知数据:
final MethodChannel _notificationChannel = MethodChannel('your_notification_channel'); @override void initState() { super.initState(); _setupNotificationListener(); } void _setupNotificationListener() { _notificationChannel.setMethodCallHandler((MethodCall call) async { if (call.method == 'onRemoteNotificationReceived') { // 处理通知数据 Map<String, dynamic> notificationData = call.arguments; print('收到远程通知:$notificationData'); // 这里可以添加你的业务逻辑,比如本地存储、触发状态更新等 } }); }
5. 正确测试后台推送
注意:用Xcode直接运行APP后切后台测试,可能会出现回调不触发的情况,因为调试环境的后台行为和正式环境有差异。正确的测试方式是:
- 用
Product > Archive打包生成Ad Hoc或Development包,安装到真实设备上 - 用APNs测试工具(比如Pusher)发送符合格式要求的推送
内容的提问来源于stack exchange,提问作者Bathant Hegazy
相关产品推荐
相关产品推荐

