Gahing's blog Gahing's blog
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Gahing / francecil

To be best
首页
知识体系
  • 前端基础
  • 应用框架
  • 工程能力
  • 应用基础
  • 专业领域
  • 业务场景
  • 前端晋升 (opens new window)
  • Git
  • 网络基础
  • 算法
  • 数据结构
  • 编程范式
  • 编解码
  • Linux
  • AIGC
  • 其他领域

    • 客户端
    • 服务端
    • 产品设计
软素质
  • 面试经验
  • 人生总结
  • 个人简历
  • 知识卡片
  • 灵感记录
  • 实用技巧
  • 知识科普
  • 友情链接
  • 美食推荐 (opens new window)
  • 收藏夹

    • 优质前端信息源 (opens new window)
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 把网站添加到桌面,「爱奇艺网页应用」是如何实现的

    • 背景
      • 方案
        • 1. Chrome App
        • 2. Progressive Web App (PWA)
      • 功能实现
        • 在线示例
        • Web app manifests 相关配置
        • 根据不同的启动方式应用不同样式
      • 浏览器兼容性
        • Service Worker
        • Add to Home Screen
        • Web app manifests
        • 结论
      • 题外话 - 自己动手丰衣足食
        • 参考文献
        gahing
        2020-05-21
        随笔 2020
        目录

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

        # 背景

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

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

        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 应用 (opens new window),这不是一个单独的技术,而是多种技术的组合,包括

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

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

        # 功能实现

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

        大体流程如下:

        1. 编写一个简单的 HTML 页面
        <!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>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        1. 编写一份 Web app manifests JSON(后面会详细讲解各个字段) ,命名为 manifest.webmanifest ? (opens new window)
        {
          "background_color": "purple",
          "display": "fullscreen",
          "icons": [
            {
              "src": "icon/fox-icon.png",
              "sizes": "192x192",
              "type": "image/png"
            }
          ],
          "name": "xx快捷版",
          "short_name": "快",
          "start_url": "."
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        1. 注册安装事件

        index.js

        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
        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
        1. 编写 sw 文件

        sw.js

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

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

        # 在线示例

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

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

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

        # Web app manifests 相关配置

        这里只举常用的,更多详见 WebAppManifest (opens new window)

        • 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 的媒体查询

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

        或者脚本检测

        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');
          }
        });
        
        1
        2
        3
        4
        5
        6
        7
        8
        9

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

        # 浏览器兼容性

        可以看到,我们仅用到了 PWA 体系中的 Web app manifests , Add to Home Screen 和 Service 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 (opens new window)
        2. Transitioning from Chrome Apps (opens new window)
        3. 渐进式 Web 应用(PWA) (opens new window)
        编辑 (opens new window)
        #随笔#PWA
        上次更新: 2024/09/01, 23:56:56
        最近更新
        01
        浅谈代码质量与量化指标
        08-27
        02
        快速理解 JS 装饰器
        08-26
        03
        Vue 项目中的 data-v-xxx 是怎么生成的
        09-19
        更多文章>
        Theme by Vdoing | Copyright © 2016-2024 Gahing | 闽ICP备19024221号-1
        • 跟随系统
        • 浅色模式
        • 深色模式
        • 阅读模式