2、Background Modes Capability:如何在Xcode中开启后台模式、Info.plist配置详解、常见的后台模式类型
好,咱们直接进入正题。后台模式这东西,说简单也简单,说复杂也复杂。我刚开始接触iOS后台开发时,第一反应就是:不就是勾个开关吗?结果后来踩了不少坑。今天我就把这块掰开揉碎了讲给你听。
2.1 如何在Xcode中开启后台模式
其实操作很简单,但很多人容易忽略一个关键点。来,我带你走一遍流程。
- 选中项目Target:在Xcode左侧导航栏里,点一下你的项目文件,然后找到对应的Target。
- 进入Signing & Capabilities:顶部选项卡里,点「Signing & Capabilities」。
- 添加Capability:点击左上角的「+ Capability」按钮,在弹出的搜索框里输入「Background Modes」。
- 勾选需要的模式:添加成功后,你会看到一堆复选框。嗯,这里要注意,别一股脑全勾上。
核心要点:开启后台模式后,你的App才能在后台继续执行特定任务。否则,系统会在几秒内把你的App挂起。
我个人习惯是,只勾选当前功能真正需要的模式。为什么?因为每个后台模式都会增加电量消耗,审核时也可能被追问。你想想看,一个计算器App勾了「Audio, AirPlay, and Picture in Picture」,审核人员会怎么想?
2.2 Info.plist配置详解
当你勾选了后台模式,Xcode会自动往Info.plist里写入一个叫UIBackgroundModes的键。这个键的值是一个数组,里面装着你勾选的那些模式对应的字符串。
说白了,Xcode的UI操作只是帮你写plist文件。你也可以手动编辑Info.plist,效果完全一样。我有时候为了快速调试,会直接改plist源码。
// Info.plist 中的 UIBackgroundModes 示例
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
<string>audio</string>
</array>
这里有个坑,我曾经遇到过:手动编辑plist时,字符串拼写错了,结果后台模式死活不生效。系统不会报错,只会静默忽略。所以,我建议你尽量用Xcode的UI来操作,减少手误。
避坑指南:Info.plist中的字符串是大小写敏感的。比如「fetch」写成「Fetch」,系统就不认。我曾经因为这个排查了半天,最后发现是首字母大写了。
2.3 常见的后台模式类型
iOS提供了好几种后台模式,每种对应不同的使用场景。我挑几个最常用的给你讲讲。
| 后台模式 | Info.plist字符串 | 适用场景 |
|---|---|---|
| Background Fetch | fetch | 定期从服务器拉取少量数据,比如新闻App刷新头条 |
| Background Processing | processing | 执行耗时任务,比如数据清洗、图片批量处理 |
| Audio, AirPlay, and Picture in Picture | audio | 播放音频或视频时保持后台运行 |
| Location Updates | location | 持续获取位置信息,比如导航App |
| Voice over IP | voip | VoIP通话,比如微信语音通话 |
| External Accessory Communication | external-accessory | 与外部配件通信,比如蓝牙设备 |
| Uses Bluetooth LE Accessories | bluetooth-central | 与蓝牙低功耗设备通信 |
| Acts as a Bluetooth LE Accessory | bluetooth-peripheral | 作为蓝牙外设广播数据 |
这里我想重点说说Background Fetch和Background Processing,因为这两个跟咱们的离线下载功能关系最密切。
2.3.1 Background Fetch
这个模式说白了就是让系统在合适的时机唤醒你的App,执行一些轻量级任务。系统会智能地安排唤醒时间,比如用户充电时、连接WiFi时。
我记得有个项目,需要每天早上7点刷新用户订阅的播客列表。用Background Fetch就特别合适。你只需要实现application:performFetchWithCompletionHandler:方法,在里面拉取数据,然后调用completion handler告诉系统你干完了。
- (void)application:(UIApplication *)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// 拉取播客列表
[self fetchPodcastListWithCompletion:^(BOOL success) {
if (success) {
completionHandler(UIBackgroundFetchResultNewData);
} else {
completionHandler(UIBackgroundFetchResultFailed);
}
}];
}
小技巧:Background Fetch的执行时间只有30秒左右。如果任务没做完,系统会终止你的代码。所以,别在这里做重活。
2.3.2 Background Processing
这个模式是iOS 13才引入的,专门用来处理那些需要更长时间的后台任务。系统会在设备空闲、电量充足时执行这些任务。
我建议你用它来做数据迁移、模型训练、批量下载等耗时操作。相比Background Fetch,它的执行窗口更长,但触发频率更低。
// 注册后台处理任务
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.downloadTask",
using: nil) { task in
self.handleDownloadTask(task as! BGProcessingTask)
}
func handleDownloadTask(_ task: BGProcessingTask) {
// 执行下载任务
task.expirationHandler = {
// 任务即将超时,保存进度
}
}
2.3.3 其他模式简述
剩下的模式我就不展开讲了,简单提一下:
- Audio模式:播放音频时保持后台运行。注意,如果没在播放,系统还是会挂起你。
- Location Updates:导航类App必备。但要注意电量消耗,我一般会结合
significantLocationChange来优化。 - VoIP:微信、Skype这类App用的。现在苹果推荐用PushKit替代,更省电。
重要提醒:不要滥用后台模式。苹果审核时会对后台模式的使用进行审查。如果你的App没有合理理由使用某个模式,会被拒绝。我曾经有个项目因为勾了「Location Updates」但没实际使用定位功能,被拒了两次。
好了,关于Background Modes Capability就讲这么多。下一章我们会深入讲解URLSession后台下载,那才是实现离线功能的核心。你先把这些基础打好,后面才能跟得上。