Audio Session — iOS 用于管理应用程序音频行为的中央机制:与系统交互、处理中断和音频路由。每个 iOS 应用程序获得一个唯一的音频会话,它决定了声音在屏幕锁定、来电和蓝牙连接时的行为。根据 Apple Developer Documentation, 2026,Audio Session 通过类别和模式进行配置 — 没有正确的配置,应用程序可能无法在后台播放声音。
要点
Audio Session — 是系统在应用程序启动时创建的一个 AVAudioSession 实例,并在其整个生命周期中存在。它充当应用程序和 iOS 音频系统之间的中介:类别配置决定应用程序是否可以在后台播放声音、在通话时声音是否会被调低以及音频输出到哪些设备。
与 Android Audio Focus 不同(每个应用程序独立请求和释放焦点),iOS Audio Session 通过每个应用程序一个会话进行集中管理。当会话激活时,系统会自动停用前一个应用程序的会话,并向其发送中断通知。这种架构差异决定两个平台上音频处理的不同方法。
根据 WWDC 2024 Session 211,约 40% 的 iOS 应用程序音频问题是由 Audio Session 配置不当引起的。最常见的错误 — 选择 ambient 类别而不是 playback,导致屏幕锁定后声音消失。
启动时,应用程序获取会话的共享实例,通过调用 setCategory(_:mode:options:) 设置类别,并通过 setActive(true) 激活会话。激活后,iOS 考虑类别策略进行路由。如果另一个应用程序激活了自己的会话,当前应用程序会通过 Notification.Name.AVAudioSessionInterruption 接收 AudioSessionInterruptionType.began 通知。
类别 — Audio Session 的主要参数,定义了六种预定义的行为变体。选择类别是 iOS 中音频配置的第一个也是最重要的决定。
| 类别 | 何时使用 | 后台音频 | 静音时降低 |
|---|---|---|---|
| ambient | 游戏、背景效果 | 否 | 是 |
| playback | 音乐、播客、有声书 | 是 | 否 |
| record | 录音机、声音录制 | 否 | 不适用 |
| playAndRecord | VoIP、语音消息 | 是 | 否 |
| multiRoute | DJ 混音器、卡拉 OK | 是 | 否 |
| soloAmbient | 默认(iOS 默认) | 否 | 是 |
对于音乐和视频播放器,始终使用 playback。此类别允许:在屏幕锁定、静音开关关闭(iPhone 机身上的物理按钮)和应用程序最小化时播放声音。没有 playback 类别,会话会在屏幕锁定或应用程序最小化时停用。
Ambient 类别适用于游戏和带有背景音的应用程序 — 允许其他应用程序继续播放。例如,如果用户正在听音乐并打开带有 ambient 会话的游戏,音乐会继续在游戏音效之上播放。这是与 Android 的根本区别,在 Android 中,这种场景需要明确的 duck 许可。
Audio Session 配置应在任何播放开始之前执行。建议在 application(_:didFinishLaunchingWithOptions:) 方法或播放器初始化器中配置会话。配置类别后,需要激活会话。
import AVFAudio
let session = AVAudioSession.sharedInstance
do {
try session.setCategory(
playback,
mode: default,
options: [allowBluetooth, defaultToSpeaker]
)
try session.setActive(true)
} catch {
print("Audio Session 设置失败:\(error.localizedDescription)")
}
Options 参数包括 allowBluetooth(输出到蓝牙耳机)和 defaultToSpeaker(通过扬声器播放,而不是听筒)。allowBluetooth 选项对于支持蓝牙耳机的应用程序是必需的 — 没有它,即使连接了耳机,声音也可能通过内置扬声器输出。
let session = AVAudioSession.sharedInstance
try session.setCategory(
playAndRecord,
mode: voiceChat,
options: [allowBluetooth, allowBluetoothA2DP]
)
try session.overrideOutputAudioPort(speaker)
try session.setActive(true)
PlayAndRecord 类别配合 voiceChat 模式优化语音通信的音频路径:包括回声抑制、自动增益控制(AGC)和选择最佳编解码器。OverrideOutputAudioPort(.speaker) 强制通过扬声器输出,即使连接了耳机 — 适用于免提通话。
调用 setActive(true) 激活会话并通知系统应用程序将使用音频。暂停播放时,建议停用会话以便其他应用程序可以获取音频流。例外 — 具有长时间后台播放的应用程序(音乐、播客),会话在整个曲目期间保持活跃。
处理 setActive 的错误很重要。如果另一个高优先级会话处于活动状态(例如通话中的电话),setActive 可能会报错。在这种情况下,需要等待 AudioSessionInterruptionType.ended 通知并重试激活。
模式进一步细化类别并针对特定使用类型优化音频路径。每种模式更改 AGC、回声抑制和编解码器的行为。模式不取代类别,而是补充类别 — 一个类别可以与不同模式一起使用。
选项提供会话行为的微调。每个选项是一个标志,可以在数组中与其他选项组合。例如,[.allowBluetooth, .defaultToSpeaker, .interruptSpokenAudioAndMix] 允许将声音输出到蓝牙耳机、默认使用扬声器并与有声书混音。
在 iOS 17+ 中出现了 spatialAudio 选项,它通过 AVAudioSessionSpatialPreferences 为 AirPods 激活个性化空间音频。根据 WWDC 2024,空间音频在 Apple 测试中将音乐应用程序用户的参与度提高了 25%。
中断 — Audio Session 与 Android Audio Focus 的主要区别。在 iOS 中,中断通过 NotificationCenter 订阅 AVAudioSession.interruptionNotification 来处理。通知包含一个带有中断类型的字典:began 或 ended。
override func viewDidLoad() {
super.viewDidLoad()
let center = NotificationCenter.default
center.addObserver(
self,
selector: #selector(handleInterruption),
name: AVAudioSession.interruptionNotification,
object: nil
)
}
@objc func handleInterruption(_ notification: Notification) {
guard let userInfo = notification.userInfo,
let type = userInfo[AVAudioSession.interruptionTypeKey]
as? AVAudioSessionInterruptionType
else { return }
switch type {
case began:
pausePlayback()
case ended:
guard let options = userInfo[AVAudioSession.interruptionOptionKey]
as? AVAudioSessionInterruptionOptions
else { return }
if options.contains(shouldResume) {
resumePlayback()
}
}
收到 interruptionType.began 时,播放器应暂停播放。在 interruptionType.ended 时,interruptionOptionKey 属性指示播放器是否可以自动恢复(shouldResume)。如果用户结束了通话,shouldResume = true。如果通话因超时而结束 — shouldResume = false,不允许恢复。
当另一个应用程序以 playback 类别激活其 Audio Session 时,当前会话会收到中断通知。如果其他应用程序使用 ambient,则不会发生中断 — 声音会混合。这种行为与 Android 截然不同,在 Android 中,任何 Audio Focus 激活都会触发 LOSS 事件。
对于应在其他会话激活时继续播放的应用程序(例如,音乐播放时的导航),请使用 .mixWithOthers 选项。此选项允许与其它应用程序混合声音,并且不会发送中断。MixWithOthers — iOS 中 Android duck 模式的对应。
Audio Session 自动管理内置扬声器、耳机、蓝牙耳机和 AirPlay 设备之间的音频路由。应用程序可以通过 currentRoute 属性跟踪当前路由,并通过 AVAudioSession.routeChangeNotification 接收更改通知。
连接蓝牙耳机时,如果会话配置了 allowBluetooth 选项,iOS 会自动将音频输出切换到它们。没有此选项,声音继续通过内置扬声器输出。从 iOS 16 开始,连接 AirPods Pro 时,系统会自动启用 ProMotion 同步以减少延迟。
订阅 routeChangeNotification 可以响应耳机的连接和断开。当蓝牙耳机断开时,播放器应暂停播放 — 用户可能不希望声音从电话扬声器开始播放。根据 Apple HIG(2026),这是音乐应用程序的强制行为。
AvailableInputs 和 availableOutputs 属性返回可用音频设备列表及其类型(builtInSpeaker、headphones、bluetoothA2DP、hdmi)。开发人员可以通过 overrideOutputAudioPort 以编程方式选择特定设备以实现自定义路由方案。
常见问题
主要区别 — 架构。Audio Session 是每个应用程序一个集中式会话,配置一次。Android 中的 Audio Focus 每次播放都需要手动请求焦点。此外,iOS 通过 mixWithOthers 选项支持混音,而在 Android 中 duck 是完全停止的唯一替代方案。
最常见的原因 — Audio Session 的 类别不正确。如果选择了 ambient 或 soloAmbient,声音会在屏幕锁定时停止。切换类别为 playback,并确保在 Info.plist 中添加了 Background Modes — Audio, AirPlay, and Picture in Picture。
在 setCategory 中添加 .mixWithOthers 选项。这将允许您的应用程序的声音与其他活跃会话混合。没有此选项,新应用程序会中断当前应用程序。MixWithOthers — Android 中 duck 模式的对应,但完全保留音量。
使用带有 nil 的 overrideOutputAudioPort 进行自动选择。强制输出到蓝牙:从 availableOutputs 获取 AVAudioSessionRouteDescription,选择类型为 .bluetoothA2DP 的端口并传递给 overrideOutputAudioPort。确保会话配置了 allowBluetooth。
对于大多数应用程序 — 是的。暂停时停用会话允许其他应用程序获得音频焦点。例外 — 具有长时间后台播放的音乐播放器。如果暂停时间短(少于 5 秒),最好保持会话活跃以便快速恢复。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。