九、使用清单使我们的应用可安装

我们现在开始向进步的 Web 应用领域迈进。从现在起,我们唯一的重点将是利用现有的应用,使其更快、更流畅、更友好。

渐进式 Web 应用的一大优势是缩小 Web 应用(在浏览器中查看)和本机应用(作为单独的应用启动)之间的差距。特别是在接下来的几章中,我们将重点介绍如何使我们的 web 应用更像本地应用,同时又不会失去 web 应用的所有优势。

与本机应用相比,web 应用的第一个主要优点是没有安装障碍。如果你创建一个本地应用,你需要说服用户在使用你的应用之前投入宝贵的存储和带宽。他们必须愿意坐下来完成下载和安装过程。然后他们必须把它放在身边,即使他们不经常使用它。

Web 应用没有这样的障碍。您几乎可以立即使用它们,最复杂的 web 应用的功能可以与本地应用相媲美。他们的缺点是什么?嗯,用户必须导航到他们的浏览器,然后导航到网页,才能使用它。他们没有从手机主屏幕上清晰地看到应用存在的提醒。

两个世界中最好的是什么?它将是一个应用,允许用户在承诺将其安装到设备之前试用,但一旦安装,它的行为与本机应用完全相同,在设备的主屏幕上有一个图标。

我们如何才能做到这一点?我们可以通过 web 应用清单来实现这一点。

在本章中,我们将介绍以下内容:

  • 什么是 web 应用清单?
  • 如何在 Android 上安装我们的应用
  • 如何在 iOS 上安装我们的应用
  • 使用 web 应用安装横幅

什么是应用清单?

第 2 章开始使用 Webpack时,当我们设置我们的 Webpack 构建配置时,我们确保我们的构建过程生成了一个资产清单,文件名为asset-manifest.json

此文件包含应用使用的 JavaScript 文件列表。如果我们愿意,我们可以将其配置为同时列出我们使用的 CSS 和图像文件。

这个资产清单让我们了解了清单的用途——描述了应用的某些部分。我们的 web 应用清单类似,但只是从更高的层次描述了我们的应用的全部内容,其方式类似于本地应用的应用商店描述。

这就是它看起来的样子,我们将在构建文件后立即深入研究它,但 web 应用清单的真正魔力在于它的功能。

在某些浏览器上(本章稍后将对此进行详细介绍),如果您的 web 应用包含正确的 web 应用清单,则用户可以选择将网页保存到其主屏幕,在主屏幕上,它将显示为普通应用,并带有自己的启动图标。当他们点击图标时,它将启动一个启动屏幕,并且(尽管它是从浏览器运行的)以全屏模式运行,因此它看起来和感觉上都像一个普通的应用。

浏览器支持

这是 web 应用清单的缺点——这是一项新技术。因此,很少有浏览器真正支持它。到目前为止,只有 Android Webview 和 Chrome for Android 的较新版本获得了完全支持。

我预测所有更新的浏览器都会很快得到支持,但这会给我们带来什么呢?

简而言之,有一些方法可以在旧浏览器上激活类似的功能。在本章中,我们将介绍如何在 iOS 设备上使用 web 应用清单(适用于更新浏览器上的用户,并为将来做好准备)和polyfill

如果您有兴趣覆盖其他设备,可以使用 polyfills,例如ManUphttps://github.com/boyofgreen/manUp.js/ )。这些多边形填充所做的是,它们针对不同的设备采取各种变通方法,并将它们编译成一个清单文件。

然而,这本书是关于 web 应用的未来的,所以我们将向您展示为 web 应用清单世界所需的一切。

让我们的应用可安装-Android

谷歌是 PWA 的最大支持者之一,因此他们的 Chrome 浏览器和 Android 操作系统对 web 应用清单最友好是有道理的。

让我们来看看创建清单的过程,以使其与最新版本的 Chrome 一起工作。在本章后面,为了支持 iOS,我们将以更手动的方式完成相同的过程。

清单属性

让我们开始吧!在public/文件夹中,创建一个名为manifest.json的文件,然后添加一个空对象。以下每一项都是该对象的键值对。我们将快速浏览每个可用的酒店:

  • name:您的申请名称。简单!:
