离线锁屏控制失效的根本原因是uni.getBackgroundAudioManager()未成功接管系统音频焦点,因src必须为/static/开头的本地绝对路径、文件真实存在打包目录、且需用户触发后立即play()并验证onPlay回调。

离线状态下锁屏控制失效,根本原因是 uni.getBackgroundAudioManager() 依赖网络资源加载和初始化,一旦断网或资源未预加载,锁屏后音频控制链就断裂——不是 API 不工作,而是它压根没成功接管系统音频焦点。
为什么离线 + 锁屏会丢控?
微信小程序和 App 端的后台音频机制都要求:音频源(src)必须可访问、且在锁屏前已触发过播放。离线时若 src 是远程 URL(如 https://xxx.com/audio.mp3),首次调用 play() 就会静默失败;后续即使切后台/锁屏,onPlay、pause() 等全部无效。
- 常见错误现象:
bgAudio.play()返回ok,但实际无声音;锁屏后物理按键无效、锁屏界面不显示进度条 - 真实原因:离线时
bgAudio.src设置失败,但 API 不抛错,bgAudio.paused仍为true,bgAudio.play()变成空操作 - 本地路径也踩坑:用
./audio.mp3或res/audio.mp3—— 必须是打包后真实存在的绝对路径,如/static/audio.mp3
离线音频源必须满足的三个硬条件
只要缺一,锁屏控制必然失效。不是“试试看”,而是必须全部满足:
-
src指向本地静态资源,且路径以/static/开头(HBuilderX 打包后该目录被映射到原生资源路径) - 文件真实存在于
unpackage/dist/build/app-plus/static/(App)或unpackage/dist/dev/mp-weixin/static/(小程序)中 - 在页面
onShow或用户主动触发动作中,先设src,再调play(),中间不能有异步等待或条件分支干扰
示例正确写法:
const bgAudio = uni.getBackgroundAudioManager(); bgAudio.src = '/static/book_001.mp3'; // ✅ 绝对路径,离线可用 bgAudio.title = '第一章'; bgAudio.play(); // 必须紧随 src 设置之后
锁屏前必须触发一次有效播放
很多开发者以为设置完 src 就万事大吉,其实系统音频焦点是在第一次 play() 成功时才获取的。离线环境下,这个“成功”需要验证:
- 监听
bgAudio.onPlay,确保回调触发(不是onError) - 若未触发,立刻检查路径是否 404(App 端可通过
plus.io.resolveLocalFileSystemURL预检文件是否存在) - 避免在
onLoad中直接play():App 启动阶段 WebView 可能未就绪,iOS 尤其敏感;改用onShow或按钮点击触发 - 不要依赖自动播放:iOS 和部分安卓 ROM 禁止自动播放,必须由用户手势(如 tap)驱动
离线场景下别碰 createInnerAudioContext
有人试图用 uni.createInnerAudioContext() 替代,这是典型误用。它的生命周期绑定页面,页面隐藏即销毁,锁屏后立即中断,且无法响应物理按键或显示锁屏 UI。官方明确说明:uni.getBackgroundAudioManager() 是锁屏听书唯一可靠方案,createInnerAudioContext 只适合页面内提示音。
容易被忽略的点:离线资源不仅要存在,还要在打包构建阶段被识别为静态资源——如果你用变量拼接路径(如 `/static/${id}.mp3`),Webpack 无法静态分析,该文件大概率不会被打进 static 目录,运行时就是 404。路径必须字面量、不可动态生成。


















