iOS应用静音且被杀状态下接收推送播自定义声音报OSStatus 561015905错误
问题描述
需要实现的功能:iOS应用在设备开启静音模式、*App被系统终止(后台被杀)*的状态下,接收远程推送时可播放自定义通知声音。
当前实现运行报错,提示:操作无法完成(OSStatus error 561015905.)
现有实现代码
import UserNotifications import AVFoundation import MediaPlayer class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? var audioPlayer = AVAudioPlayer() override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) playSound() if let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() { // 系统即将终止扩展前触发,需在此回调中返回最终修改后的通知内容,否则将使用原始推送 payload if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } } extension NotificationService { //MARK: - 音频播放实现 private func playSound() { do { try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback) try AVAudioSession.sharedInstance().setActive(true) if let url = URL(string: "file:///private/var/mobile/Containers/Shared/AppGroup/9A4FCED-7432FE-FEW-A559-234FBW/Library/Sounds/Update.caf") { audioPlayer = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.caf.rawValue) audioPlayer.volume = 1.0 DispatchQueue.main.asyncAfter(deadline: .now() + 5) { // 预留5秒延迟播放音频,避免音频因过短被截断无法被听到 self.audioPlayer.play() } } } catch { print("[SoundPlayer] 加载音频失败: \(error.localizedDescription)") } if (audioPlayer.isPlaying) { audioPlayer.stop() } audioPlayer.play() } }
问题根因与可落地方案
- 错误码
OSStatus 561015905对应内核层面的kAudioUnitErr_CannotDoInCurrentContext,触发原因是通知服务扩展的沙盒权限不足,不被允许配置playback类别的AVAudioSession——这类不受静音键限制的播放权限,仅开放给拥有前台音频播放资格的主App,扩展进程直接调用相关接口会被系统拦截报错。 - 现有执行逻辑存在硬伤。调用
contentHandler提交通知内容后,扩展进程会立刻进入待回收状态,代码里设置的5秒延迟播放任务,基本会在执行前就被系统强制终止,根本无法走到音频播放的逻辑分支。 - 硬编码的共享容器路径不具备通用性。沙盒路径里的App Group标识是设备维度的随机字符串,换设备、系统版本迭代后路径会直接失效,通过纯字符串拼接
file://URL加载资源,会频繁出现文件找不到的加载异常。 - 核心认知偏差:通知服务扩展本身不支持绕过静音键主动播放自定义长音频。要实现静音模式下的通知声音,完全不需要在扩展里手动初始化音频播放器——只需要在推送payload里指定符合格式要求的自定义声音文件,系统通知进程会负责触发音频播放,这套机制不受App状态、静音键状态、进程权限的限制,哪怕App已经被彻底终止,只要推送到达设备就会正常播放。
修正步骤
- 将自定义CAF格式音频文件同时打包到主App和通知扩展的Target资源目录中,不要通过硬编码的沙盒路径加载文件。
- 远程推送的payload中添加
sound字段,值为自定义音频的文件名,例如sound: "Update.caf",由系统负责音频的加载和播放,移除扩展里所有手动初始化AVAudioPlayer、配置AVAudioSession的代码。 - 移除代码中冗余的重复调用
audioPlayer.play()的逻辑,避免音频会话状态冲突触发系统错误。 - 注意自定义音频时长不得超过30秒,否则会被系统截断,无法完整播放。
内容的提问来源于stack exchange,提问作者Yerke
相关产品推荐
相关产品推荐

