iOS应用进入后台时如何保持手电筒代码运行?多线程优先级尝试无效
问题背景
提问者想要实现App切换到后台时,手电筒功能依然能正常运行、保持点亮状态,已经尝试过给手电筒控制逻辑搭配不同QoS优先级的全局队列,但完全没有效果,相关的实现代码如下:
Button(action: { DispatchQueue.global(qos: .userInteractive).async { self.lightOn.toggle() let cam = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) try? cam?.lockForConfiguration() if (cam?.torchMode == AVCaptureDevice.TorchMode.on) { cam?.torchMode = AVCaptureDevice.TorchMode.off } else if value == 0.0 { do { try cam?.setTorchModeOn(level: 0.05) } catch { print(error) } } else { do { try cam?.setTorchModeOn(level: value) } catch { print(error) } } cam?.unlockForConfiguration() } })
问题本质
iOS对应用的后台执行权限有严格的沙盒管控规则,单纯调整DispatchQueue的QoS调度优先级,完全无法解决App切后台后被系统挂起的问题。这也是提问者尝试了userInteractive、userInitiated、utilities、background所有队列优先级都没有效果的根本原因:DispatchQueue的QoS只决定任务在同一个进程内的CPU调度先后顺序,完全不涉及系统分配给App的后台执行权限额度。所有运行在普通全局队列的代码,在App进入后台超过系统默认的数秒缓冲时间后,都会被系统直接冻结,和优先级高低没有关联。
另外手电筒的控制本质是对内置相机的Torch硬件通道的操作,iOS系统的默认规则是:App进入后台后,会立刻回收所有非白名单应用的相机硬件访问权限,直接切断Torch的供电连接,哪怕在切后台前已经把手电筒打开,系统也会强制把它熄灭。
正确实现路径
要让手电筒在App切后台后保持常亮、并支持正常的状态调整,需要走系统提供的合法后台硬件访问通道,不能依靠普通的后台任务申请硬撑:
- 首先在项目能力配置里开启对应的后台权限:
- 为项目添加
Background Modes能力 - 勾选「后台运行时访问相机」、「后台音频播放」对应的后台模式选项
- 在Info.plist中补充对应的硬件访问权限描述,让系统明确App在后台需要持续占用相机资源
- 为项目添加
- 调整代码逻辑,不要零散调用
AVCaptureDevice的Torch接口:- 初始化一个常驻的
AVCaptureSession实例,把手电筒的Torch控制逻辑和这个活跃的会话绑定。系统识别到有正在运行的相机会话时,才会允许App在后台维持相机硬件的访问权限,不会随便切断Torch连接。 - 手电筒点亮后是由硬件直接维持状态的,根本不需要代码在后台循环跑逻辑——只要拿到了合法的后台硬件权限,哪怕App进程被挂起,Torch的点亮状态也会一直持续,直到用户手动关闭或者App被系统彻底杀死。
- 初始化一个常驻的
- 如果确实需要在后台动态调整手电筒亮度,不要依赖普通的全局队列提交任务,要把对应的调整逻辑绑定在活跃的相机会话回调里,避免被系统拦截。
现有代码还有个逻辑bug:当检测到Torch已经处于on状态时,代码直接把它切到了off状态,根本没有走到后面的亮度调整分支,会导致点击按钮时手电筒直接闪断,不符合预期的控制逻辑。
内容的提问来源于stack exchange,提问作者Ernest Tan
相关产品推荐
相关产品推荐

