Progressive Web App(PWA)
PWA的中文名叫做渐进式网页应用,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验
PWA 不是特指某一项技术,而是应用了多项技术的 Web App。其核心技术包括 App Manifest、Service Worker、Web Push,等等
PWA具有以下特点:
- 可发现: 可以通过搜索引擎发现。
- 可安装: 可以出现在设备的主屏幕。
- 可链接: 可以简单地通过 URL 分享。
- 独立于网络: 可以在离线状态或者是在网速很差的情况下运行。
- 渐进式: 在老版本的浏览器仍旧可以使用,在新版本的浏览器上可以使用全部功能。
- 可重入: 无论何时有新的内容,都可以发送通知。
- 响应式: 在任何具有屏幕和浏览器的设备上可以正常使用——包括手机、平板电脑、笔记本、电视、冰箱等。
- 安全:在用户、应用和服务器之间的连接是安全的,第三方无法访问你的敏感数据。
使用PWA很简单,只需要在HTML中的head中使用link标签引用一个manifest.json文件即可。
manifest
添加应用至主屏幕
显示应用安装横幅的条件
浏览器在 PWA 站点满足以下条件时会自动显示横幅:
- 站点部署 manifest.json,该文件需配置如下属性:
- short_name (用于主屏幕显示)
- name (用于安装横幅显示)
- icons (其中必须包含一个 mime 类型为 image/png 的图标声明)
- start_url (应用启动地址)
- display (必须为 standalone 或 fullscreen)
- 站点注册 Service Worker。
- 站点支持 HTTPS 访问。
- 站点在同一浏览器中被访问至少两次,两次访问间隔至少为 5 分钟。
manifest.json 的配置如下:
{
"short_name": "短名称",
"name": "这是一个完整名称",
"icon": [
{
"src": "../../images/logo-144x144.png",
"type": "image/png",
"sizes": "144x144"
}
],
"start_url": "./index.html"
}
显示原生应用安装横幅的条件
浏览器在 PWA 站点满足以下条件时会自动显示横幅:
- 站点部署 manifest.json,该文件需配置如下属性:
- short_name (用于主屏幕显示)
- name (用于安装横幅显示)
- icons (其中必须包含一个 192x192 且 mime 类型为 image/png 的图标声明)
- 包含原生应用相关信息的 related_applications 对象
- 站点注册 Service Worker。
- 站点支持 HTTPS 访问。
- 站点在同一浏览器中被访问至少两次,两次访问间隔至少为 2 天。
其中 related_applications 的定义如下:
related_applications: Array. 关联应用列表 AppInfo 的属性值包括:
platform: {string} 应用平台 id: {string} 应用id
"related_applications": [
{
"platform": "play",
"id": "com.baidu.samples.apps.iosched"
}
]
常用配置的含义:
- name:应用的名称
- short_name:应用的简称
- start_url:应用的启动页
- display:应用的显示模式,有以下几种模式:
- fullscreen:全屏模式
- standalone:独立模式
- minimal-ui:最小化模式
- browser:浏览器模式
- background_color:应用的背景颜色
- theme_color:应用的主题颜色
- description:应用的描述
- icons:应用的图标,可以配置多个图标,每个图标都有自己的尺寸和类型
- src:图标的路径
- sizes:图标的尺寸
- type:图标的类型
Service Worker
ServiceWorker
是一个运行在浏览器背后的独立线程,它拥有访问网络的能力,可以用来实现缓存、消息推送、后台自动更新等功能,甚至可以用来实现一个完整的 Web 服务器。
Service Worker 的生命周期
- parsed: 注册完成, 脚本解析成功, 尚未安装
- installing: 对应 Service Worker 脚本 install 事件执行, 如果事件里有 - event.waitUntil() 则会等待传入的 Promise 完成才会成功
- installed(waiting): 页面被旧的 Service Worker 脚本控制, 所以当前的脚本尚未激活。可以通过 self.skipWaiting() 激活新的 Service Worker
- activating: 对应 Service Worker 脚本 activate 事件执行, 如果事件里有 event.waitUntil() 则会等待这个 Promise 完成才会成功。这时可以调用 Clients.claim() 接管页面
- activated: 激活成功, 可以处理 fetch, message 等事件
- redundant: 安装失败, 或者激活失败, 或者被新的 Service Worker 替代掉
Service Worker 注册
if (navigator.serviceWorker) {
navigator.serviceWorker.register('service-worker.js')
.then(function(registration) {
console.log('service worker 注册成功');
}).catch(function (err) {
console.log('servcie worker 注册失败');
});
}
Service Worker 拦截
this.addEventListener('fetch', function(event) {
event.respondWith(
// magic goes here
);
});
Service Worker 更新缓存
-
更新sw.js文件,一旦浏览器发现安装使用的sw.js是不同的(通过计算hash值),浏览器就会重新安装service worker,你可以在安装激活的过程中清空之前的缓存,这样浏览器就会使用服务器上最新的资源。
-
对资源文件进行版本控制,就像我上面的例子一样你可以用style-2.css来代替style-1.css,这样service worker就会使用新的资源并缓存它。当然版本号不应该这么简单,最好是使用文件的内容+修改时间+大小的hash值来作为版本号。
缓存区别
- 浏览器缓存:
- 分为强缓存和协商缓存,其共同点都是通过设置 HTTP Header 实现
- 当没有网络的时候,应用无法访问,因为 HTML 页面总得去服务器获取。 缓存不可编程,无法通过 JS 来精细地对缓存进行增删改查。
- 应用缓存(Application Cache):
- 不能选择更新哪些资源
- 当manifest文件更新了,所有指定资源都会重新下载
- Web Worker:
- 只能服务于新建它的页面,不同页面之间不能共享同一个 Web Worker
- 当页面关闭时,该页面新建的 Web Worker 也会随之关闭,不会常驻在浏览器中。
- Service Worker
- 可精细化控制缓存
- 不是服务于某个特定页面的,而是服务于多个页面的。(按照同源策略)
- 会常驻在浏览器中,即便注册它的页面已经关闭,Service Worker 也不会停止。本质上它是一个后台线程,只有你主动终结,或者浏览器回收,这个线程才会结束
优先级: memory > sw > dist
加载速度: memory > dist > sw
service-worker缺点:
- 无法访问DOM,无法使用同步方法,如localStorage
- 必须再https环境下使用
- 需要在作用范围的根目录下创建service-worker,如要将全局的页面进行管理,就需要在根目录下注册
- 速度比浏览器缓存慢
- 在存在memory cache的情况下,无法更新缓存
通知推送
通知
它能够脱离推送 API 单独工作
通知-请求授权
var button = document.getElementById("notifications");
button.addEventListener('click', function(e) {
Notification.requestPermission().then(function(result) {
if(result === 'granted') {
randomNotification();
}
});
});
创建一个通知
function randomNotification() {
var randomItem = Math.floor(Math.random()*games.length);
var notifTitle = games[randomItem].name;
var notifBody = 'Created by '+games[randomItem].author+'.';
var notifImg = 'data/img/'+games[randomItem].slug+'.jpg';
var options = {
body: notifBody,
icon: notifImg
}
var notif = new Notification(notifTitle, options);
setTimeout(randomNotification, 30000);
}
推送
通知 (notification),它允许服务器向用户提示一些信息,并根据用户不同的行为进行一些简单的处理
步骤:
- 注册ServiceWorker获得registration对象
- 通过registration对象获得PushManager对象
- 通过PushManager对象订阅消息推送,获得subscription对象
- 将subscription对象发送给服务器,由服务器保存
- 服务器通过subscription对象推送消息
- ServiceWorker通过监听push事件,获得推送的消息
- ServiceWorker通过showNotification方法,显示消息
在FCM服务器申请 GCMApiKey 用于验证推送消息的身份
离线推送
当浏览器关闭的时候,如果有推送消息,这时推送消息就会被FCM服务器保存起来,等你的网页或者浏览器上线的时候,FCM
服务器会通过notificationcallback
回调来推送消息到你的网页或者浏览器
PWA 支持检测工具: www.pwabuilder.com/
注:部分图片来自互联网