"name": "Chatastrophe",
  • short_name:应用名称的可读版本。这适用于全名不适合的情况,例如在用户的主屏幕上。如果你的应用名为“为什么 PWAs 对每个人都很好”,你可以将其缩短为“PWAs R Great”或其他内容:
“short_name”: “Chatastrophe”,
  • icons: A list of icons for the user's device to use. We will just use our current logo, which is conveniently the maximum size needed for an icon.

    谷歌推荐以下一组图标:

    • 128x128 作为基本图标大小
    • 适用于 Apple 设备的 152x152
    • 用于 Microsoft 设备的 144x144
    • 铬合金 192x192
    • 256x256、384x384 和 512x512 用于不同的设备尺寸

    最后两个包含在资产包中。我们需要设计师为我们的生产构建创建其余部分,但目前还不需要他们:

"icons": [
  {
    "src":"/img/icon.png",
    "sizes": "192x192",
    "type": "image/png"
  },
  { 
    "src": "/img/icon-256.png", 
    "sizes": "256x256", 
    "type": "image/png" 
  }, 
  { 
    "src": "/img/icon-384.png", 
    "sizes": "384x384", 
    "type": "image/png" 
  }, 
  { 
    "src": "/img/icon-512.png", 
    "sizes": "512x512", 
    "type": "image/png" 
  }
],
  • start_url:起始 URL 用于分析目的,以便您可以查看有多少用户通过已安装的 PWA 访问您的 web 应用。这是可选的,但不会造成伤害:
"start_url": "/?utm_source=homescreen",
  • background_color:背景色用于应用启动时显示的启动屏幕的颜色。在这里,我们将其设置为漂亮的橙红色:
"background_color": "#e05a47",
  • theme_color:这类似于background_color,但当你的应用处于活动状态时,它会在 Android 上设置工具栏的样式。很好的触感:
"theme_color": "#e05a47",
  • display:如前所述,PWAs 可以像本地应用一样启动,即浏览器栏隐藏;这就是这个属性所激活的。如果您认为用户能够更好地查看地址栏,可以将其设置为“浏览器”:
"display": "standalone"

其他属性

对于我们的应用,您还需要注意以下几个属性:

  • related_applications:您可以提供与您的 web 应用相关的本地应用列表,并提供一个可下载的 URL;将其与prefer_related_applications配对。
  • prefer_related_applications:默认为 false 的布尔值。如果为 true,则会通知用户相关应用。
  • scope:字符串,如/app。如果用户导航到范围之外的页面,应用将返回到浏览器中常规网页的外观。
  • description:您的应用的功能描述;不是强制性的。
  • dir:类型的方向。
  • langshort_name的语言。当与dir配对时,可用于确保从右向左的语言正确显示。

链接我们的舱单

就这样!最后,你的manifest.json应该是这样的:

{
  "name": "Chatastrophe",
  "short_name": "Chatastrophe",
  "icons": [
    {
      "src":"/img/icon.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    { 
      "src": "/img/icon-256.png", 
      "sizes": "256x256", 
      "type": "image/png" 
    }, 
    { 
      "src": "/img/icon-384.png", 
      "sizes": "384x384", 
      "type": "image/png" 
    }, 
    { 
      "src": "/img/icon-512.png", 
      "sizes": "512x512", 
      "type": "image/png" 
    }
  ],
  "start_url": "/?utm_source=homescreen",
  "background_color": "#e05a47",
  "theme_color": "#e05a47",
  "display": "standalone"
}

然后您可以从您的index.html链接它,如图所示:

<link rel="manifest" href="/manifest.json">

确保您也将其复制到您的build文件夹中。

如果一切顺利,并且您拥有最新版本的 Chrome,您可以通过进入 Chrome 开发工具中的Application选项卡来检查它是否正常工作。请确保首先重新启动服务器。您应该看到以下内容:

现在来测试它!让我们使用yarn deploy再次运行部署流程。完成后,导航到 Android 设备上的应用。为了触发 web app 安装横幅,您需要访问两次该网站,每次访问间隔五分钟:

