Javascript 在移动设备上未触发服务工作程序`onupdatefound`
下面是我如何注册我的服务人员:Javascript 在移动设备上未触发服务工作程序`onupdatefound`,javascript,android,google-chrome,service-worker,workbox,Javascript,Android,Google Chrome,Service Worker,Workbox,下面是我如何注册我的服务人员: if ('serviceWorker' in navigator) { window.addEventListener('load', () => { function updateOnlineStatus() { SnackBar.show({ text: navigator.onLine ? onlineMsg : offlineMsg, backgroundColor: '#000000',
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
function updateOnlineStatus() {
SnackBar.show({
text: navigator.onLine ? onlineMsg : offlineMsg,
backgroundColor: '#000000',
actionText: close,
actionTextColor: '#d2de2f',
customClass: 'custom-snackbar',
});
}
window.addEventListener('online', updateOnlineStatus);
window.addEventListener('offline', updateOnlineStatus);
navigator.serviceWorker.register('sw.js').then((reg) => {
reg.onupdatefound = () => {
const installingWorker = reg.installing;
installingWorker.onstatechange = () => {
switch (installingWorker.state) {
case 'installed':
if (navigator.serviceWorker.controller) {
SnackBar.show({
text: refreshMsg,
backgroundColor: '#000000',
actionText: refresh,
actionTextColor: '#d2de2f',
onActionClick: () => { location.reload(); },
customClass: 'custom-snackbar',
});
} else {
console.info(availableMsg);
}
break;
case 'redundant':
console.info(redundantMsg);
break;
default:
break;
}
};
};
}).catch((e) => {
console.error(errorMsg, e);
});
});
}
此服务辅助程序是在按Workbox生成期间生成的
我有点担心,因为这些通知显示在我的电脑上(ubuntu++chrome 59.0.3071.115
),但从来没有在我的手机上显示过(android 6.0.1++chrome 59.0.3071.125
)
使用远程调试功能进行分析后,我的手机上似乎从未触发过onupdatefound
我对UX感觉很糟糕,想到手机上的访问者不知道新版本的网站即将发布
如有任何建议,将不胜感激
编辑1:我找到了有关此网页“浏览器兼容性”部分的更多详细信息:。Chrome对Android的支持似乎是未知的 当浏览器不支持
onupdatefound
事件时,你们是否有一种回退/解决方法
编辑2:回应Jeff,
sw.js
头在.htaccess
文件中管理:
<Files sw.js>
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</Files>
关于您建议的workbox微调,我还没有来得及深入研究,所以我在一个文件中使用了easyworkbox build
。但我希望会:)
你认为这可能是由skipWaiting:true引起的吗
编辑3:尝试使用广播频道
navigator.serviceWorker.register('/sw.js').then((reg) => {
console.log('test');
const updateChannel = new BroadcastChannel('precache-updates');
updateChannel.addEventListener('message', event => {
console.log(`Cache updated: ${event.data.payload.updatedUrl}`);
});
}).catch((e) => {
console.error(errorMsg, e);
});
即使在Chrome、mobile或firefox的日志中输出了
test
,更新消息只在Chrome上抛出在Android和Linux上Chrome的service worker实现中应该没有任何区别,这将解释一个平台在service worker注册时没有暴露updatefound
事件。(MDN在这里不一定具有权威性。)
过去,每当我调试这种不可预测的更新时,都是由于与HTTP缓存和sw.js
脚本的交互。你能检查一下你在提供sw.js
服务时使用的缓存控制
头吗
另外,您提到您正在使用Workbox,如果是这样的话,您可以使用更高级的方法来检查更新的资源。
workbox broadcast cache update
插件(如果您使用的是workbox sw
的precache()
方法,则默认情况下会启用该插件)可以宣布特定缓存资源何时更新,然后您可以使用广播频道API在页面上侦听该消息。这样,当最重要的资源(如HTML)发生变化时,您才可以显示您的SnackBar
,而不是不太重要的资源(如可能预先制作的随机图像)。正如您所怀疑的,问题根本不是服务人员自己造成的
我从零开始,试图找出这个问题的根源,逐段添加代码,直到没有更多的事件被暴露。我明白了:这是因为three.js
动画中使用了一个“昂贵”的循环
在将这段代码放入worker之后,我的页面现在能够在移动设备或Firefox上捕获这些事件,用户的通知工作正常
关于它在桌面版Chrome上工作这一令人困惑的事实,我想这是因为它必须支持多线程
再次感谢您的帮助:)您可能希望在查看文档后修改您的观察者。感谢您抽出时间!我编辑了OP,其中包含了与您的观察相关的更多详细信息
skipWaiting
和clientsClaim
都不应阻止触发updatefound
事件。如果您使用的是workbox build
,那么生成的sw.js
将“免费”获得广播频道API更新。只需在precache updates
频道上收听客户端页面的更新。见我应用了你的建议(编辑3)。遗憾的是,它在手机或Firefox上仍然不起作用,但在PC的chrome上仍然起作用。我真的很困惑:(但无论如何还是要感谢你的帮助!这似乎是一个bug。你向chromium团队报告了吗?
// Service Worker generation
gulp.task('bundle-sw', gulp.series('generate-sitemap', () => {
return wbBuild.generateSW({
globDirectory: gulpOutputDir,
swDest: `${gulpOutputDir}/sw.js`,
globPatterns: ['**/*.{html,png,xml,css,ico,txt,json,svg,js,map,gif,jpeg,jpg,bmp,cur,webp,woff2}'],
skipWaiting: true,
clientsClaim: true,
})
.then(() => {
console.warn('Service worker generated.');
})
.catch((err) => {
console.error(`[ERROR] This happened: ${err}`);
});
}));
navigator.serviceWorker.register('/sw.js').then((reg) => {
console.log('test');
const updateChannel = new BroadcastChannel('precache-updates');
updateChannel.addEventListener('message', event => {
console.log(`Cache updated: ${event.data.payload.updatedUrl}`);
});
}).catch((e) => {
console.error(errorMsg, e);
});