前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PWA - 令人惊奇的web用户体验新方法

PWA - 令人惊奇的web用户体验新方法

作者头像
江米小枣
发布2020-06-16 17:13:19
2.6K0
发布2020-06-16 17:13:19
举报
文章被收录于专栏:云前端

PWA(Progressive Web Apps)-令人惊奇的web用户体验新方法。

PWA全称Progressive Web App,即渐进式WEB应用,由谷歌2015年提出.明确的一点就是:PWA是一个网页, 可以通过web技术开发出一个网页应用. 随后添加上 App Manifest 和 Service Worker 来实现 PWA 的安装和离线等功能.pwa 可以添加在用户的主屏幕上,不用从应用商店进行下载,他们通过网络应用程序 Manifest file 提供类似于 APP 的使用体验( 在 Android 上可以设置全屏显示,由于 Safari 支持度的问题,所以在 IOS 上并不可以 ),并且还能进行 ”推送通知” 。

  • 渐进式:能确保每个用户都能打开网页,可以运行在不支持 PWA 技术的浏览器里。用户不能离线访问,不过其他功能都像原来一样没有影响。
  • 离线应用:支持用户在没网的条件下也能打开网页,这里就需要 Service Worker 的帮助,可以离线运行
  • APP 化:能够像 APP 一样和用户进行交互。被打开时,PWA 会展示一个有吸引力的闪屏。chrome 提供了可选选项,可以使 PWA 得到全屏体验。
  • 安全:PWA使用https进行通信加密,防止了被第三方获取数据以及数据被篡改
  • 推送:做到在不打开网页的前提下,推送新的消息
  • 可安装:能够将 Web像 APP 一样添加到桌面,可以在主屏幕上创建图标
为什么是渐进式
  • 降低站点改造的代价,逐步支持各项新技术,不要一蹴而就
  • 新技术标准的支持度还不完全,新技术的标准还未完全确定
Service Worker主要是干什么?
  • 主要用来做持久的离线缓存。
  • 一个独立的 worker 线程,独立于当前网页进程,有自己独立的 worker context。
  • 一旦被 install,就永远存在,除非被 uninstall
  • 可编程拦截代理请求和返回,缓存文件,缓存的文件可以被网页进程取到(包括网络离线状态)
  • 能向客户端推送消息
  • 出于安全的考虑,必须在 HTTPS 环境下才能工作
  • 异步实现,内部大都是通过 Promise 实
  • Service Worker 的缓存机制是依赖 Cache API 实现的
  • 依赖 HTML5 fetch API
  • 运行于浏览器后台,可以控制打开的作用域范围下所有的页面请求
  • 不能操作页面 DOM。但可以通过事件机制来处理
service worker 生命周期

register(注册) - installing -> installed(安装) -> actvating -> Activated(激活) -> Redundant(废弃)

  • 安装( installing ):这个状态发生在 Service Worker 注册之后,表示开始安装,触发 install 事件回调指定一些静态资源进行离线缓存。

install 事件回调中有两个方法: * event.waitUntil():传入一个 Promise 为参数,等到该 Promise 为 resolve 状态为止。 * self.skipWaiting():self 是当前 context 的 global 变量,执行该方法表示强制当前处在 waiting 状态的 Service Worker 进入 activate 状态。 * 安装后( installed ):Service Worker 已经完成了安装,并且等待其他的 Service Worker 线程被关闭。 * 激活( activating ):在这个状态下没有被其他的 Service Worker 控制的客户端,允许当前的 worker 完成安装,并且清除了其他的 worker 以及关联缓存的旧缓存资源,等待新的 Service Worker 线程被激活。

activate 回调中有两个方法: * event.waitUntil():传入一个 Promise 为参数,等到该 Promise 为 resolve 状态为止 * self.clients.claim():在 activate 事件回调中执行该方法表示取得页面的控制权, 这样之后打开页面都会使用版本更新的缓存。旧的 Service Worker 脚本不再控制着页面,之后会被停止。 * 激活后( activated ):在这个状态会处理 activate 事件回调 (提供了更新缓存策略的机会)。并可以处理功能性的事件 fetch (请求)、sync (后台同步)、push (推送)。 * 废弃状态 ( redundant ):这个状态表示一个 Service Worker 的生命周期结束。 * 安装 (install) 失败,激活 (activating) 失败 都进入废弃 (redundant) 状态

