如何在Service Worker中打开mailto:与tel:链接?解决Chrome安卓端异常问题
解决Android Chrome中Service Worker推送通知的mailto/tel协议唤起问题
我之前也碰到过一模一样的问题——Windows端Chrome里点击推送通知的邮件/电话按钮能正常唤起对应系统应用,但Android端Chrome却会打开一个显示mailto:...或tel:...链接的空白黑标签页,完全不符合预期。这其实是Android Chrome在Service Worker环境下,对mailto:、tel:这类非HTTP(S)协议的处理逻辑和桌面端有差异,直接调用clients.openWindow()会被当作普通URL解析,而非唤起系统应用。
修复后的代码方案
你可以调整notificationclick事件的处理逻辑,先获取当前活跃的客户端页面(或者打开一个临时空白页),然后在客户端上下文里发起协议跳转,就能让Android Chrome正确唤起对应应用了:
self.addEventListener('notificationclick', function(event) { event.notification.close(); // 先关闭通知弹窗 const { contactRequest } = JSON.parse(event.notification.data); // 封装协议跳转逻辑 const handleProtocolAction = (url) => { return clients.matchAll({ type: 'window', includeUncontrolled: true }) .then(clientList => { // 优先复用已打开的同域名页面 for (const client of clientList) { if (client.url.startsWith(self.origin) && 'focus' in client) { return client.focus().then(() => { client.navigate(url); // 在已有页面上下文里触发协议跳转 }); } } // 没有活跃页面时,打开临时空白页再跳转 if (clients.openWindow) { return clients.openWindow('/blank.html').then(newClient => { if (newClient) { newClient.navigate(url); } }); } }); }; switch(event.action) { case 'call': event.waitUntil(handleProtocolAction('tel:' + contactRequest.phone)); break; case 'mail': event.waitUntil(handleProtocolAction('mailto:' + contactRequest.email)); break; default: // 处理通知默认点击行为(比如打开网站主页) event.waitUntil(clients.openWindow('/')); } });
关键细节说明
- 用
event.waitUntil()包裹异步操作:确保Service Worker在完成协议跳转逻辑前不会被浏览器终止,保证操作能执行完成。 - 优先复用已有客户端:通过
clients.matchAll()找到当前域名下的活跃页面,在这个页面上下文里发起协议跳转,避免不必要的新标签页打开。 - 临时空白页兜底:如果没有活跃页面,先打开一个同域名的空白页面(比如
/blank.html,你需要自己创建这个空页面),再在页面内触发协议跳转——Android Chrome会识别到协议并唤起对应应用,之后空白页可以自动关闭。
你需要创建的/blank.html可以非常简单,只需要加一段自动关闭的逻辑即可:
<!DOCTYPE html> <html> <head> <script> // 页面加载后短暂延迟自动关闭 window.addEventListener('load', () => { setTimeout(() => window.close(), 100); }); </script> </head> <body></body> </html>
这样修改后,Android Chrome就能和桌面端一样,点击推送通知的邮件/电话按钮直接唤起系统邮件或拨号应用,不会再出现烦人的空白黑标签页了。
内容的提问来源于stack exchange,提问作者Ivan Beldad
相关产品推荐
相关产品推荐

