You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter推送插件中application:didReceiveRemoteNotification:fetchCompletionHandler:未触发求助

我之前也碰到过类似的iOS推送回调触发问题,结合Flutter插件的开发场景,咱们来拆解下原因和可行的解决办法:

问题根源分析

首先得明确:application:didReceiveRemoteNotification:fetchCompletionHandler:是iOS专门用于**后台处理推送(含静默推送)**的回调,苹果对它的触发有严格的规则,不是所有通知都会走这个方法。你遇到的两种情况刚好对应了它不触发的核心原因:

  1. 旧回调回退:application:didReceiveRemoteNotification:是iOS 10之前的旧回调,当你的代码没适配新的UNUserNotificationCenter框架时,系统会回退到这个旧方法,但它不支持后台处理的完成回调机制。
  2. 仅满足部分静默推送条件: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: alert
  • apns-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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 22:57:43