添加 web 应用到桌面
Web App Manifest文件 web 应用的信息,可以将 web 应用添加到设备的主屏幕,让用户直接访问,而不是通过浏览器输入 url 访问。
Manifest 文件示例和说明如下:
{
name: "App 名称",
short_name: "App 名称",
display: "standalone", // 启动画面类型
start_url: "/?from=homescreen",
icons: [...],
background_color: "#3e4eb8",
theme_color: "#2f3ba2"
}
- dispaly:
- fullscreen: 占满整个屏幕
- standalone: 隐藏浏览器相关 UI
- minimal-ui: 与 standalone 类型
- browser: 与普通网页在浏览器中打开的显示一致
- start_url: 如果为空则为默认使用用户打开的当前页面为首屏/添加参数用于来源统计
- icons: 用于设置图标
- background_color: 启动画面背景颜色
- theme_color”: 启动画面上状态栏、地址栏的颜色
通过在 html 页面 head 中增加 link,引入 manifest 文件。
<link rel="manifest" href="/assets/manifest.json">
本网站的 manifest.json
Service Worker
Service Worker 可以拦截本地请求,根据条件判断是否请求服务器,还是从本地缓存中取数据,这使得应用在离线状态时,仍可以提供基本的功能。
Pages <----------> Service Worker <------------> Server
↑ |
| ↓
CacheStorage
Service Workder 是浏览器中独立的线程
- 不能直接访问/操作 Dom
- Promise
- Fetch API
- Cache API
- 需要时直接唤醒,不需要自动休眠
- 离线缓存内容开发者可控
- 一旦被安装则永远存活,手动触发卸载
- 必须在 HTTPS 环境下工作(本地环境 localhost 除外)
生命周期:
Error Fetch/Message
/ |
| |
Register ---> Install ---> Activated ---> Idle
| ↑ |
\ / |
Waiting Terminated
查看当前运行的 Service Worker 线程:<chrome://inspect/#service-workers>
查看所有 Service Worker 线程信息:<chrome://serviceworker-internals>
注册
通过 serviceWorker.register
注册 service worker,参数中的脚本地址通知浏览器去哪里获取 service worker 脚本,service worker 是驻留在 app 内的一个 JavaScript 文件,工作在 worker context 里,没有访问 DOM 的权限。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('sw.js', {scope: '/'})
.then(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(error => {
console.warn('Registration failed with ', error)
})
}
scope
选项指定让 service worker 控制内容的子目录,默认为 service worker 脚本所在的目录。要注意的是,如果你的 service worker 脚本在类似 /foo/../bar/scripts/
的目录下,scope
不能为 /foo/../
, /foo/../bar/
这类 scripts 的父目录。如果想指定父目录,需要把脚本的位置提到父目录,或者可以保留脚本的位置不变,通过 Service-Worker-Allowed
http 返回头字段指定 scope
。
安装 (install 事件)
install
在注册完成后触发,为 install
事件增加监听方法用于填充浏览器缓存。
// sw.js
this.addEventListener('install', function(event) {
event.waitUntil(
caches.open('v1').then(function(cache) {
return cache.addAll([
'/',
'/index.html',
'/assets/styles/main.css',
'/assets/scripts/blog.js',
]);
})
);
});
cache
是一个 service worker 上的全局对象,可以利用它存储网络响应的资源。
当安装完成之后,service worker 就会激活。
fetch 事件
任何 service worker 控制 scope 内的请求,都会触发 fetch
事件,通过监听 fetch
事件,可以拦截并处理请求,通过事件的 respondWith
方法返回响应。
self.addEventListener('fetch', event => {
let request = event.request;
// Always fetch non-GET requests from the network.
if (request.method !== 'GET') {
event.respondWith(fetch(request));
return;
}
// For HTML requests, try the network first else fall back to the offline page.
if (request.headers.get('Accept').indexOf('text/html') !== -1) {
event.respondWith(
fetch(request).catch(() => caches.match('/offline/'))
);
return;
}
// Look to the cache first, then fall back to the network.
event.respondWith(
caches.match(request).then(response => {
// return response || fetch(request)
return response || fetch(request).then(resp => {
// 将从服务器请求的资源保存到缓存中
return caches.open('v1').then(cache => {
cache.put(event.request, response.clone());
return response;
})
});
})
);
});
激活(activate 事件)
之前提到过 service worker 会在 install 完成之后激活,激活事件对第一个版本的来说无关紧要,但如果想要更新 service worker 脚本,可以利用新版本 service worker 的激活事件获取控制权,清理旧版本缓存资源。
self.addEventListener('activate', function(event) {
var cacheWhitelist = ['v2'];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});
这里假设新版本 service worker 用 v2
缓存,清理所有不是 v2
的缓存资源。
APPCache 已不推荐使用
## APPCache index.html ``` html ``` example.appcache ``` appcache CACHE MANIFEST # 2018-04-09: v2 CACHE /favicon.ico index.html stylesheet.css images/logo.png scripts/main.js NETWORK: /api FALLBACK: /index.html /static.html ```- older
- Newer