Service Worker 有几个重要的功能性的的事件

  • fetch (请求):当浏览器在当前指定的 scope 下发起请求时,会触发 fetch 事件,并得到传有 response 参数的回调函数,回调中就可以做各种代理缓存的事情了。
  • push (推送):push 事件是为推送准备的。不过首先需要了解一下 Notification API 和 PUSH API。通过 PUSH API,当订阅了推送服务后,可以使用推送方式唤醒 Service Worker 以响应来自系统消息传递服务的消息,即使用户已经关闭了页面。
  • sync (后台同步):sync 事件由 background sync (后台同步)发出。background sync 配合 Service Worker 推出的 API,用于为 Service Worker 提供一个可以实现注册和监听同步处理的方法。但它还不在 W3C Web API 标准中, 也只是一个实验性功能。

cache api

  • Cache.match(request, options) 返回一个 Promise对象,resolve的结果是跟 Cache 对象匹配的第一个已经缓存的请求。
  • Cache.matchAll(request, options) 返回一个Promise 对象,resolve的结果是跟Cache对象匹配的所有请求组成的数组。
  • Cache.add(request) 抓取这个URL, 检索并把返回的response对象添加到给定的Cache对象.这在功能上等同于调用 fetch(), 然后使用 Cache.put() 将response添加到cache中.
  • Cache.addAll(requests) 抓取一个URL数组,检索并把返回的response对象添加到给定的Cache对象。
  • Cache.put(request, response) 同时抓取一个请求及其响应,并将其添加到给定的cache。
  • Cache.delete(request, options) 搜索key值为request的Cache 条目。如果找到,则删除该Cache 条目,并且返回一个resolve为true的Promise对象;如果未找到,则返回一个resolve为false的Promise对象。
  • Cache.keys(request, options) 返回一个Promise对象,resolve的结果是Cache对象key值组成的数组。
跑一个小例子

下面是个简单的 PWA 页面, 准备一个 HTML 文件, 以及相应的 CSS 等。sw.js 文件需要在 HTML 当中引入:

一个简单的结构:
看一下index.html 要干点啥:
代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <meta http-equiv="X-UA-Compatible" content="ie=edge">
 <title>pwa beauty</title>
 <link rel="stylesheet" href="index.css">
 <link rel="manifest" href="manifest.json">
</head>
<body>
 <p>hello world beauty</p>
</body>
<script>index.html
 //判断serviceWorker是否可用
 if ('serviceWorker' in navigator) {
   navigator.serviceWorker
   .register('sw.js', {scope: '/'}) //启动安装,scope参数可选,指定控制内容的子目录,接收指定目录的所有fetch事件
   .then(function(registration) {
     //success
     console.log('scope: ', registration.scope);
   })
   .catch(err => console.log('serviceWorker 失败'), err);
 }
</script>
</html>

Service Worker 在网页已经关闭的情况下还可以运行, 用来实现页面的缓存和离线, 后台通知等等功能。

接下来看一下sw.js 主要做的这几件事情:

首先安装时会触发 install 事件,监听该事件可执行安装时要做的事情。示例中是缓存用于离线时使用的静态资源,这也是最常见的行为.

处理静态缓存:首先定义需要缓存的路径, 以及需要缓存的静态文件的列表:

代码语言:javascript
复制
var cacheStorageKey = 'manimal-pwa-1';var cacheList = [
 '/',
 'index.html',
 'index.css',
 '8.png'
]
//监听sw 的install 的事件
self.addEventListener('install', e => {
 //安装成功,调用e.waitUtill这个回调
 e.waitUtill(
   //操作缓存,先通过打开这个应用的缓存空间
   caches.open(cacheStorageKey)
   .then(caches => caches.addAll(cacheList)) //cacheList就是你想缓存的数组
   .then(() => self.skipWaiting) //skipWaiting install 之后强制进入激活状态,跳过waiting状态
 )
})
service worker 自定义请求响应

