网站适配PWA
一、什么是PWA
PWA 全称为 Progressive Web App,中文译为渐进式 Web APP。
PWA 是 Google 于 2016 年提出的概念,于 2017 年正式落地,于 2018 年迎来重大突破,全球顶级的浏览器厂商,Google、Microsoft、Apple 已经全数宣布支持 PWA 技术。
也就是说,使用软件时,并不需要再花时间去应用商店下载客户端,也就不会占用手机的内存容量,只需要一点网络流量就可以让你快速方便的使用到原本软件里的功能。而 PWA 所占用的存储容量可能才区区的几M而已。与微信里的「小程序」,小米的“快应用”,和苹果的“轻应用”虽然原理不同,但使用方式上基本类似。
PWA 是一种渐进式网页应用理念,全称为 Progressive Web App,效果就是使用 Google 或 Edge 等支持 PWA 的浏览器打开我网站后地址栏最右边有的个圆圈小加号,点击小加号就可以将网站像桌面应用一样安装成独立APP
这个应用不仅支持 pc 端,也可以在手机上体验,操作很简单,打开网站后将站点添加到主屏幕就好了
这时有人就会说了,普通网站也可以添加到主屏幕啊,这里我就给讲讲区别,普通网站添加到主屏幕之后只是添加了一个网站的快捷打开方式,添加后点击桌面的图标会跳转到浏览器打开网页,而具有 PWA 效果的网站添加到主屏幕之后,点击桌面图标程序会单独运行,体验就像一个独立app的应用程序
官方详细介绍 Google: https://developers.google.com/web/progressive-web-apps/
二、怎么让网站适配WPA
2.1 网站必须HTTPS化
支持 PWA 的必要条件,就是网站必须 HTTPS 化。
然后对网站进行一次检测。你可以使用 Chrome 的 Lighthouse 对网站进行测试。Lighthouse 是一个 chrome 插件,可以告诉你访问的网站是不是支持 PWA,如果不支持应该如何优化。
如果网站适配过PWA,在Lighthouse里PWA选项是点亮的,没适配过或者不支持PWA这一栏会置灰
2.2 需要准备的文件
-
PWA应用的图标
-
manifest.json(PWA应用信息的文件)
-
sw.js(Service Worker 的配置文件)
2.2.1 PWA应用图标
需要2种规格的应用图标,192×192px
和 512×512px
这两种尺寸的 .png
格式的图标
2.2.2 manifest.json
{
"name": "杜若说",
"short_name": "杜若说",
"description": "dooruo Flarum PWA",
"icons": [
{
"src": "../assets/img/icon_192.png", //根据图片实际路径配置
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "../assets/img/icon_512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"background_color": "#FFE8E7", //应用加载之前的背景色,用于应用启动时的过渡
"theme_color": "#FFE8E7", //主题颜色,用于控制浏览器地址栏着色
"display": "standalone", // 定义应用的显示方式
"orientation": "portrait",
"start_url": "/", // 打开后第一个出现的页面地址
"scope": "/" // PWA作用域
}
2.2.3. sw.js
PWA 是通过 ServiceWorker 访问 Cache,所以需要注册 ServiceWorker 工作者,就用 .js 文件来配置:
'use strict';
const cacheName = 'pwa-you-website-cache'; // 缓存名字
const startPage = 'https://say.dooruo.com/'; // 首页地址
const offlinePage = 'https://say.dooruo.com/';// 离线首页地址
const filesToCache = [startPage, offlinePage];
const neverCacheUrls = [/admin/];
// 之后的代码可以不用修改
// Install
self.addEventListener('install', function(e) {
console.log('PWA service worker installation');
e.waitUntil(
caches.open(cacheName).then(function(cache) {
console.log('PWA service worker caching dependencies');
filesToCache.map(function(url) {
return cache.add(url).catch(function (reason) {
return console.log('PWA: ' + String(reason) + ' ' + url);
});
});
})
);
});
// Activate
self.addEventListener('activate', function(e) {
console.log('PWA service worker activation');
e.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if ( key !== cacheName ) {
console.log('PWA old cache removed', key);
return caches.delete(key);
}
}));
})
);
return self.clients.claim();
});
// Fetch
self.addEventListener('fetch', function(e) {
// Return if the current request url is in the never cache list
if ( ! neverCacheUrls.every(checkNeverCacheList, e.request.url) ) {
console.log( 'PWA: Current request is excluded from cache.' );
return;
}
// Return if request url protocal isn't http or https
if ( ! e.request.url.match(/^(http|https):\/\//i) )
return;
// Return if request url is from an external domain.
if ( new URL(e.request.url).origin !== location.origin )
return;
// For POST requests, do not use the cache. Serve offline page if offline.
if ( e.request.method !== 'GET' ) {
e.respondWith(
fetch(e.request).catch( function() {
return caches.match(offlinePage);
})
);
return;
}
// Revving strategy
if ( e.request.mode === 'navigate' && navigator.onLine ) {
e.respondWith(
fetch(e.request).then(function(response) {
return caches.open(cacheName).then(function(cache) {
cache.put(e.request, response.clone());
return response;
});
})
);
return;
}
e.respondWith(
caches.match(e.request).then(function(response) {
return response || fetch(e.request).then(function(response) {
return caches.open(cacheName).then(function(cache) {
cache.put(e.request, response.clone());
return response;
});
});
}).catch(function() {
return caches.match(offlinePage);
})
);
});
// Check if current url is in the neverCacheUrls list
function checkNeverCacheList(url) {
if ( this.match(url) ) {
return false;
}
return true;
}
2.3 文件准备好了之后,我们在页面中使用。
将 manifest.json 文件,引入到每个页面的
<link rel="manifest" href="mainifest.json" crossorigin="anonymous" />
<meta name="theme-color" content="#03A9F4" />
<link rel="apple-touch-icon" sizes="48x48" href="favicon.png" />
先判断浏览器是否支持 PWA,再在每个页面有条件的引入 sw.js 文件:
<script type="text/javascript">
if (navigator.serviceWorker != null) {
navigator.serviceWorker.register('sw.js')
.then(function(registration) {
console.log('Registered events at scope: ', registration.scope);
}).catch(function(err) {
console.log('Registered events at fail: ', err);
});
}
</script>
这样就适配完成了。
三、效果展示
适配完成刷新网页,我们可以看到网站地址栏有个安装的图标。
点击安装
点击安装完成后,桌面会多一个快捷方式。点击快捷方式打开应用 效果图一
手机端适配效果
手机浏览器打开网站https://say.dooruo.com,打开浏览器设置--添加至桌面。有的浏览器打开就自动提示你要添加至桌面。添加完成后手机桌面多一个app的图标。harmony系统会直接识别成快应用。
四、适配过PWA的一些网站
https://www.v2ex.com/ (需要代理)
https://www.iq.com/ (iqiyi海外版,需要全局代理)
https://www.youtube.com/ (需要代理)
参考资料
本文主要参考 图筑风暻
让你的网站初步适配PWA https://www.nousbuild.org/codeu/website-with-pwa