如果您没有看到安装横幅,您也可以通过转到选项下拉列表并选择添加到主屏幕来安装它。

单击“添加到主屏幕”后,您将看到它出现:

然后,当我们启动时,我们会看到一个漂亮的闪屏:

很可爱。

这就是为 Android 制作可安装 PWA 的要点。多亏了谷歌对 PWAs 的倡导,这是一个很好的简化流程,但毫无疑问,我们的许多用户将使用 iPhone,因此我们必须确保我们也支持他们。

使我们的应用可安装-iOS

截至撰写本文时,苹果还没有公开支持渐进式网络应用。关于原因有很多理论(他们创造收入的应用商店生态系统、与谷歌的竞争、缺乏控制),但这确实意味着让我们的应用可安装的过程更为手动。

让我们明确一点——到目前为止,最佳的 PWA 体验将是在 Android 设备上使用最新版本的 Chrome 的用户。

然而,PWA 也都是关于渐进增强的,我们将在后面的章节中更深入地介绍这个概念。渐进式增强意味着我们为每个用户在其设备上提供最佳体验;如果他们能支持所有闪亮的新东西,那就太好了,否则,我们会用他们使用的工具尽最大努力。

因此,让我们来看看让想要将我们的应用保存到主屏幕的 iPhone 用户满意我们的 UX 的过程。

我们将使用大量的<meta>标签告知浏览器我们的应用是可安装的。让我们从图标开始:

<link rel="apple-touch-icon" href="/img/icon.png">

将以下内容添加到public/index.html(对于本节的其余部分,将所有meta标签分组到link标签之上)。这定义了用户主屏幕上的图标。

接下来,我们在页面中添加一个标题,该标题将用作主屏幕上应用的名称。在您的link标签后添加以下内容:

<title>Chatastrophe</title>

然后,我们需要让 iOS 知道这是一个 web 应用。您可以使用以下meta标记来执行此操作:

<meta name="apple-mobile-web-app-capable" content="yes">

正如我们在安卓部分中对theme_color所做的那样,我们希望设计状态栏的显示方式。默认值为黑色,如下所示:

另一个选项是黑色半透明,它不是很黑,主要是半透明的:

添加以下内容:

<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

我们最不想做的事情是设计启动屏幕的样式;应用启动时显示的内容。

在 iOS 上实现这一点的方法是一点手动操作——提供一个静态映像。

要获得全面支持,您需要为每个 iOS 屏幕大小(从 iPad 到最小的 iPhone)提供单独的启动映像。如果您想看到多个启动图像和图标的好例子,请查看中的要点 https://gist.github.com/tfausak/2222823 。以下是该要点中的启动映像链接:

    <!-- iPad retina portrait startup image -->
    <link href="https://placehold.it/1536x2008"
          media="(device-width: 768px) and (device-height: 1024px)
                 and (-webkit-device-pixel-ratio: 2)
                 and (orientation: portrait)"
          rel="apple-touch-startup-image">

    <!-- iPad retina landscape startup image -->
    <link href="https://placehold.it/1496x2048"
          media="(device-width: 768px) and (device-height: 1024px)
                 and (-webkit-device-pixel-ratio: 2)
                 and (orientation: landscape)"
          rel="apple-touch-startup-image">

    <!-- iPad non-retina portrait startup image -->
    <link href="https://placehold.it/768x1004"
          media="(device-width: 768px) and (device-height: 1024px)
                 and (-webkit-device-pixel-ratio: 1)
                 and (orientation: portrait)"
          rel="apple-touch-startup-image">

    <!-- iPad non-retina landscape startup image -->
    <link href="https://placehold.it/748x1024"
          media="(device-width: 768px) and (device-height: 1024px)
                 and (-webkit-device-pixel-ratio: 1)
                 and (orientation: landscape)"
          rel="apple-touch-startup-image">

    <!-- iPhone 6 Plus portrait startup image -->
    <link href="https://placehold.it/1242x2148"
          media="(device-width: 414px) and (device-height: 736px)
                 and (-webkit-device-pixel-ratio: 3)
                 and (orientation: portrait)"
          rel="apple-touch-startup-image">

    <!-- iPhone 6 Plus landscape startup image -->
    <link href="https://placehold.it/1182x2208"
          media="(device-width: 414px) and (device-height: 736px)
                 and (-webkit-device-pixel-ratio: 3)
                 and (orientation: landscape)"
          rel="apple-touch-startup-image">

    <!-- iPhone 6 startup image -->
    <link href="https://placehold.it/750x1294"
          media="(device-width: 375px) and (device-height: 667px)
                 and (-webkit-device-pixel-ratio: 2)"
          rel="apple-touch-startup-image">

    <!-- iPhone 5 startup image -->
    <link href="https://placehold.it/640x1096"
          media="(device-width: 320px) and (device-height: 568px)
                 and (-webkit-device-pixel-ratio: 2)"
          rel="apple-touch-startup-image">

    <!-- iPhone < 5 retina startup image -->
    <link href="https://placehold.it/640x920"
          media="(device-width: 320px) and (device-height: 480px)
                 and (-webkit-device-pixel-ratio: 2)"
          rel="apple-touch-startup-image">

    <!-- iPhone < 5 non-retina startup image -->
    <link href="https://placehold.it/320x460"
          media="(device-width: 320px) and (device-height: 480px)
                 and (-webkit-device-pixel-ratio: 1)"
          rel="apple-touch-startup-image">