处理动态缓存: 每次任何被 Service Worker 控制的资源被请求到时,都会触发 fetch 事件,Service Worker 添加一个 fetch 的事件监听器,接着调用 event 上的 respondWith() 方法来劫持我们的 HTTP 响应,然后你可以用来更新他们

代码语言:javascript
复制
self.addEventListener('fetch', function(e) {
 e.respondWith(
   caches.match(e.request)
   .then(function (response) {
     //如果有自己的返回,直接返回,减少请求
     if (response != null) {
       return response
     }
     const request = e.request.clone();
     return fetch(request).then(function (httpRes) {
       //失败返回失败结果
       if (!httpRes || httpRes.status !== 200) {
         return httpRes;
       }
       //成功,把请求缓存
       const responseClone = httpRes.clone();
       caches.open(cacheStorageKey).then(function (caches) {
         caches.put(e.request, responseClone)
       })
       return httpRes;
     })
   })
 )
})
版本更新

更新静态资源:缓存的资源随着版本的更新会过期, 所以会根据缓存的字符串名称(这里变量为 cacheStorageKey, 值用了 "minimal-pwa-1")清除旧缓存, 可以遍历所有的缓存名称逐一判断决决定是否清除。如果 /sw.js 内容有更新,当访问网站页面时浏览器获取了新的文件,逐字节比对 /sw.js 文件发现不同时它会认为有更新启动 更新算法,于是会安装新的文件并触发 install 事件。但是此时已经处于激活状态的旧的 Service Worker 还在运行,新的 Service Worker 完成安装后会进入 waiting 状态。直到所有已打开的页面都关闭,旧的 Service Worker 自动停止,新的 Service Worker 才会在接下来重新打开的页面里生效

自动更新所有页面
代码语言:javascript
复制
self.addEventListener('activate', function (e) {
 e.waitUtill(
   caches.keys().then(cacheNames => {
     return Promise.all(
       //处理旧版本
       cacheNames.map(name => {
         if (name !== cacheStorageKey) {
           return caches.delete(name)
         }
       })  
     )
   }).then(() => {
     //更新客户端该方法表示取得页面的控制权, 这样之后打开页面都会使用版本更新的缓存
     return self.clients.claim();
   })
 )
})

在新安装的 Service Worker 中通过调用 self.clients.claim() 取得页面的控制权, 这样之后打开页面都会使用版本更新的缓存。旧的 Service Worker 脚本不再控制着页面之后会被停止。

手动更新
代码语言:javascript
复制
var version = 'manimal-pwa-2';navigator.serviceWorker.register('/sw.js').then(function (reg) {
   if (localStorage.getItem('sw_version') !== version) {
       reg.update().then(function () {
           localStorage.setItem('sw_version', version)
       });
   }
});
查看demo

执行命令:

代码语言:javascript
复制
http-server -p 8088 -c-1 # 注意设置关闭缓存, 这里用参数 -c-1
# 用另一个终端
ngrok http 8088

注意: Demo 当中如果直接启动 http-server 而不使用 -c-1 关闭缓存, sw.js 可能被缓存住, 导致更新方案失败。这种情况下存在 Caches API 和 HTML caching 两层缓存, 需要进行清理才能完成更新。由于 Service Worker 限制了使用 HTTPS 地址, 在 Android Chrome 打开需要借助 ngrok 生成的 HTTPS 地址, 这样才能把 demo 添加到首屏。添加到首屏之后, 即便在离线状态下, 页面也可以打开。

桌面浏览器可以直接通过 http://localhost:8088 访问, 从 DevTools 的 Application 标签可以看到 Service Worker。

Service Worker 浏览器支持情况

  • 2018年,全球顶级的浏览器厂商,Google、Microsoft、Apple已经全数宣布支持PWA技术
  • (apple: Safari 11.1 beta版已经支持Web App Manifest 和 Service Worker)
  • Microsoft:Edge和Windows 10全面支持PWA
  • 微软,宣布全面支持PWA
sw调试 借助 Chrome 浏览器 debug

使用 Chrome 浏览器,可以通过进入控制台 Application -> Service Workers 面板查看和调试

APP Manifest (应用清单)与添加到主屏幕

