0%

把网站添加到桌面,「爱奇艺网页应用」是如何实现的

背景

希望网站提供一个「添加网页应用」功能,点击安装后,自动为用户创建一个网站的桌面快捷方式。

下次用户直接从桌面快捷方式,即可访问我们的网站

iqiyi.png

方案

1. Chrome App

在线安装(由于网络原因不太可行,而且如今已经没有入口了) or 离线下载

举几个熟悉的 Chrome 应用:微信、Postman 。可以理解为一个独立的新应用了,和网站本身没有任何关系,因此可拓展性也较高。

曾经较为流行,由于各种原因,chrome 将不再支持(目前只支持更新,不再上新),所以该方案放弃

详见 https://blog.chromium.org/2020/01/moving-forward-from-chrome-apps.html

2. Progressive Web App (PWA)

渐进式 Web 应用,这不是一个单独的技术,而是多种技术的组合,包括

  • Web app manifests: 通过 JSON 提供应用程序相关信息,目的是将应用程序安装到设备桌面
  • Service Worker: 充当浏览器与服务端间的网络代理,提供离线访问能力
  • Push API: 从服务器向客户端推送消息,需要借助 service worker
  • Notifications API: 允许网页或应用程序在系统级别发送在页面外部显示的通知
  • Add to Home Screen: 将应用程序安装到设备桌面的关键,需要浏览器支持 beforeinstallprompt 事件

不要被上述技术栈吓到。。如果只是为了实现 「把网站添加到桌面」功能,仅需要 Web app manifests, Add to Home Screen , Service Worker . 5分钟就可以开发好

功能实现

首先需要说明的是,我们的网站必须运行在 https 环境。所以开发测试的时候可以用 github.io 白嫖

大体流程如下:

  1. 编写一个简单的 HTML 页面
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>A2HS demo</title>
    <style>
    .add-button {
    position: absolute;
    top: 1px;
    left: 1px;
    }
    </style>
    <script src="index.js" defer></script>
    <link rel="manifest" href="manifest.webmanifest">
    </head>
    <body>
    <div>测试文本</div>
    <button class="add-button">添加到桌面</button>
    </body>
    </html>
  2. 编写一份 Web app manifests JSON(后面会详细讲解各个字段) ,命名为 manifest.webmanifest ?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"background_color": "purple",
"display": "fullscreen",
"icons": [
{
"src": "icon/fox-icon.png",
"sizes": "192x192",
"type": "image/png"
}
],
"name": "xx快捷版",
"short_name": "快",
"start_url": "."
}
  1. 注册安装事件

index.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
let deferredPrompt;
// 默认不展示按钮,仅支持 「Add to Home Screen」 功能才展现
const addBtn = document.querySelector('.add-button');
addBtn.style.display = 'none';

// 规定必须注册 serviceWorker 才能使用 Add to Home Screen,
// 且需要监听 install 和 fetch 事件,可以不处理
if('serviceWorker' in navigator) {
navigator.serviceWorker
.register('./sw.js')
.then(function() { console.log('Service Worker Registered'); });
}

// 仅浏览器支持且未安装该应用,以下事件才会触发
window.addEventListener('beforeinstallprompt', (e) => {
// Chrome 67 及之前版本,会自动展现安装的 prompt
// 为了版本统一及用户体验,我们禁止自动展现 prompt
e.preventDefault();
// 存放事件用于后续触发
deferredPrompt = e;
// 展现按钮
addBtn.style.display = 'block';

addBtn.addEventListener('click', (e) => {
// hide our user interface that shows our A2HS button
addBtn.style.display = 'none';
// 展现安装的 prompt
deferredPrompt.prompt();
// 等待用户对 prompt 进行操作
// 如果用户从地址栏或其他浏览器组件安装了PWA,则以下代码将不起作用
deferredPrompt.userChoice.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('点击添加');
} else {
console.log('取消添加');
}
deferredPrompt = null;
});
});
});
// 无论以何种方式安装 PWA 该事件都会触发
// 因此这里可以用来做埋点
window.addEventListener('appinstalled', (evt) => {
console.log('应用安装');
});
  1. 编写 sw 文件

sw.js

1
2
3
4
5
6
7
self.addEventListener('install', function(e) {
console.log('install success')
});