您可能会注意到,这些链接不包括 iPhone 6 Plus 之后的任何 iPhone。截至撰写本文时,iOS 9 上的启动映像支持有问题,iOS 10 上没有支持。虽然这不会影响你的应用的用户体验(不管怎样,闪屏应该只会出现一秒钟),但这表明苹果对 PWAs 缺乏全面支持。希望这种情况在不久的将来会有所改变。

总的来说,让你的应用成为一个可安装的 iOS 网络应用并不像manifest.json那样花哨或直观,但相当简单。使用yarn deploy重新部署应用,然后在 iPhone 上使用 Safari 打开网页。然后,点击共享并添加到主屏幕:

它应该像普通应用一样出现在主屏幕上,并且在启动时显示如下:

这很滑。

以下是决赛index.html的样子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="utf-8">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon">
    <link rel="manifest" href="/manifest.json">
    <link rel="apple-touch-icon" href="/img/icon.png">
    <title>Chatastrophe</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="/secrets.js"></script>
    <script src="https://www.gstatic.com/firebasejs/4.3.0/firebase.js"></script>
    <script>
      // Initialize Firebase
      var config = {
        apiKey: window.apiKey,
        authDomain: "chatastrophe-draft.firebaseapp.com",
        databaseURL: "https://chatastrophe-draft.firebaseio.com",
        projectId: "chatastrophe-draft",
        storageBucket: "chatastrophe-draft.appspot.com",
        messagingSenderId: window.messagingSenderId
      };
      window.firebase = firebase;
      firebase.initializeApp(config);
    </script>
  </body>
</html>

应用安装横幅和你

能够添加到主屏幕是很好的功能,但是我们的用户如何知道我们的应用是可安装的,特别是如果他们从未听说过 PWAs?

进入Web App 安装横幅。以前,应用安装横幅是宣传本机应用的便捷方式——请参见 Flipboard 中的以下示例:

然而,现在,谷歌在 PWA 安装横幅上领先,促使用户添加到主屏幕。请参见 Chrome 开发者峰会网站上的以下示例:

此横幅的优点是让您的用户知道您的站点是 PWA,对于那些不熟悉可安装 web 应用的用户,它提供了进入 PWA 世界的入口点。

以下是您在上一个屏幕截图中单击“添加”时主屏幕上的显示:

然而,与本节中的所有内容一样,这是一项新技术。到目前为止,Android 上的 Chrome 浏览器和 Android 上的 Opera 浏览器都只提供了坚定的支持。此外,安装横幅何时出现在两种浏览器上有明确的标准:

  • 应用必须具有 web 应用清单
  • 应用必须通过 HTTPS 提供
  • 应用必须使用服务工作器
  • 应用必须访问两次,两次访问之间至少间隔五分钟

