cover

其实 PWA 技术在很早之前就出现并已经在应用了,只是国内IOS当道,而苹果不支持PWA,所以推广和知名度不怎么好,不过最近苹果在IOS 11.3中开始支持PWA部分特性,微软UWP政策失败后,也在慢慢转战PWA,所以PWA也开始渐渐火热了起来

什么是PWA

PWA全称是Progressive Web App,是提升 Web App 的体验的一种新方法,能给用户原生应用的体验。

PWA能带给我们:

  • 显著提高应用加载速度
  • 让 web 应用可以在离线环境使用的 Service Worker 与 Cache Storage;
  • 用于描述 web 应用元数据(metadata)、让 web 应用能够像原生应用一样被添加到主屏、全屏执行的 Web App Manifest;
  • 让 web 应用能在未被激活时发起推送通知的 Push API 与 Notification API 等等。

目前PWA最佳的案例莫过于印度最大电商FlipKart把自家官网换成了PWA,并改名为FlipKart Lite,下面就和笔者一起通过图片对比体验下PWA应用能带来什么:

当浏览器发现用户需要 Flipkart Lite 时,它就会提示用户「嘿,你可以把它添加至主屏哦」(用户也可以手动添加)。这样,Flipkart Lite 就会像原生应用一样在主屏上留下一个自定义的 icon 作为入口;与一般的书签不同,当用户点击 icon 时,Flipkat Lite 将直接全屏打开,不再受困于浏览器的 UI 中,而且有自己的启动屏效果。

更强大的是,在无法访问网络时,Flipkart Lite 可以像原生应用一样照常执行,还会很骚气的变成黑白色;不但如此,曾经访问过的商品都会被缓存下来得以在离线时继续访问。在商品降价、促销等时刻,Flipkart Lite 会像原生应用一样发起推送通知,吸引用户回到应用。

图中从左到右分别为:类似原生应用的安装界面;被收纳在应用抽屉里的 Flipkart Lite 与 Hux Blog;设置界面中并列出现的 Flipkart 原生应用与 Flipkart Lite PWA (可以看到 PWA 巨大的体积优势)

PWA 关键技术

Web App Manifest

做过android开发的同学一看名字应该就知道是什么套路,通过在head标签引入app清单文件,就能定义我们的PWA程序在主屏幕上的名字、图标、启动画面等等。

使用 link 标签将 manifest.json 部署到 PWA 站点 HTML 页面的头部,如下所示:
<link rel="manifest" href="path-to-manifest/manifest.json">

一个基本的 manifest.json 应包含如下信息:


{
    "short_name": "短名称",
    "name": "这是一个完整名称",
    "icon": [
        {
            "src": "icon.png",
            "type": "image/png",
            "sizes": "48x48"
        }
    ],
    "start_url": "index.html"
}

具体的配置还有很多很多,而且还在不断新增和完善中,具体可查阅相关资料,这里就不一一列觉了。

Service Worker

Web App 在移动设备上最让人诟病的莫过于白屏次数太多,遇到网络不好的时候也许你会看到程序只有一半显示或显示错乱,严重影响用户体验。Service Worker离线技术的出现终于能够让我们的网站做到离线浏览了

也许有小伙伴会问?之前不是有个什么APPCache技术吗?确实 W3C 在 HTML5.0 中曾推出了Application Cache。不过由于设计太烂,完全不具备可编程,无路由等功能,W3C自己都已经在HTML5.1标准中移除了。- -!

Service Worker特性如下:

  • 一个独立的 worker 线程,独立于当前网页进程,有自己独立的 worker context。

  • 一旦被 install,就永远存在,除非被手动 unregister

  • 用到的时候可以直接唤醒,不用的时候自动睡眠

  • 可编程拦截代理请求和返回,缓存文件,缓存的文件可以被网页进程取到(包括网络离线状态)

  • 离线内容开发者可控

  • 能向客户端推送消息

  • 不能直接操作 DOM

  • 必须在 HTTPS 环境下才能工作

  • 异步实现,内部大都是通过 Promise 实现

总的来说 Service Worker 就像是一个运行在客户端的代理程序

如何注册一个Service Worker


if ('serviceWorker' in navigator) {
    window.addEventListener('load', function () {
        navigator.serviceWorker.register('/service-worker.js', {scope: '/'})
            .then(function (registration) {

                // 注册成功
                console.log('ServiceWorker registration successful with scope: ', registration.scope);
            })
            .catch(function (err) {

                // 注册失败:(
                console.log('ServiceWorker registration failed: ', err);
            });
    });
}

这样我们就为我们的程序注册了一个 Service Worker

如何缓存我们的资源


// service-worker.js
self.oninstall = (e) => {
  e.waitUntil(
    caches.open('installation')
      .then(cache =>  cache.addAll([
        '/',
        '/index.htm',
        '/style.css'
      ]))
  )
});

这样我们在 Service Worker安装的时候就把我们的资源缓存起来了,当用户离线,网络无法访问时,我们就可以从缓存中启动我们的 web 应用:


//service-worker.js
self.onfetch = (e) => {
  const fetched = fetch(e.request)
  const cached = caches.match(e.request)

  e.respondWith(
    fetched.catch(_ => cached)
  )
}

当然这只是一种缓存策略:

Service Worker 也有自己的生命周期,具体可参考下图:

1

Push Notification

提到消息推送一般都会认为只有原生程序才具备,其实现在我们在使用Chrome上网时很多网站都会给我们推送一些消息,就是利用 Web Notifications 给我们 Web 应用推送消息的。

目前推送的支持度还不是很高,苹果也有自己的推送协议,所以目前基本只有高版本的Chorme和Firefox支持。

下面代码展示如何在 Service Worker 中利用 Push API 显示通知消息


// service-worker.js
self.addEventListener('push', event => {
  event.waitUntil(
    // Process the event and display a notification.
    self.registration.showNotification("我是推送消息!")
  );
});

最后

在原生应用统治手机端这么多年,Web 应用能否重振PC端的辉煌,现在还不好下定论,不过就连乔布斯都相信:只有Web应用才是移动应用的未来,让我拭目以待吧!

支付宝扫码打赏 微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章

杨少凡's Picture
杨少凡

全栈工程师,现居重庆,目前就职于人和集团电商部。

Chongqing「重庆」 http://shaofan.org