self.addEventListener('fetch', function(e) {
console.log(e.request.url);
});
  1. 最后,准备一个 icon ,见 manifest.webmanifest 中的 icons 配置

之后,就可以体验这个功能了

在线示例

https://fe-examples.github.io/pwa-examples/a2hs/

如果浏览器支持 ,页面左上角将展现 「添加到桌面」按钮

欢迎试用,并把操作系统、浏览器型号发在评论区,看看兼容性如何~

Web app manifests 相关配置

这里只举常用的,更多详见 WebAppManifest

  • background_color: 应用启动时资源未加载时展示的背景色。仅用于改善加载时的用户体验,不影响后续网站背景。
  • theme_color: 主题色,相当于显式的设置 <meta name="theme-color" content="颜色值"> ,将会影响浏览器外观颜色的展现。
  • display: 指定如何显示应用。有以下几种取值,在不支持的情况下按从上往下顺序 fallback
    • fullscreen: 占用所有可用显示区域,无任何浏览器 UI 元素。不影响 Fullscreen API
    • standalone: 类似本机应用程序。排除地址栏,但是可能包含状态栏和系统后退按钮
    • minimal-ui: 相比 standalone 增加了导航控件(后退,前进,刷新)等 UI 元素
    • browser: 等同于打开标签页。需要注意的是, browser 是兜底方式且仅部分浏览器支持,如果浏览器还不支持,整份配置将无效

      Macos chrome 下测试 2 和 1 显示一致,不支持 4

  • icons: 指定在不同位置时采用的图标,主要是根据 sizes 字段来判断。相比移动端 APP 的 icon ,PWA 多了桌面位置、Chrome 应用入口位置。至少指定一个 icon
  • name/short_name: 前者为完整的应用名称,后者为当没有足够空间显示全名时才展示。最好两者都提供
  • start_url: 应用启动时所加载的 URL 。其值为相对于 manifest 的 url 的相对路径

    例如 manifest URL 为 https://www.iqiyi.com/manifest.json ; start_url 为 ./index.html ,则启动地址为 https://www.iqiyi.com/index.html 。而 start_url 为 . 启动地址就是 https://www.iqiyi.com/
    还有更多的骚操作,比如把 uuid 或者 launcher 方式带在 start_url 后面( ./?launcher=homescreen&uuid=xxxx),有助于用户分析

singleton

singleton

minimal-ui
minimal-ui

根据不同的启动方式应用不同样式

比如说,PWA 背景色应用红色,普通 Tab 应用白色,该如何实现呢?

可以采用 CSS 的媒体查询

1
2
3
4
5
@media all and (display-mode: standalone) {
body {
background-color: red;
}
}

或者脚本检测

1
2
3
4
5
6
7
8
9
window.addEventListener('load', () => {
if (navigator.standalone) {
console.log('Launched: Installed (iOS)');
} else if (matchMedia('(display-mode: standalone)').matches) {
console.log('Launched: Installed');
} else {
console.log('Launched: Browser Tab');
}
});

⚠️ 注意:iOS Safari 不支持 matchMedia ,但是其可以通过 navigator.standalone 返回的 true 表明自己以独立模式运行

浏览器兼容性

可以看到,我们仅用到了 PWA 体系中的 Web app manifests , Add to Home ScreenService Worker,因此该功能的浏览器兼容性取决于这几个的短板

Service Worker

sw.png

Add to Home Screen

待测试,本机(Macos chrome 81 支持)

Web app manifests

待测试,本机(Macos chrome 81 支持)

结论

(兼容性列表欢迎大家一起维护~)

题外话 - 自己动手丰衣足食

对于普通的 Chrome 用户,如果自己喜欢的网站没有实现上述功能,自己如何把网站添加到桌面呢?

右上角选择「更多工具」-「创建快捷方式」- 「确定」

如果选择新窗口打开,新开窗口将不带导航栏、工具栏等,类似于 display=standalone ,否则就是普通的打开标签页 display=browser

可以看到桌面就存在一个该网站的图标了~ 点击就可以打开该网站

参考文献

  1. Provide a custom install experience
  2. Transitioning from Chrome Apps
  3. 渐进式 Web 应用(PWA)
您的支持将鼓励我继续创作!