大家好,我是拭心。
Android 17 对后台音频交互引入了新的限制,这个变更分两层:第一层对所有应用 生效(无论 targetSdk),第二层对 target 37 的应用更严格。
如果你的应用涉及后台音频播放、音频焦点管理,有必要了解一下这次变更的边界和应对方案。
这篇文章我们来了解下这两层限制。
一、为什么要加这个限制?
在说"限制了什么"之前,先说说"为什么要限"------因为现实中确实存在三类让用户头疼的"幽灵音频"场景。
场景一:冻结后意外恢复播放。 用户切走去做别的事,音乐 App 被系统冻结。数小时后系统解冻 App,音频意外恢复播放,用户完全不知情。
场景二:断断续续的后台音频。 App 没有前台服务,受到后台运行限制,音频播放时断时续,体验极差。
场景三:泄漏的播放会话。 Activity 销毁时播放没有正确停止,音频焦点泄漏,其他 App 无法获取焦点,用户按下暂停也没用。
这三类问题的根源都是"App 在用户不知情的情况下进行音频操作"。Android 17 的限制,本质上是让系统从制度层面要求 App 证明自己的音频行为是"用户授权的"。
二、两层限制详解

第一层:适用于所有应用
无论 targetSdk 是多少,只要应用在后台进行音频交互(播放、请求音频焦点、调整音量),就必须满足以下条件之一:
- 有可见的 Activity(应用在前台)
- 运行了非
SHORT_SERVICE类型的前台服务(Foreground Service)
不满足条件时:
- 音频播放、音量调整 API → 静默失败(不抛异常,但操作不生效)
- 音频焦点请求 → 返回
AUDIOFOCUS_REQUEST_FAILED
"静默失败"是个需要特别注意的点。没有异常抛出,意味着你如果不主动检测返回值,代码看起来跑通了,但音频压根没有播。
第二层:仅适用于 target 37 应用
在第一层的基础上,target 37 的应用有额外要求:前台服务必须具备 WIU(While-In-Use)能力。
什么是 WIU 能力?前台服务在以下情况下会被系统授予 WIU 能力:
- 在用户发起的操作中启动(比如用户点击播放按钮)
- 在应用对用户可见时启动
简单来说:FGS 必须由用户主动触发,而不是 App 自己偷偷启动。
所有应用(第一层):
后台音频 → 必须有非 SHORT_SERVICE 类型的 FGS,或有可见 Activity
target 37(第二层,更严):
后台音频 → 必须有 WIU-capable FGS
(FGS 在用户操作时或应用可见时启动)
有一个豁免情况:如果应用持有 MODIFY_AUDIO_SETTINGS 权限,且修改的是带有 FLAG_AUDIBILITY_ENFORCED 属性的音频流,则不受 WIU 要求限制。
三、正确的后台音频架构
官方推荐方案是 Media3 + MediaSessionService。这套方案不仅满足了新限制的要求,还自动解决了通知栏控制、锁屏控制、Android Auto 集成等一系列问题。
3.1 定义 MediaSessionService
kotlin
class MusicPlaybackService : MediaSessionService() {
private lateinit var player: ExoPlayer
private lateinit var mediaSession: MediaSession
override fun onCreate() {
super.onCreate()
player = ExoPlayer.Builder(this).build()
mediaSession = MediaSession.Builder(this, player).build()
}
override fun onGetSession(
controllerInfo: MediaSession.ControllerInfo
): MediaSession = mediaSession
override fun onDestroy() {
// 必须释放资源,否则可能导致粘性通知无法消除
mediaSession.release()
player.release()
super.onDestroy()
}
}
在 Manifest 里声明,指定 foregroundServiceType 为 mediaPlayback:
xml
<service
android:name=".MusicPlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
</intent-filter>
</service>
3.2 关键:在用户操作时启动 FGS
这是 target 37 的核心要求------FGS 必须在应用可见、用户主动操作时启动,才能获得 WIU 能力:
kotlin
// ✅ 正确:在用户点击播放时启动(应用可见 → 获得 WIU 能力)
class PlayerActivity : AppCompatActivity() {
fun onPlayButtonClick() {
val intent = Intent(this, MusicPlaybackService::class.java)
ContextCompat.startForegroundService(this, intent)
val sessionToken = SessionToken(
this, ComponentName(this, MusicPlaybackService::class.java)
)
val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
controllerFuture.addListener({
controllerFuture.get().play()
}, MoreExecutors.directExecutor())
}
}
kotlin
// ❌ 错误:在 BOOT_COMPLETE 中启动并播放(非用户发起,无 WIU 能力)
class BootReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
// Android 17 下,后续的音频操作会被静默阻止
context.startForegroundService(
Intent(context, MusicPlaybackService::class.java)
)
}
}
}
3.3 瞬时中断时保持 FGS 活跃
来电、其他 App 请求焦点等瞬时中断,不要停止 FGS,否则恢复播放时 WIU 能力已失效:
kotlin
private val audioFocusChangeListener = AudioManager.OnAudioFocusChangeListener { focusChange ->
when (focusChange) {
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
player.pause()
// ✅ 不要 stopSelf(),保持 FGS 活跃
}
AudioManager.AUDIOFOCUS_LOSS -> {
player.stop()
stopSelf() // 永久失去焦点才停止 FGS
}
AudioManager.AUDIOFOCUS_GAIN -> {
player.play()
}
}
}
3.4 主动检测音频焦点失败
由于播放和音量 API 是静默失败的,音频焦点请求是唯一有明确返回值的入口,一定要检测:
kotlin
val result = audioManager.requestAudioFocus(
AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN)
.setOnAudioFocusChangeListener(audioFocusChangeListener)
.build()
)
when (result) {
AudioManager.AUDIOFOCUS_REQUEST_GRANTED -> {
player.play()
}
AudioManager.AUDIOFOCUS_REQUEST_FAILED -> {
// 后台无 WIU FGS 时会走到这里
// 可以提示用户"请先返回应用再播放",或者等应用回到前台再重试
Log.w("Audio", "音频焦点请求失败,当前可能在后台且无 WIU FGS")
}
AudioManager.AUDIOFOCUS_REQUEST_DELAYED -> {
// 延迟授予,在 OnAudioFocusChangeListener 里等待 AUDIOFOCUS_GAIN
}
}
四、迁移检查清单
| 检查项 | 风险 | 处理方式 |
|---|---|---|
使用 MediaPlayer + 普通 Service 后台播放 |
高 | 迁移到 Media3 + MediaSessionService |
FGS 在 BOOT_COMPLETE 或定时任务中启动 |
高 | 改为用户操作触发 |
未检测 AUDIOFOCUS_REQUEST_FAILED |
中 | 添加失败处理逻辑 |
使用 SHORT_SERVICE 类型 FGS |
中 | 改为 mediaPlayback 类型 |
瞬时中断时调用了 stopSelf() |
中 | 改为只在永久失去焦点时停止 FGS |
| 播放结束未停止 FGS | 中 | 监听 Player.STATE_ENDED,播完停止 FGS |
总结
Android 17 后台音频限制的核心逻辑:系统要求 App 证明自己的音频行为是用户授权的。两层限制的关键区别:
- 所有应用:后台音频必须有 FGS(非 SHORT_SERVICE),否则静默失败
- target 37:FGS 还必须具备 WIU 能力,即在用户操作时或应用可见时启动
迁移方向是 Media3 + MediaSessionService------这不只是为了满足限制,MediaSessionService 还自动处理了通知栏控制、锁屏播放控制等一系列后台播放的配套能力,是一次"被迫的架构升级",升完之后反而更省心。
好了,这篇文章到这里就结束了,感谢你的阅读,愿你平安顺遂。
如果对你有帮助,欢迎评论点赞转发,你的支持是我最大的动力❤️