Web App Manifest 是一个 JSON 格式的文件用来描述应用相关的信息,目的是提供将应用添加至桌面的功能:

  • 能够将你浏览的网页添加到你的手机屏幕上
  • 在 Android 上能够全屏启动,不显示地址栏 ( 由于 Iphone 手机的浏览器是 Safari ,所以不支持哦)
  • 控制屏幕 横屏 / 竖屏 展示
  • 定义启动画面
  • 可以设置你的应用启动是从主屏幕启动还是从 URL 启动
  • 可以设置你添加屏幕上的应用程序图标、名字、图标大小
代码语言:javascript
复制
<link rel="manifest" href="manifest.json">
代码语言:javascript
复制
{
 "scope": "/", //定义应用模式下的路径范围,超出范围会已浏览器方式显示
 "name": "这是一个app 的名字", //完整的名字
 "short_name": "app", //短名称
 "start_url": "/index.html", //启动地址
 "display": "standalone",
 "description": "每天知道多一点.",
 "dir": "rtl",
 "lang": "cn",
 "orientation": "portrait", //纵向, 竖屏
 "theme_color": "#3f51b5",
 "background_color": "#fff",
 "icons": [{
   "src": "images/avatar/lzwme-36x36.png",
   "sizes": "36x36",
   "type": "image/png"
 }, {
   "src": "images/avatar/lzwme-48x48.png",
   "sizes": "48x48",
   "type": "image/png"
 }, {
   "src": "images/avatar/lzwme-72x72.png",
   "sizes": "72x72",
   "type": "image/png"
 }, {
   "src": "images/avatar/lzwme-96x96.png",
   "sizes": "96x96",
   "type": "image/png"
 }, {
   "src": "images/avatar/lzwme-144x144.png",
   "sizes": "144x144",
   "type": "image/png"
 }, {
   "src": "images/avatar/lzwme-192x192.png",
   "sizes": "192x192",
   "type": "image/png"
 }, {
   "src": "images/avatar/lzwme-256x256.png",
   "sizes": "256x256",
   "type": "image/png"
 }]
}
  • short_name: 应用展示的名字
  • icons: 定义不同尺寸的应用图标
  • start_url: 定义桌面启动的 URL
  • description: 应用描述,可以参考 meta 中的 description
  • display: 定义应用的显示方式,有 4 种显示方式,分别为:
    • fullscreen: (全屏)
    • standalone: 应用 , 浏览器相关UI(如导航栏、工具栏等)将会被隐藏
    • minimal-ui: 类似于应用模式,但比应用模式多一些系统导航控制元素,但又不同于浏览器模式
    • browser: 浏览器模式,默认值
  • name: 应用名称
  • orientation: 定义默认应用显示方向,竖屏、横屏
  • background_color: 应用加载之前的背景色,用于应用启动时的过渡
  • theme_color: 定义应用默认的主题色
  • dir: 文字方向,3 个值可选 ltr(left-to-right), rtl(right-to-left) 和 auto(浏览器判断),默认为 auto
  • lang: 语言
  • scope: 定义应用模式下的路径范围,超出范围会已浏览器方式显示

PWA 应用具备了轻量化、离线使用、本地通知等优势特点,应用本身只需占用很小的存储空间,依然保留了原生 Apps 大部分功能,甚至还优化了硬件性能消耗、应用频繁出现广告内容的问题。如果你希望在安装原生应用之前,提前体验功能和内容,轻量化的 PWA 应用会是一个非常不错的选择。

参考资料

  • 浏览器兼容
  • manifest.json参数详解
  • Service Worker API
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PWA(Progressive Web Apps)-令人惊奇的web用户体验新方法。
    • 为什么是渐进式
      • Service Worker主要是干什么?
        • service worker 生命周期
        • Service Worker 有几个重要的功能性的的事件
        • cache api
          • 跑一个小例子
            • 一个简单的结构:
            • 看一下index.html 要干点啥:
          • service worker 自定义请求响应
            • 版本更新
              • 自动更新所有页面
                • 手动更新
                  • 查看demo
                    • sw调试 借助 Chrome 浏览器 debug
                      • APP Manifest (应用清单)与添加到主屏幕
                      • 参考资料
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档