如何在Chrome/Safari等移动端浏览器中实现手机锁屏状态下播放音频?
问题根因
你遇到的问题是两个浏览器底层限制共同导致的:
- 移动端浏览器在页面最小化、锁屏进入后台状态后,会对页面主线程、WebSocket连接做节流甚至临时冻结,长时间后台的情况下WebSocket连接会被系统或浏览器主动断开,无法接收事件
- 浏览器默认的音频自动播放策略,禁止非用户主动交互触发的音频播放,后台场景下该限制会更严格
可行解决方案
方案1(优先推荐):结合Web Push + Service Worker实现后台提醒
这是目前适配性最好的实现方案,不受页面后台/锁屏状态限制:
- 用户点击「Queue」按钮加入队列时,在点击回调中主动请求浏览器通知权限,该请求由用户主动交互触发,权限申请通过率高,同时完成Service Worker注册
- 服务端收到管理员叫号请求时,并行触发两个逻辑:
- 对在线的WebSocket连接正常发送
callCustomer事件 - 若检测到用户WebSocket连接处于断连/后台状态,通过Web Push服务向用户绑定的推送端点发送推送通知
- 对在线的WebSocket连接正常发送
- Service Worker独立于页面线程运行,就算页面被冻结、甚至临时被浏览器回收,只要浏览器未被彻底关闭,就可以正常接收推送,收到推送后直接触发系统级通知,同时播放提醒音频,该场景下的音频播放不会被浏览器策略拦截
示例代码参考:
用户端加入队列时申请权限+注册Service Worker:
// 加入队列按钮点击回调中执行 if ('serviceWorker' in navigator && 'PushManager' in window) { // 注册Service Worker const reg = await navigator.serviceWorker.register('/sw.js') // 请求通知权限 const permission = await Notification.requestPermission() if (permission === 'granted') { // 把推送端点上报到服务端存储,和用户排队ID绑定 const pushSubscription = await reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: <你的服务端公钥> }) await fetch('/api/save-subscription', { method: 'POST', body: JSON.stringify(pushSubscription) }) } }
Service Worker接收推送逻辑:
// sw.js中添加 self.addEventListener('push', (event) => { const options = { body: '您已被叫号,请前往窗口办理', icon: '/icon.png', sound: '/alert.mp3' } event.waitUntil( self.registration.showNotification('叫号提醒', options) ) // 直接播放音频 const audio = new Audio('/alert.mp3') audio.play() })
方案2(兼容轻量场景):优化现有WebSocket实现
如果不想引入Service Worker和推送逻辑,可以做以下优化,能覆盖大部分非长时间锁屏的场景:
- 提前解锁音频播放权限:用户点击「Queue」按钮时,主动播放一段1s的静音音频,该操作由用户主动交互触发,会给当前页面解锁音频播放权限,后续后台收到WebSocket事件时播放音频不会被拦截
- 优化WebSocket保活:单独启动Web Worker跑WebSocket心跳逻辑,心跳间隔设置为20-30秒,避免后台状态下页面主线程被冻结导致WebSocket断连
- 引导用户开启权限:提示安卓用户给浏览器开启后台活动权限、将站点添加到桌面,iOS用户开启Safari后台应用刷新权限
注意事项
iOS端Safari对后台页面的限制非常严格,锁屏超过30秒后会主动冻结所有页面线程,包括WebSocket和Web Worker,仅Web Push可以正常唤醒,要覆盖iOS全场景必须使用方案1。
内容的提问来源于stack exchange,提问作者vanir
相关产品推荐
相关产品推荐

