Apple Watch后台定时启停录音触发561015905错误求助
解决后台定时启停录音的AVFAudio错误561015905
错误原因解析
错误码561015905对应AVAudioSessionErrorCannotActivateInBackground,核心问题是:iOS不允许应用在后台直接激活纯录音类别的AVAudioSession,后台音频权限仅支持持续的音频任务,而你当前用Timer+主队列延迟的方式,触发时机不符合系统的后台音频会话规则。
针对性解决思路
1. 调整AVAudioSession的类别与激活时机
- 不要提前在
startPeriodicMonitoring中激活会话,改为每次录音启动前激活,结束后按需停用(停用会话时保留权限相关选项,避免系统回收后台资格)。 - 替换
record类别为playAndRecord,该类别对后台环境的兼容性更好,即使你不需要播放功能:
func startMonitoring() { let session = AVAudioSession.sharedInstance() do { try session.setCategory(.playAndRecord, mode: .default, options: [.mixWithOthers, .allowBluetooth]) try session.setActive(true, options: .notifyOthersOnDeactivation) // 执行你的录音启动逻辑 } catch { print("激活录音会话失败: \(error.localizedDescription)") } } func stopMonitoring() { let session = AVAudioSession.sharedInstance() do { try session.setActive(false, options: .notifyOthersOnDeactivation) // 执行你的录音停止逻辑 } catch { print("停用录音会话失败: \(error.localizedDescription)") } }
2. 替换Timer为后台安全的调度方式
Timer.scheduledTimer依赖主RunLoop,应用进入后台后主RunLoop可能被挂起,导致定时器失效。改用DispatchSourceTimer(基于GCD)实现后台定时:
private var measurementTimer: DispatchSourceTimer? func startPeriodicMonitoring() { let queue = DispatchQueue(label: "com.yourapp.recording.timer", qos: .background) measurementTimer = DispatchSource.makeTimerSource(queue: queue) // 立即触发,之后按interval重复,预留100ms误差缓冲 measurementTimer?.schedule(deadline: .now(), repeating: measurementInterval, leeway: .milliseconds(100)) measurementTimer?.setEventHandler { [weak self] in guard let self = self else { return } DispatchQueue.main.async { self.startMonitoring() DispatchQueue.main.asyncAfter(deadline: .now() + self.recordingDuration) { self.stopMonitoring() } } } measurementTimer?.resume() }
3. 修正后台权限配置
- 移除
WKBackgroundModes配置:该字段仅针对WatchKit应用,iOS应用无需设置,避免混淆系统权限判断。 - 精简
UIBackgroundModes:只保留audio项,self-care权限与iOS后台录音无关,可删除。
4. 维持后台音频会话活跃性
如果录音间隔较长,系统可能回收应用后台权限。可以播放一段静音音频来维持会话活跃:
private var silentPlayer: AVPlayer? func setupSilentPlayer() { guard let silentURL = Bundle.main.url(forResource: "silent", withExtension: "mp3") else { return } silentPlayer = AVPlayer(url: silentURL) silentPlayer?.actionAtItemEnd = .none // 监听音频结束事件,循环播放静音 NotificationCenter.default.addObserver(self, selector: #selector(restartSilentPlayback), name: .AVPlayerItemDidPlayToEndTime, object: silentPlayer?.currentItem) } @objc func restartSilentPlayback() { silentPlayer?.seek(to: .zero) silentPlayer?.play() }
启动定时录音前调用setupSilentPlayer()并启动播放,确保后台音频会话持续活跃。
额外注意事项
- 确认Info.plist中已配置
NSMicrophoneUsageDescription,后台录音同样需要用户授权麦克风权限。 - iOS对后台音频的管控严格,频繁启停录音可能被判定为权限滥用,建议尽量减少录音次数,或改为持续录音后分段处理。
内容的提问来源于stack exchange,提问作者MahanTp
相关产品推荐
相关产品推荐