我们已经介绍了前三个(Firebase 应用通过 HTTPS 自动部署)。最后一个标准是尽量减少用户的烦恼。

延迟应用安装横幅

The following section is only applicable if you have an Android device to test on, with the latest version of Chrome or Opera for Android. You'll also need to set up Remote Debugging for your Android device, following the guide at https://developers.google.com/web/tools/chrome-devtools/remote-debugging/.

我们前面提到的 PWAs 的优点之一是,用户在决定是否安装之前有机会与您的应用进行交互。如果 Web 应用安装横幅显示得太早(在用户与您的应用进行积极交互之前),则可能会中断该过程。

在本节中,我们将通过延迟 web 应用安装横幅事件来找到解决方法,直到用户与我们的应用进行了积极的交互。

我们将在App.js中添加一个事件侦听器,以侦听横幅显示事件何时准备触发。然后,我们将截获该事件,并将其保存以备用户发送消息时使用。

倾听事件

Chrome 在显示 web 应用安装横幅之前直接发出beforeinstallprompt事件。这是我们将要听到的事件。像我们其他的 Firebase 事件侦听器一样,让我们将此添加到我们的App.js``componentDidMount

我们将创建一个名为listenForInstallBanner的方法,然后从componentDidMount中调用该方法:

componentDidMount() {
  firebase.auth().onAuthStateChanged(user => {
    if (user) {
      this.setState({ user });
    } else {
      this.props.history.push('/login');
    }
  });
  firebase
    .database()
    .ref('/messages')
    .on('value', snapshot => {
      this.onMessage(snapshot);
      if (!this.state.messagesLoaded) {
        this.setState({ messagesLoaded: true });
      }
    });
  this.listenForInstallBanner();
}
listenForInstallBanner = () => {

};

listenForInstallBanner中,我们将做两件事:

  1. 注册事件的侦听器。
  2. 当该事件激发时,请取消该事件并将其存储以供以后使用。

存储它以备以后使用意味着我们可以随时触发它,也就是当用户发送第一条消息时。

下面是代码的样子:

listenForInstallBanner = () => {
  window.addEventListener('beforeinstallprompt', (e) => {
    console.log('beforeinstallprompt Event fired');
    e.preventDefault();
    // Stash the event so it can be triggered later.
    this.deferredPrompt = e;
  });
};

我们正在将我们的deferredPrompt存储在App实例上,以便稍后获取它。我们将这样做,而不是我们的handleSubmitMessage方法:

handleSubmitMessage = msg => {
  const data = {
    msg,
    author: this.state.user.email,
    user_id: this.state.user.uid,
    timestamp: Date.now()
  };
  firebase
    .database()
    .ref('messages/')
    .push(data);
  if (this.deferredPrompt) {
 this.deferredPrompt.prompt();
 this.deferredPrompt.userChoice.then(choice => {
 console.log(choice);
 });
 this.deferredPrompt = null;
 }
};

提交消息后,我们将触发保存的事件。然后,我们注销用户选择(无论他们是否真的安装了应用,我们也可以将其发送到我们将来选择使用的任何分析)。最后,我们删除事件。

好的,让我们测试一下!

将 Android 设备插入计算机,并在 DevTools 上打开远程调试。我们必须首先部署我们的应用,所以点击yarn deploy并等待它完成。然后,在设备上打开应用并键入消息;你应该会看到应用安装横幅弹出。

如果没有显示,请检查代码,或者转到 DevTools 的“应用”选项卡并单击“添加到主屏幕”按钮。这将触发beforeinstallprompt事件。

总结

Web 应用安装横幅仍然是一项新技术,标准处于不断变化的状态。有关最新信息,请查阅谷歌网页上的 web 应用安装横幅--https://developers.google.com/web/fundamentals/engage-and-retain/app-install-banners/ 。也就是说,我希望这一章有助于阐明横幅的可能性,以及当前的技术状态。

现在,我们已经使我们的应用变得更大、更好,是时候减肥了,并且只关注性能了。下一章见!