如何修复iPadOS播放声音时卡顿及AudioQueue报错-66671问题
问题根因
- 未正确配置
AVAudioSession,错误码-66671是系统音频队列找不到激活的合法音频会话抛出的异常 - 音频文件加载、
AVAudioPlayer初始化全在主线程执行,SwiftUI的UI渲染、交互响应全部依赖主线程,同步执行音频IO、解码操作会直接阻塞主线程造成卡顿 - 每次触发播放都重新创建
AVAudioPlayer实例,重复做文件读取、解码器初始化操作,无意义占用大量系统资源,进一步加剧卡顿
修复步骤
- 单例初始化阶段提前配置音频会话,从根源解决-66671报错
- 预加载所有需要高频触发的短音效,不要播放时临时加载文件
- 播放操作切到后台队列执行,绝对不阻塞主线程
- 复用播放器实例,避免重复创建对象
修复后的完整SoundService代码:
import Foundation import AVFoundation class SoundService { static let shared = SoundService() private var tockPlayer: AVAudioPlayer? private init() { // 配置音频会话,适配短提示音场景,不打断其他App背景音频 do { try AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default) try AVAudioSession.sharedInstance().setActive(true) } catch { print("[SoundService] 音频会话初始化失败: \(error.localizedDescription)") } // 预加载滴答音效,提前完成文件读取和解码器初始化 guard let soundURL = Bundle.main.url(forResource: "tock", withExtension: "mp3") else { print("[SoundService] 未找到tock.mp3资源,请检查文件是否加入对应Target") return } do { tockPlayer = try AVAudioPlayer(contentsOf: soundURL) // 调用prepareToPlay预解码,把播放延迟降到最低 tockPlayer?.prepareToPlay() } catch { print("[SoundService] 音效加载失败: \(error.localizedDescription)") } } public func tockSound() { // 播放逻辑丢到后台队列,不占用主线程资源 DispatchQueue.global(qos: .userInitiated).async { [weak self] in guard let player = self?.tockPlayer else { return } // 支持快速连续触发:如果正在播放就重置进度从头播 if player.isPlaying { player.stop() player.currentTime = 0 } player.play() } } // 其余音效参考tockSound的逻辑,提前初始化对应AVAudioPlayer实例即可 }
额外注意事项
- 调用
SoundService.shared.tockSound()不需要额外做线程切换,方法内部已经做了线程处理,直接在SwiftUI的Button action、视图回调里调用即可 - 短提示音尽量用小体积、低码率的音频文件,不要把好几MB的音乐文件当按钮提示音用,会增加加载开销
- 如果是iOS 17及以上系统,也可以替换为
AVAudioPlayer的原生异步初始化接口,兼容性更好,上述代码支持iOS 13及以上所有版本
内容的提问来源于stack exchange,提问作者phlpp77
相关产品推荐
相关产品推荐

