背景
说实话当初去适配targetSdk35的时候,真心没有注意到音频方面的改动,精力完全被16kb跟edge-to-edge占用了,直到这段时间,线上用户反馈里面,太多的骂声都是围绕在应用在切到后台后,本来在播放的东西听不到了,我才把主观思想从"你们手机系统内存是不是该清理了"转移到"好像都是从我升级了targetSdk35后才开始有的问题,我又要背锅了",于是乎我又去翻了一下官方文档,还真的有一些音频上的改动
Android 15-音频焦点请求限制
核心变更
Android 15对targetSdkVersion是35及以上的应用引入了一条关键限制应用必须是顶层应用或正在运行的前台服务,才能请求音频焦点。 如果不符合条件,requestAudioFocus() 就会返回 AUDIOFOCUS_REQUEST_FAILED
其他相关变更
- BOOT_COMPLETED 限制 :启动广播中禁止启动
mediaPlayback、phoneCall、microphone等类型的前台服务,否则抛ForegroundServiceStartNotAllowedException - mediaProcessing 新类型 :新增
mediaProcessingFGS 类型,用于媒体转码等场景,与dataSync共享 6h/24h 时间配额 - Direct/Offload 资源管理 :资源受限时,系统主动废弃旧
AudioTrack以让新请求成功
Android 17-后台音频强化
然后在Android17也有一条针对音频方面的更新,发现在15的基础上做了更多的限制,变化如下
主要变更
Android 17 对三类后台音频交互实施了静默拦截:
| 交互类型 | 受影响的 API | 失败表现 |
|---|---|---|
| 音频播放 | AudioTrack.write()、AAudioStream_write、OpenSL ES,以及 Media3、ExoPlayer、Oboe 等上层库 |
静默失败,播放无声,无异常无日志 |
| 音频焦点请求 | AudioManager.requestAudioFocus() |
返回 AUDIOFOCUS_REQUEST_FAILED |
| 音量/响铃模式调整 | setStreamVolume()、setStreamMute()、adjustStreamVolume() 等 |
静默忽略 |
不受影响的条件
以下场景,无论targetSDK多少,只要满足任一条件,都可以不受音频限制
- 有可见的 Activity(含 PiP 画中画模式)
- 正在运行一个前台服务(FGS),且该前台服务类型不是
SHORT_SERVICE
targetSdk是37的额外限制
如果目标平台是37的应用,如果在后台运行,则必须运行一个具有"使用期间"(When In Use, WIU)功能的前台服务(FGS),但是如果应用已获得精确闹钟权限(SCHEDULE_EXACT_ALARM)且正在操作 USAGE_ALARM 流的应用,可免于 WIU 要求。
什么是WIU
- 标准 FGS:在应用可见或被授予后台activity启动功能时启动的服务会被授予 WIU 访问权限
- 后台启动的FGS(BFSL):大多数不授予 WIU。例外包括通知点击、Widget 互动、媒体键事件等用户显式意图触发的情况
- 系统启动的 FGS:Telecom Jetpack 库委托或
VoiceInteractionService等场景可获 WIU
所以说Android17的管控范围更大了,原本Android15只是针对请求音频焦点的时候才需要前台服务,现在是整个音频交互链路上都需要前台服务,如播放音频,请求焦点,调整音量等
对我们应用的影响
如果不去适配这些特性,可能的影响包括但不限于以下几点
短期影响
针对目标平台是35的应用,并且已经在使用前台服务播放音频了,那么焦点请求限制影响较小,但以下场景需要关注:
- 启动阶段自动播放 :如果应用在后台启动(如
BOOT_COMPLETED)时尝试请求焦点,会失败 - 焦点管理不严谨 :之前靠
requestAudioFocus返回值做判断的逻辑,需要处理AUDIOFOCUS_REQUEST_FAILED - 后台预加载:用户未打开应用时预加载音频内容并获取焦点,会被拒绝
长期影响
对于Android17的后台音频强化,难度就升级了
-
后台播放全面受限
- 即使有 FGS,也必须带 WIU 功能
- 如果使用
SHORT_SERVICE做前台服务,在后台直接不能播放
-
音量 API 的后台限制
setStreamVolume()、adjustStreamVolume()等在后台静默失效- 这对有独立音量控制功能的 app 影响较大
-
静默失败难以排查
- 播放失败、焦点失败不抛异常,只能用
adb shell cmd audio set-enable-hardening throw在调试阶段捕获 - 生产环境需要靠日志和
dumpsys audio排查
- 播放失败、焦点失败不抛异常,只能用
-
MediaSessionService 成为硬要求
- 官方建议使用 Media3 Jetpack 库的
MediaSessionService------这不是建议,在 Android 17 下这几乎是唯一正确的路径
- 官方建议使用 Media3 Jetpack 库的
适配策略与最佳实践
迁移到 Media3 MediaSessionService

正确处理前台服务生命周期

音频焦点管理(如未使用 Media3,需手动处理)

测试与调试

logcat 输出中的示例

总结
可以看到,从Android 15限制音频焦点请求条件,到 Android 17全面强化后台音频交互规则,谷歌又在做一些优(bu)化(guan)用(niu)户(ma)体(si)验(huo)的事情,打算构建一个 "用户必须明确意图" 的音频播放管控体系,打算在未来的Android系统上,不可以再随意的在后台自由的播放音频,系统会主动拦截那些没有在前台运行的音频行为,不过也有好的一面,咱这Q3的技改需求不用再交白卷了