iOS挂起状态下,如何用Objective-C实现推送触发的后台代码执行?
解决iOS挂起状态下通过推送触发后台抓取的问题
我来帮你排查这个问题——这在iOS后台任务开发里是个很常见的坑,咱们一步步来梳理:
1. 先确认后台模式配置是否正确
你必须同时开启两个后台能力,缺一个都不行:
- 打开Xcode,进入项目的「Signing & Capabilities」标签,找到「Background Modes」
- 勾选「Background fetch」和「Remote notifications」两项
- 或者直接在
Info.plist里添加UIBackgroundModes数组,包含fetch和remote-notification两个字符串
这是基础中的基础,很多人会漏掉其中一项导致触发失败。
2. 推送Payload必须包含content-available: 1
这是最容易踩的坑!推送的JSON里必须把content-available作为顶级字段(不能放在aps字典里),示例如下:
{ "aps": { "alert": "你的通知内容", "sound": "default" }, "content-available": 1 }
如果是静默推送(不需要显示通知弹窗),aps里可以只保留必要字段,但content-available依然要放在顶级位置:
{ "aps": { "content-available": 1 } }
注意:用Xcode的推送模拟器测试可能不会正确触发后台逻辑,建议用APNs官方工具或者第三方推送平台发送测试推送。
3. 确保你的代码实现正确且规范
你已经实现了带fetchCompletionHandler的didReceiveRemoteNotification方法,但要注意几个关键点:
- 必须调用completionHandler:系统会根据这个回调判断任务是否完成,超过时限(约30秒)没调用的话,应用会被系统终止
- 后台任务不能太耗时:只能做轻量级操作,比如数据同步、小请求,复杂操作会被系统杀掉
- 示例代码参考:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // 这里执行你的后台逻辑,比如更新本地数据、发送统计请求 NSLog(@"后台收到推送,开始执行任务: %@", userInfo); // 根据任务结果调用completionHandler completionHandler(UIBackgroundFetchResultNewData); // 可选值:NewData/NoData/Failed }
另外,如果你用了iOS 13+的SceneDelegate,还要在SceneDelegate里实现对应的方法:
- (void)scene:(UIScene *)scene didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // 同样的逻辑处理 completionHandler(UIBackgroundFetchResultNewData); }
4. 正确的测试姿势
调试后台任务不能直接在Xcode挂起应用(Xcode附加调试会干扰系统的后台调度),正确步骤:
- 将应用安装到真机,断开Xcode连接
- 打开应用,按Home键将其挂起
- 发送带
content-available:1的推送 - 重新打开应用,查看日志确认任务是否执行
你也可以用Xcode的「Debug → Simulate Background Fetch」来模拟定时触发的后台抓取,验证你的任务逻辑是否正常。
关于“应用关闭时无响应”的说明
这里要明确:如果用户把应用从多任务栏划掉(完全关闭),iOS会终止应用进程,此时推送无法触发任何后台代码——这是iOS的安全机制,没有办法绕过。只有应用处于后台/挂起状态时,才能触发推送驱动的后台抓取。
内容的提问来源于stack exchange,提问作者Frederik Frandsen




