PWA(Progressive Web App)入门系列:(三)PWA关键技术Manifest

3,970 阅读9分钟

前言

前面说过,让Web App能够达到Native App外观体验的主要实现技术就是PWA中的manifest技术,本章会详细说明manifest的实现,及各个参数的具体含义,还将了解如何定义Web App的启动图标、启动样式等。

简介

manifest是一种简单的json数据风格的配置文件,通过对其相应的属性进行配置,才实现相应的功能,这里可以称manifest为WEB应用清单。WEB应用清单可以实现自定义启动画面、打开URL、设置界面颜色、设置桌面图标等等。

大概就是下面这样:

{
    "short_name": "短名称",
    "name": "这是一个完整名称",
    "icons": [
        {
            "src": "144x144.png",
            "type": "image/png",
            "sizes": "144x144"
        }
    ],
    "background_color": "#2196f3",
    "display": "standalone",
    "start_url": "index.html"
}

部署到浏览器

好么manifest.js如何让浏览器去执行呢?

只需要用link标记引用即可:

<link rel="manifest" href="manifest.js">

目前各大浏览器对manifest的支持程度:

成员

下面对manifest涉及到的各个属性详细说一下。

name

name: {string},用来描述应用的名称,会显示在各类提示的标题位置和启动画面中。

short_name

short_name: {string},用来描述应用的短名字。当应用的名字过长,在桌面图标上无法全部显示时,会用short_name中定义的来显示。

start_url

start_url: {string},用来描述当用户从设备的主屏幕点击图标进入时,出现的第一个画面。

  • 如果设置为空字符串,则会以manifest.js的地址做为URL
  • 如果设置的URL打开失败,则和正常显示的网页打开错误的样式一下(可以通过后面讲的ServiceWorker改善)
  • 如果设置的URL与当前的项目不在一个域下,也不能正常显示
  • start_url 必须在scope的作用域范围内
  • 如果 start_url 是相对地址,那么根路径基于manifest的路径
  • 如果 start_url 为绝对地址,则该地址将永远以 / 作为根路径

scope

scope : {string},用来设置manifest对于网站的作用范围。
下面列一下,scope的作用范围及对start_url的影响:

manifest的文件位置 start_url scope配置 计算好的scope 计算好的start_url 是否有效
/inner/manifest.json ./index.html undefined /inner/ /index.html 有效
/inner/manifest.json ./index.html ../ / /index.html 有效 - 但作用域泄露到了更高层级
/inner/manifest.json / / / /index.html 有效 - 但作用域泄露到了更高层级
/inner/manifest.json / undefined /inner/ / 无效 - start url不在作用域范围内
/inner/manifest.json ./inner/index.html undefined /inner/ /inner/inner/index.html 有效 - 但start url明显不符合预期
/manifest.json ./inner/index.html undefined / /inner/index.html 有效 - 广作用域
/manifest.json ./inner/index.html inner /inner/ /inner/index.html 有效 - 窄作用域

icons

icons: {Array.<ImageObject>},用来设置Web App的图标集合。

ImageObject 包含属性:

  • src: {string},图标的地址
  • type {string},图标的 mime 类型,可以不填写。这个字段会让浏览器不使用定义类型外的图标
  • sizes {string},图标的大小,用来表示widthxheight,单位为px,如果图标要适配多个尺寸,则第个尺寸间用空格分割,如12x12 24x24 100x100

sizes适配规则:

  • 在PWA添加到桌面的时候,浏览器会适配最合适尺寸的图标。浏览器首先会去找与显示密度相匹配且尺寸调整到 48dp 屏幕密度的图标,例如它会在 2 倍像素的设备上使用 96px,在 3 倍像素的设备上使用 144px。。
  • 如果没有找到任何符合的图标,则会查找与设备特性匹配度最高的图标。
  • 如果匹配到的图标路径错误,将会显示浏览器默认 icon。

需要注意的是,图标中必须要有一张尺寸为144x144的,图标的 mime 类型为 image/png的。

background_color

background_color: {Color},值为CSS的颜色值,用来设置Web App启动画面的背景颜色。

可以像正常写CSS颜色那样定义:

// 完整色值
"background_color": "#0000ff"
// 缩写
"background_color": "#00f"
// 预设色值
"background_color": "yellow"
// rgb
"background_color": "rgb(0, 255, 255)"
// transparent 背景色显示为黑色
"background_color": "transparent"

其他的定义rgbahslhsla等颜色定义方式浏览器不支持,未设置时,背景色均显示白色。

theme_color

theme_color: {Color},定义和background_color一样的CSS颜色值,用于显示Web App的主题色,显示在banner位置。

display

display: {string},用来指定 Web App 从主屏幕点击启动后的显示类型

显示类型 描述 降级显示类型
fullscreen 应用的显示界面将占满整个屏幕 standalone
standalone 浏览器相关UI(如导航栏、工具栏等)将会被隐藏 minimal-ui
minimal-ui 显示形式与standalone类似,浏览器相关UI会最小化为一个按钮,不同浏览器在实现上略有不同 browser
browser 浏览器模式,与普通网页在浏览器中打开的显示一致 (None)

对于不同的显示样式,可以通过CSS的媒体查询进行设置:

@media all and (display-mode: fullscreen) {
    div {
        padding: 0;
    }
}

@media all and (display-mode: standalone) {
    div {
        padding: 1px;
    }
}

@media all and (display-mode: minimal-ui) {
    div {
        padding: 2px;
    }
}

@media all and (display-mode: browser) {
    div {
        padding: 3px;
    }
}

orientation

