后台音频播放需绑定持久媒体上下文,用Web Audio API+Service Worker协同,首次resume()须用户手势触发,并及时设置mediaSession元数据,PWA需声明权限并监听push事件恢复。

后台音频播放不是“关掉页面还能响”,而是指用户切换标签页、锁屏或App退到后台时,音频不中断——但现代浏览器(Chrome 120+、Firefox 125+、Safari 17+、Edge 120+)默认会暂停或降频处理,必须主动干预才能维持。
为什么audio在后台自动暂停
这不是 bug,是浏览器的资源策略:iOS Safari 和 Android Chrome 会在页面失去焦点(visibilitychange → hidden)或进入后台(pagehide)时强制 suspend 音频解码线程。即使 play() 成功,paused 可能仍为 false,但 currentTime 停滞、timeupdate 停发、ended 不触发。
- Chrome/Edge:后台约 30 秒后静音并冻结播放器状态,无法靠 JS 恢复
- Safari(iOS/macOS):一旦页面不可见,立即暂停,且不触发
pause事件,只悄悄停 - Firefox:相对宽松,但锁屏后也会降频,
timeupdate间隔拉长至秒级
如何让audio在后台持续播放(合法路径)
唯一被所有平台认可的方式:把音频绑定到「持久媒体上下文」,而非依赖单个 <audio> 元素。关键不是改属性,而是用 Web Audio API + 后台服务 Worker 协同。
- 必须启用
AudioContext,且首次调用resume()必须由用户手势触发(如点击按钮),否则后续所有操作都无效 - 不要用
<audio>直接播放长背景音乐;改用AudioContext.decodeAudioData()加载后,用BufferSourceNode播放,它比 HTMLaudio更抗后台中断 - 在 iOS 上,需额外调用
navigator.mediaSession设置元数据(title、artist),否则 Safari 会直接禁用后台播放权限 - Android Chrome 要求 manifest.json 中声明
"background_sync"和"audio"权限,并在 service worker 中监听push或notificationclick来恢复上下文(仅适用于 PWA)
常见“伪后台播放”失败原因
很多方案看似能播,实则脆弱:比如监听 visibilitychange 后立刻 play(),或用 setTimeout 定期重试——这些在 Safari 17+ 和 Chrome 120+ 已全部失效。
立即学习“前端免费学习笔记(深入)”;
-
play()返回 Promise 被 reject,但没.catch()→ 控制台沉默,逻辑卡死 - 在
pagehide事件里调audio.play()→ 浏览器直接忽略,不报错也不执行 - 用
setInterval每 5 秒检查audio.paused并尝试恢复 → iOS Safari 会累积多个 pending play 请求,最终全部拒绝 - 误以为
muted+autoplay就能后台播 → 它只解决前台静音启动,对后台无任何作用
真正能落地的兼容方案组合
没有银弹,只有分层兜底:前台靠用户手势解锁,后台靠系统级权限申请,失败时优雅降级。
- 前台阶段:用按钮 click 触发
new AudioContext().resume(),同时设置navigator.mediaSession.metadata = new MediaMetadata({ title: "BGM" }) - 后台阶段:PWA 环境下,在 service worker 中注册
self.addEventListener('push', ...),收到推送后调用clients.matchAll().then(...).postMessage({ action: 'resume-audio' }) - 降级逻辑:监听
visibilitychange,若document.hidden === true且audio.paused === true,记录当前currentTime到localStorage;切回前台后,等canplaythrough再 seek 并play() - 别碰
webkit-playsinline或playsInline—— 这是 iOS 视频内联播放用的,对 audio 无效,还可能干扰媒体上下文初始化
最易被忽略的一点:iOS Safari 要求 mediaSession 元数据必须在用户手势触发后的 300ms 内设置,超时即失效。不是写上就行,是时机必须卡准。



















