在Service Worker网页推送通知中如何播放自定义通知音效?
报错原因及解决方案
错误根因
你当前的push事件监听代码运行在Service Worker 线程中,这是浏览器的后台无UI工作线程,无法访问页面上下文的 DOM、BOM API,包括你调用的Audio构造函数、alert方法,页面级的navigator.vibrate也无法在SW中直接调用,因此触发报错。
可行实现方案
有两种兼容场景的实现方式,覆盖用户打开/未打开网页的情况:
方案1:通过SW通知页面播放音频(用户已打开网页时生效)
第一步:修改Service Worker中的push事件代码
self.addEventListener("push", (e) => { const data = e.data.json(); // 调用系统通知 e.waitUntil( self.registration.showNotification(data.title, { body: data.message, icon: data?.icon, image: data?.media, data: { url: data?.url }, // 通知自带震动配置,不需要单独调用navigator.vibrate vibrate: [ 100, 30, 100, 30, 100, 30, 200, 30, 200, 30, 200, 30, 100, 30, 100, 30, 100, ], // 新增:通知自带sound参数,用户未打开网页时兼容的浏览器会自动播放 sound: "/notification-sound.mp3" // 替换为你自己站点下的音频地址 }) ); // 给所有打开的当前站点页面发消息,触发页面播放音频 e.waitUntil( self.clients.matchAll().then(clients => { clients.forEach(client => { client.postMessage({ type: "push-notification", data: data }); }); }) ); });
第二步:在你的网页业务代码中添加监听逻辑
// 监听Service Worker发来的推送消息 if ('serviceWorker' in navigator) { navigator.serviceWorker.addEventListener('message', (e) => { if (e.data.type === 'push-notification') { // 页面上下文可以正常使用Audio API const playSound = new Audio("/notification-sound.mp3"); playSound.play().catch(err => { // 捕获播放失败情况,比如用户未交互过页面导致自动播放被拦截 console.log("通知音效播放失败:", err); }); // 这里可以写你需要的页面提示逻辑,替代之前的alert alert("NEW ORDER RECEIVED"); } }); }
注意事项
- 音频文件请放在站点同域目录下,不要使用第三方跨域音频链接,避免CORS限制导致加载失败
- 提前将音频文件加入Service Worker的预缓存列表,避免推送到达时才首次加载音频导致延迟或播放失败
- 部分浏览器(如Firefox)暂不支持Notification的
sound参数,这种场景下只有用户打开网页时才能正常播放自定义音效 - 浏览器自动播放策略要求音频播放需要用户至少和页面有过一次交互,否则可能被拦截
内容的提问来源于stack exchange,提问作者Sreerag Pavithran
相关产品推荐
相关产品推荐

