iOS SwiftUI应用基于Combine的后台长任务被系统终止的解决咨询
问题描述
- 基于SwiftUI开发iOS应用,核心需求是根据用户跑步状态切换启停对应的长时任务
- 当前实现方案:通过Combine框架,在QoS等级为
.background的后台线程中执行跑步相关进程的启停逻辑 - 异常表现:进程启停操作偶发延迟,甚至会被系统直接终止;可以接受任务延迟,无法接受进程被系统直接杀掉
- 参考对比:谷歌地图启动位置导航后,对应长时进程不会被系统终止,说明iOS存在支持后台长时运行的合法实现路径,但暂不明确具体实现逻辑
现有实现代码
self.activaity.$running .subscribe(on: self.BackgroundQueue) .receive(on: self.BackgroundQueue) .removeDuplicates(by: {$0 == $1}) .sink(receiveValue: { [self] value in if value { self.start() } else { self.stop() } }) .store(in: &self.cancellables) func start() { self.persistMetaData() self.persist() self.sensorManager.startUpdates() }
解决思路
为什么会出现进程被系统终止的问题
- 仅靠自定义的
.backgroundQoS队列运行任务,完全没有申请iOS系统合法的后台运行许可,这类无系统背书的后台任务,在应用切换到后台后最多几秒就会被系统回收,和队列本身的QoS等级没有关系 - 谷歌地图导航不被系统终止的核心原因,是它走了iOS官方开放的位置更新类后台长时运行通道,而非单纯靠后台队列维持进程存活
具体实现路径
- 按照运动类应用的场景要求,在应用
Info.plist中添加始终/使用期间定位权限的用户说明文案,并在后台模式配置中勾选位置更新选项,告知系统该应用有持续后台定位的合法需求 - 改造现有
sensorManager.startUpdates()逻辑:基于CoreLocation框架开启持续的高精度位置更新,只要位置更新流程未被手动停止,系统就会将当前应用判定为正在执行后台运动/导航任务的进程,不会随机终止其运行 - 现有Combine的订阅链路不需要大改:只要进程被系统标记为合法的后台长时运行状态,队列调度带来的任务启停延迟属于系统正常资源调度范围,不会出现被直接杀掉的问题
- 针对数据持久化的操作,可以搭配iOS提供的临时后台任务申请接口,在应用即将进入后台时申请最长30秒的额外执行窗口,完成元数据、传感器数据的落盘,避免写入流程被系统打断
内容的提问来源于stack exchange,提问作者Abdulmajed
相关产品推荐
相关产品推荐