orientation: {string},Web App的在屏幕上的显示方向。

  • landscape-primary,当视窗宽度大于高度时,当前应用处于“横屏”状态
  • landscape-secondarylandscape-primary的180°方向
  • landscape,根据屏幕的方向,自动横屏幕180°切换
  • portrait-primary,当视窗宽度小于高度时,当前应用处于“竖屏”状态
  • portrait-secondaryportrait-primary的180°方向
  • portrait,根据屏幕方向,自动竖屏180°切换
  • natural, 根据不同平台的规则,显示为当前平台的0°方向
  • any,任意方向切换

dir

dir: {string},设置文字的显示方向。
- ltr,文本显示方向,左到右
- rtl,文本显示方向,右到左
- auto,根据系统的方向显示

related_applications

related_applications: {Array.<AppInfo>},用于定义对应的原生应用,类似应用安装横幅的形式去推广、引流。

AppInfo结构:
- platform: {string}, 应用平台
- id: {string} 应用id

如安卓可以这么定义:

"related_applications": [
    {
        "platform": "play",
        "id": "com.app.xxx"
    }
]

prefer_related_applications

prefer_related_applications:{Boolean},用于设置只允许用户安装原生应用。

实例

下面写一下相关的常用实例。

目录结构

项目结构:

根路径 /
    |
    |----manifest.json  // 清单文件
    |
    |----index.html
    |
    |----144x144.png  // 图标文件
    |
    |----sw.js

因为浏览器要安装manifest中的定义,需要一些其他的代码环境条件,以上目录中,我们只讨论manifest.json文件,其他文件后面会做说明。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Manifest</title>
  <link rel="manifest" href="./manifest.json"> <!-- 引用manifest文件 -->
</head>
<body>
  <h1>Manifest Page</h1>
  <script>
  // 此处代码 后面相关章节会去说明
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
      navigator.serviceWorker.register('sw.js')
        .then(function(registration) {})
        .catch(function(err) {})
    })
  }
  </script>
</body>
</html>

sw.js

// 此处代码 后面相关章节会去说明
var cacheName = 'helloWorld'

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(cacheName)
    .then(cache => cache.addAll([
      'index.html'
    ]))
  )
})

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.match(event.request)
    .then(function (response) {
      if (response) {
        return response;
      }
      return fetch(event.request);
    })
  )
})

144x144.png

将应用添加到桌面

manifest.js

{
    "short_name": "短名称",
    "name": "这是一个完整名称",
    "icons": [
        {
            "src": "144x144.png",
            "type": "image/png",
            "sizes": "144x144"
        }
    ],
    "display": "standalone",
    "start_url": "index.html"
}

按照上面方式配置,在移动端Chrome上访问,效果如下:

浏览器会提示一个“添加到主屏幕”的提示。提示的标题显示的是在manifest中定义的name,当点击时,就会将应用添加到桌面:

桌面图标上显示的文本为manifest中定义的short_name。

点击应用图标,打开应用:

可以看到根据设置的display属性,打开的应用去除了浏览器的地址栏。

注意

浏览器“添加到主屏幕”的提示是需要满足下面条件才会显示的:

  1. 需要manifest文件
  2. manifest中需要定义start_url
  3. 需要包含144x144的png图标文件
  4. 网站是通过Https访问的
  5. 并且网站中运行ServiceWorker
  6. 用户需要至少浏览过网站两次,并且两次的间隔大于5分钟
  7. 如果修改了 manifest 的配置,已添加到主屏幕的名称并不会改变,只有当用户重新添加到桌面时,更改后的配置才会生效。但是在未来版本的 Chrome 浏览器将支持自动更新

关于上面提到的第4点,我们可以建立一个https网站或者可以直接用github的pages服务来实现。

关于第6点,是为了防止每次打开网址都有这个提示,对用户造成较差的体验。

设置主题色

"theme_color": "red"

给主题色设置个红色:

可以发现App的header上已经变成了设置的红色。

设置启动界面

启动界面是由icon、background_color和name构成的。

"background_color": "#2196f3"

效果:

icon也会根据屏幕的尺寸,浏览器来适配最佳的图标。

添加到主屏幕 触发的事件

当执行”添加到主屏幕“的操作时,内部会触发相应的事件beforinstallprompt。可以利用这个事件做一些事情,例如App判断流量入口:

window.addEventListener('beforeinstallprompt', function(e) {
    e.userChoice.then(function (result){
        if (result.outcome === 'dismissed'){
            // 发送数据进行分析
        } else {
            // 发送数据进行分析
        }
    })
})

事件中的userChoice对象用来返回用户的选择信息,处理是基于Promise的,这个后面章节会详说。

本地调试

上面是为了实现真是效果,所以在真是移动端上实现的。其实在测试的时候,是可以通过Chrome的开发者工具来测试的。

首先,打开上一章里下载的”WebServer for Chrome”本地服务器工具,并把项目加下到里面,然后开始服务

然后,在Chrome浏览器中访问”Web Server URL(s)“下的地址http://127.0.0.1:8887

然后,打开开发者工具,打开Application选项卡,选择Manifest,就可以后到配置的信息了。

并可以通过点击”Add to homescreen“触发添加图标到桌面的事件。

授权后即可添加到桌面




线上manifest验证

除去本地调试外,还可以通过在线清单验证工具来实现验证,例如:Web Manifest Validator

总结

到这里,总结一下:

  • manifest是一种简单的JSON文件,通过对属性进行相应的配置,可以实现很多类Native的体验
  • 添加到主屏幕会触发相应的事件,可以基于这些事件做相应的处理
  • 调试的时候,可以基于Chrome的开发者工具,或者通过线上的测试验证工具
  • https可以借助github pages功能实现

博客名称:王乐平博客

CSDN博客地址:blog.csdn.net/lecepin

知识共享许可协议 本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。