背景
以前用RN做过一个App,因时间成本太高搁置了,后来趁休假做了H5版的还在吗挂上去。 PWA火的时候大概了解了下,后来想在公司业务上用也没上成,所以就周未宅家支持了pwa看能不能提升下体验。
PWA
PWA(Progressive Web Apps) 渐进式web应用,Google推出的致力于将网页app化的项目。弥补web app对比native app急缺的几个能力,比如离线使用、后台加载、添加到主屏和消息推送等,同时具备“无需安装、用完即走”的特性。
曾经火了一阵,后来就没声音了,不是技术本身不好,是环境不适合,孤岛理论,圈地收割。
参考:
- developer.mozilla.org/en-US/docs/…
- mip、lavas
Web App Manifest
配置文件(建议命名为pwa.webmanifest),目的是将Web应用程序安装到设备的主屏幕。
{
"name": "Minimal app to try PWA",
"short_name": "AppName",
"display": "standalone",
"start_url": "/",
"theme_color": "#8888ff",
"background_color": "#aaaaff",
"icons": [
{
"src": "icon.png",
"sizes": "256x256",
"type": "image/png"
}
]
}
详细配置参考:developer.mozilla.org/zh-CN/docs/…
Service Worker
独立于UI主线程的线程避免阻塞渲染,用于处理耗费性能的事情,可以实现:后台消息传递、网络代理,转发请求,伪造响应、离线缓存、消息推送、…
特性
- 须支持https(开发用localhost)
- sw并不会一直在运行状态,生命周期与它所处理的事件执行联系在一起(作用域下事件触发,被唤醒处理事件,然后终止)
生命周期
- installing,注册时会下载js、解析进入安装状态。成功进入installed或失败进入redundant。可监听install事件中使用waitUntil实现延期。
- installed/waiting,另一个激活的worker在控制应用会维持在waiting状态。
- activating,激活前会触发activate事件
- activated,激活后开始监听功能性事件(fetch、push),serviceworker只能够在页面开始加载前控制页面
- redundant,serviceworker独立于浏览器窗口或标签页,打开新标签浏时览器检测到试图注册的sw已激活就不会再次安装。安装激活事件只会运行一次。
事件
- fetch,页面发起http请求时sw可以通过fetch事件拦截请求,并且给出自己的响应。
- message,页面和sw之间可通过posetMessage()发消息,通过message事件接收。可将sw作为中间纽带,使得一个域名或子域名下的多页面通信。
注册
- 默认scope是sw文件所在目录,只能指定scope为所在目录或子目录域。
- 如果sw文件的返回头中指定了service-worker-allowed:/,则可以设置任意根目录下的scope。
- 同域下可注册多个不同scope的sw。 参考:谨慎处理 Service Worker 的更新
平台差异
各平台浏览器实现差异...
部分Code
this.addEventListener('load,function(event){
if (navigator.serviceWorker) {
navigator.serviceWorker.register('static/service-worker.js',{scope:'/static/'})
.then(registration=> {
console.log('service worker 注册成功');
}).catch(function (err) {
console.log('servcie worker 注册失败')
});
navigator.serviceWorker.oncontrollerchange = function(){
alert('页面已经更新');
}
if(!navigator.online){
alert('当前离线,为您展示缓存内容');
window.addEventListener('online',()=>{
alert('网络已连接,请刷新获取最新内容');
})
}
}
})
let CACHE_NAME='cache_v0';
let CACHE_URLS=[
'/',
'/js/main.js',
'/js/render.js',
'css/main.css',
'img/log.png'
];
this.addEventListener('install,function(event){
event.waitUntil(
caches.open(CACHE_NAME).then(function(cache){
cache.addAll(CACHE_URLS);
}).then(()=>{
self.skipWaiting();
})
);
})
this.addEventListener('activate',function(event){
event.waitUntil(
Promise.all([
this.clients.claim(); //不刷新接管已加载页面
caches.keys().then(cacheList=>{
return Promise.all(
cacheList.map(cacheName=>{
if(cacheName != CACHE_NAME){
return caches.delete(cacheName);
}
})
)
})
])
);
})
this.addEventListener('fetch',function(event){
let url = new URL(event.request.url);
if(url.origin != self.origin){ //外域cdn资源
return;
}
if(event.request.url.include('api/')){
event.responseWith(
fetch(event.request).then(
cache.open(CACHE_NAME).then(
cache=>cache.put(req,res.clone())
)
return res;
).catch(
return catchs.match(event.request);
)
)
return;
}
event.responseWith(
fetch(vent.request).catch(()=>{
return catchs.match(event.request);
})
);
})
使用了PWA的网站
实践上线
调试
- 控制台-application-Manifest/service worker
- chrome://inspect/#service-workers 可以查看到当前运行的service worker
workbox
找到现成的方案,workbox
webpack插件:workbox-webpack-plugin
- GenerateSW,简单快速使用,自动生成sw文件,自行手动注册即可
- InjectManifest,适合于细粒度控制,可以结合已有代码使用
缓存策略,
- NetworkFirst
- CacheFirst
- NetworkOnly
- CacheOnly
- StaleWhileRevalidate从缓存中读取同时发送请求更新缓存
总结
- 如果能添加到桌面,一等公民,体验上也会较普通浏览器中有较大提升
- Android上,Chrome无疑是支持最好的,前提是用户手机能安装Chrome,且Chrome有桌面快捷方式的权限(正常人都找不到开启权限的地方),国内厂商自带浏览器个别支持(huawei、mi),主流浏览器(uc、qq、360)完全不支持
- iOS虽然晚支持,不让其它浏览器添加桌面,Safari也不会弹提示,但能Safari上能判断并做出引导,添加桌面后图标上也无特殊标识,所以反而是目前可做到效果最好的 所以总结下来就是->爱而不得