博客简单支持PWA

PWA

PWA(Progressive Web App) 渐进式增强Web应用。

目的将网页应用可以和原生应用一样给用户原生app的使用体验。

当然更多的可以查看相关文档。

为了配合我的github pages 上的博客

主要是利用缓存API进行响应的存储和拦截请求从缓存返回响应。

在断网状态下也可以返回一个自定义的断网页面。

主要的技术是利用:

  • Web App Manifest
  • Service Workers
  • Promise
  • Cache API

结合上面3个就能简单实现PWA的web app 的简单支持了。

参考文档链接:

使用Service Workers

解决问题和方法

无法离线使用:

​ 使用缓存和Service Workers 等技术实现离线加载缓存内容

无法添加到桌面:

​ 通过使用manifest.json文件配置,可以将web app 添加到主屏幕。

开始

使用sw.js

// 应用前缀
const APP_PREFIX = 'XTRUET';
// 根据每次的sw.js的版本更改缓存内容
// 需要更改缓存的时候需要改变这个版本才能进行重新安装状态
const VERSION = 'v_3.0.1';
// 缓存的名称
const CACHE_NAME = APP_PREFIX + VERSION;
// 需要缓存的url静态资源
const URLS = [
  '/index.html',
  '/public/css/style.css',
  '/public/js/toc.js',
  '/public/js/prism.js',
  '/public/image/alipay.png',
  '/public/image/wechatpay.png',
  '/public/image/404.jpg',
  '/public/simple-jekyll-search/search.json',
  'https://ae01.alicdn.com/kf/Hb70dbc4687de416199bb2b295704957f0.png'
]

// 缓存资源

self.addEventListener('install',(e)=>{
  // 等待promise完成标记安装状态为完成安装
  e.waitUntil(
    // 打开一个缓存对象
    caches.open(CACHE_NAME).then((cache)=>{
      console.log(`install:${CACHE_NAME}`);
      // 以url为key,内容为value
      return cache.addAll(URLS);
    }).then(()=>self.skipWaiting())
  );
});

// 拦截请求

this.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function() {
      return fetch(event.request.url).then(function(response) {
        return caches.open(CACHE_NAME).then(function(cache) {
          cache.put(event.request.url, response.clone());
          return response;
        });  
      });
    }).catch(function() {
      return caches.match('/public/image/404.jpg');
    })
  );
});


// 移除旧缓存

self.addEventListener('activate',(e)=>{
  e.waitUntil(
    caches.keys().then((keys)=>{
      var cacheWhitelist = keys.filter((key)=>key.indexOf(APP_PREFIX));
      cacheWhitelist.push(CACHE_NAME);
      return Promise.all(keys.map((key,i)=>{
        if(cacheWhitelist.indexOf(key) === -1){
            console.log(`delete cache:${keys[i]}`);
            return caches.delete(keys[i]);
        }
      }));
    }).then(()=>clients.claim())// 更新客户端
  );
})

建立manifest.json

{
  "short_name": "XTRUET",
  "name": "XTRUET",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    }
  ],
  "start_url": "/",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}
short_name: 应用展示的名称(桌面上显示的名称)

icons: 定义不同尺寸的应用图标

start_url: 定义桌面启动的 URL

description: 应用描述,可以参考 meta 中的 description

display: 定义应用的显示方式,有 4 种显示方式,分别为:

fullscreen: 全屏

standalone: 应用

minimal-ui: 类似于应用模式,但比应用模式多一些系统导航控制元素,但又不同于浏览器模式

browser: 浏览器模式,默认值

name: 应用名称(浏览器提示用户添加和Android启动屏显示的名称)

orientation: 定义默认应用显示方向,竖屏、横屏

prefer_related_applications: 是否设置对应移动应用,默认为 false

related_applications: 获取移动应用的方式

background_color: 应用加载之前的背景色,用于应用启动时的过渡

theme_color: 定义应用默认的主题色

dir: 文字方向,3 个值可选 ltr(left-to-right), rtl(right-to-left)  auto(浏览器判断),默认为 auto

lang: 语言

scope: 定义应用模式下的路径范围,超出范围会已浏览器方式显示

在页面添加

<link rel="manifest" href="/manifest.json">

注册使用sw.js

<script>
    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.register('/sw.js', 
           { scope: '/' }).then(function(reg) {
            if(reg.installing) {
                console.log('Service worker installing');
            } else if(reg.waiting) {
                console.log('Service worker installed');
            } else if(reg.active) {
                console.log('Service worker active');
            }
        }).catch(function(error) {
            // registration failed
            console.log('Registration failed with ' + error);
        });
    }
</script>

上述两个需要写在页面的内容,我将他们放置到了我的_include文件加的head.html

好处

部分浏览器支持添加到电脑桌面快捷方式,将应用成为一个类桌面的应用。

使用缓存提高加载速度,提升用户体验。

问题

浏览器兼容不好,蛮多浏览器没有主动能提示用户这是个pwa应用。

即使我们使用谷歌浏览器添加到了主屏幕,也可以不出现,有些手机系统桌面直接就是一级菜单,不存在能添加快捷方式的地方,所以还是跟没有一样。。。



奖励一下