iOS的后台音频播放如果没配置好,和系统背景音同时工作时会出现各种奇怪现象:用户打开雨声背景音,你的应用一进后台就没声了;或者反过来,应用一出声就把系统背景音掐断。要解决这个问题,需要先搞清楚AVAudioSession的会话分类和混音选项,尤其是AVAudioSessionCategoryOptionMixWithOthers与iOS 15系统背景音之间的作用关系。

冲突从哪里来:音频会话的独占机制
iOS里的音频输出并不是谁想播就能播,所有音频都被AVAudioSession统一管理。一个应用如果要播放声音,就得先激活音频会话,而会话的分类决定了它如何与其他音频源相处。AVAudioSessionCategoryPlayback是最常用的后台播放分类,它专门为音乐、播客、有声书这类需要长时间播放的音频设计。但这个分类默认行为是独占的,也就是说,一旦你的应用以Playback分类激活会话,系统可能会中断其他正在播放的音频,包括音乐App、视频App,以及iOS 15加入的系统背景音。
系统背景音是用户在设置中开启的雨声、海洋、白噪音等环境音,它属于系统级音频输出,运行在独立的音频链路上。如果你的应用没有声明混音选项,当应用激活Playback会话时,系统就会认为你要独占输出通道,于是背景音被暂停或被压低;而如果系统背景音已经在播放,应用进入后台后也可能因为音频会话策略不够清晰而被挂起或中断。这里的关键选项就是AVAudioSessionCategoryOptionMixWithOthers,它告诉系统:这个应用的音频可以和其他音频同时播放,不要独占。
光知道加选项还不够,因为音频会话的配置是组合生效的。分类、模式、选项三者会共同影响后台播放、混音、音量策略和系统中断行为。比如你虽然设置了MixWithOthers,但如果分类用的是AVAudioSessionCategoryAmbient,那应用本身就不支持后台连续播放;如果你没有在工程里声明后台音频模式,进入后台后同样会被系统挂起。因此解决冲突必须把几个环节串起来看,而不是只改一行配置。
正确的后台音频与混音配置方式
要保证应用在后台持续播放,并且与系统背景音同时出声,首先要把分类设置成Playback,同时加上MixWithOthers选项。下面这段Swift代码是基础配置:
import AVFoundation
func configureAudioSession() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(.playback,
mode: .default,
options: [.mixWithOthers])
try session.setActive(true)
} catch {
print("音频会话配置失败: \(error.localizedDescription)")
}
}
这段代码执行后,应用的音频输出就不会再因为激活会话而立刻打断系统背景音。需要注意的是,setCategory必须在setActive之前调用,否则会话可能以旧配置激活,导致混音策略不生效。实际开发中建议在播放器初始化阶段就完成配置,并且在从后台恢复时再次确认会话处于激活状态。
配置好会话只是第一步,应用还要声明后台音频模式。打开Xcode工程,在Info.plist里加入UIBackgroundModes,并在数组中加入audio,否则应用进入后台后播放器会被系统挂起。对应的XML片段如下:
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
加上这个声明之后,Playback分类才能真正发挥后台播放能力。这里容易混淆的是AVAudioSessionCategoryAmbient,它本身也支持混音,但Ambient分类在应用进入后台后通常不会继续播放音频,除非应用有其他后台执行机制。如果你希望后台一直播,同时不打断系统背景音,正确组合就是Playback分类、MixWithOthers选项,再加UIBackgroundModes的audio声明。
另外,mode的设置也会影响实际表现。一般音乐或播客场景使用default即可;如果是语音播报、导航类应用,可以考虑spokenAudio模式,它会告诉系统这是一个语音输出场景,此时与其他音频的混合策略可能有细微差别。但在解决与系统背景音冲突这个具体问题上,核心仍然是MixWithOthers选项,mode可以先保持default,后续根据业务需要微调。
系统背景音变化时的中断处理与恢复
即使已经配置了MixWithOthers,应用在播放过程中仍然可能收到系统发来的中断通知,比如用户接听电话、闹钟响起,或者系统背景音因为某些原因重新初始化。对于后台播放的应用来说,如果收到中断后没有处理,播放器可能一直处于暂停状态,用户回来后发现声音早停了。因此需要监听AVAudioSession的interruptionNotification,在中断开始和结束时分别暂停和恢复播放。
NotificationCenter.default.addObserver(
self,
selector: #selector(handleInterruption(_:)),
name: AVAudioSession.interruptionNotification,
object: AVAudioSession.sharedInstance()
)
@objc func handleInterruption(_ notification: Notification) {
guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { return }
if type == .began {
// 先暂停播放器,保留当前播放位置
} else if type == .ended {
try? AVAudioSession.sharedInstance().setActive(true)
// 根据业务需要恢复播放
}
}
除了通用中断,还有一个更贴近混音场景的通知:silenceSecondaryAudioHintNotification。当系统认为你的应用属于次要音频,而其他主要音频开始播放时,会发送这个通知。虽然设置了MixWithOthers后应用通常不会被判定为次要音频,但某些情况下,比如系统背景音重新获得焦点时,这个通知也可能出现。监听它可以提前预判音量变化,避免用户突然听不到应用声音。
NotificationCenter.default.addObserver(
self,
selector: #selector(handleSecondaryAudioHint(_:)),
name: AVAudioSession.silenceSecondaryAudioHintNotification,
object: AVAudioSession.sharedInstance()
)
@objc func handleSecondaryAudioHint(_ notification: Notification) {
guard let userInfo = notification.userInfo,
let typeValue = userInfo[AVAudioSessionSilenceSecondaryAudioHintTypeKey] as? UInt,
let type = AVAudioSession.SilenceSecondaryAudioHintType(rawValue: typeValue) else { return }
if type == .begin {
// 系统提示次要音频可以降低音量或暂停
} else if type == .end {
// 次要音频可以恢复正常播放
}
}
在实际测试中,iOS 15及以上的系统背景音与第三方应用混音时,不同的设备型号和系统小版本可能会有差异。有的版本会优先保证系统背景音持续输出,把应用音频压低;有的版本则完全按照MixWithOthers的字面意义做等音量混合。因此监听这些通知并针对两种情况做兼容处理,能减少用户反馈的声音忽大忽小问题。
几个容易忽略的细节:DuckOthers、耳机切换和静音键
当你允许应用音频与系统背景音混合后,两个声音可能叠加在一起,用户反而听不清应用内容。这时候可以在options里再追加一个DuckOthers选项,让系统背景音等次要音频在应用播放期间自动降低音量,突出你要表达的内容。配置方式如下:
try session.setCategory(.playback,
mode: .default,
options: [.mixWithOthers, .duckOthers])
DuckOthers并不是把所有其他音频完全静音,而是暂时降低它们的输出音量。这个选项对系统背景音同样有效,适合播客、语音导航、语音消息等需要清晰人声的场景。但如果你做的是音乐类应用,可能不希望系统背景音被压低,那就不加DuckOthers,让两个音源自然混合。
还有一个常被忽略的点是耳机和蓝牙路由。音频会话激活后,系统会按照当前路由输出声音,比如扬声器、有线耳机、AirPods等。当用户插入耳机或连接蓝牙设备时,音频路由会发生变化,系统背景音和应用音频可能会被路由到不同设备,也可能同时切到新设备。建议监听AVAudioSession的routeChangeNotification,在路由变化后检查当前输出端口,必要时重新激活会话,确保混音策略仍然生效。
静音开关的影响也值得注意。Playback分类默认会绕过静音开关,也就是说用户把手机侧边静音拨片打开时,你的后台音频仍然会响。这听起来正常,但如果应用混音了系统背景音,用户可能会觉得明明静音了怎么还有声音。如果你希望应用跟随静音开关,可以使用AVAudioSessionCategoryAmbient,但那样又会牺牲后台播放能力。对于多数后台音频应用,保持Playback的默认行为是合理的,但在设置页面或播放器界面给用户明确提示,能减少误解。
最后回到冲突本身,解决思路其实很清晰:先确认分类是Playback,再确认options包含MixWithOthers,然后检查Info.plist里的UIBackgroundModes是否声明了audio,最后用中断和路由通知兜底。把这几个环节串起来,应用在后台播放时就能与iOS系统背景音和平共处,不会再出现互相打断或无声的情况。
AVAudioSessionCategoryOptionMixWithOthers后台音频播放系统背景音修改时间:2026-09-24 14:39:38