使用 Service Worker 管理通知

Kate Jeffreys
Kate Jeffreys

在此 Codelab 中,您将使用 Service Worker 以管理通知。 此处的说明假定您已熟悉 以及请求通知权限和发送通知的基础知识。 如果您需要回顾一下通知,请参阅 Notifications API 使用入门 Codelab。如需详细了解 Service Worker,请参阅 Matt Gaunt 的 Service Worker 简介

重新合成示例应用并在新标签页中查看

系统会自动屏蔽嵌入式 Glitch 应用的通知,因此您无法在此页面上预览该应用。此时,您需要执行以下操作:

  1. 点击 Remix to Edit 以使项目可修改。
  2. 如需预览网站,请按查看应用。然后按 全屏 全屏

系统应该会在新的 Chrome 标签页中打开 Glitch。

在学习此 Codelab 时,请更改此页面上嵌入式 Glitch 中的代码。使用已发布的应用刷新新标签页以查看更改。

熟悉示例应用和起始代码

首先,在新 Chrome 标签页中查看正在运行的应用:

  1. 按 `Ctrl+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
  2. 点击控制台标签页。

  3. 确保在级别下拉菜单中选择信息选项 (位于过滤条件框旁边)。

  4. 在实时应用的开发者工具控制台中,您应该会看到以下控制台消息:

    TODO: Implement getRegistration()

    这是来自您将在此 Codelab 中实现的函数桩的消息。

现在,我们来看看本页嵌入式 Glitch 中的示例应用代码。

  1. 在嵌入式 Glitch 中,查看 public/index.js

    • 您将实现的函数有四个存根:registerServiceWorkergetRegistrationunRegisterServiceWorkersendNotification

    • requestPermission 函数会请求用户授予发送通知的权限。如果您学习了开始使用 Notifications API 的 Codelab,就会注意到此处使用了其 requestPermission 函数。唯一的区别是,现在还会在解析权限请求后更新界面。

    • updateUI 函数可刷新应用的所有按钮和消息。

    • initializePage 函数在浏览器中针对 Service Worker 功能执行功能检测,并更新应用界面。

    • 脚本将等待页面加载,然后初始化页面。

  2. 在嵌入式 Glitch 中,打开 public/service-worker.js

    顾名思义,您需要向应用添加代码,以便将此文件注册为 Service Worker

    尽管该文件尚未被应用使用,但它包含一些起始代码,这些代码将在激活 Service Worker 时向控制台输出消息。

    您将向 public/service-worker.js 添加代码,以便在 Service Worker 收到通知时处理通知。

注册 Service Worker

在此步骤中,您将编写可运行 当用户点击应用界面中的 Register Service Worker 时触发。 此代码会将 public/service-worker.js 注册为 Service Worker。

  1. 在嵌入式 Glitch 编辑器中,打开 public/index.js。 将 registerServiceWorker 函数替换为以下代码:

    // Use the Service Worker API to register a service worker.
    async function registerServiceWorker() {
      await navigator.serviceWorker.register('./service-worker.js')
      updateUI();
    }
    

    请注意,registerServiceWorker 使用 async function 声明,以便更加方便地处理 promise。这样,您就可以 await 处理 Promise 的解析值。例如,在更新界面之前,上述函数会等待注册 Service Worker 的结果。如需了解详情,请参阅 MDN 上的 await

  2. 现在,用户可以注册 Service Worker,您可以获取对 Service Worker 注册对象的引用。在 public/index.js 中,将 getRegistration 函数替换为以下代码:

    // Get the current service worker registration.
    function getRegistration() {
      return navigator.serviceWorker.getRegistration();
    }
    

    上面的函数使用 Service Worker API 来获取当前的 Service Worker 注册(如果存在)。 它会更方便地获取对 Service Worker 注册的引用。

  • 要完成 Service Worker 注册功能,请添加用于取消注册 Service Worker 的代码。将 unRegisterServiceWorker 函数替换为以下代码:

    // Unregister a service worker, then update the UI.
    async function unRegisterServiceWorker() {
      // Get a reference to the service worker registration.
      let registration = await getRegistration();
      // Await the outcome of the unregistration attempt
      // so that the UI update is not superceded by a
      // returning Promise.
      await registration.unregister();
      updateUI();
    }
    

在您当前查看应用的标签页中,重新加载页面。Register Service WorkerUnregister Service Worker 按钮现在应该可以正常使用了。

向 Service Worker 发送通知

在此步骤中,您将编写相应代码,当用户点击应用界面中的发送通知时,这些代码将会运行。这段代码将创建一个通知,检查 Service Worker 是否已注册,然后使用其 postMessage 方法将该通知发送到 Service Worker。

在嵌入式 Glitch 编辑器中,打开 public/index.js 并 将 sendNotification 函数替换为以下代码:

// Create and send a test notification to the service worker.
async function sendNotification() {
  // Use a random number as part of the notification data
  // (so you can tell the notifications apart during testing!)
  let randy = Math.floor(Math.random() * 100);
  let notification = {
    title: 'Test ' + randy,
    options: { body: 'Test body ' + randy }
  };
  // Get a reference to the service worker registration.
  let registration = await getRegistration();
  // Check that the service worker registration exists.
  if (registration) {
    // Check that a service worker controller exists before
    // trying to access the postMessage method.
    if (navigator.serviceWorker.controller) {
      navigator.serviceWorker.controller.postMessage(notification);
    } else {
      console.log('No service worker controller found. Try a soft reload.');
    }
  }
}

该代码的作用如下:

  • sendNotification 是一个异步函数,因此您可以使用 await 获取对 Service Worker 注册的引用。

  • Service Worker 的 postMessage 方法将数据从应用发送到 Service Worker。如需了解详情,请参阅有关 postMessage 的 MDN 文档

  • 该代码在尝试访问 postMessage 函数之前,会检查是否存在 navigator.serviceWorker.controller 属性。如果没有活跃的 Service Worker,或者页面已被强制刷新(Shift+重新加载),则 navigator.serviceWorker.controller 将为 null。如需了解详情,请参阅关于 MDN 的 ServiceWorker 控制器文档

在 Service Worker 中处理通知

在此步骤中,您将在 Service Worker 中编写代码,用于处理发布到 Service 的消息并向用户显示通知。

在嵌入式 Glitch 编辑器中,打开 public/service-worker.js。将以下代码添加到文件末尾:

// Show notification when received
self.addEventListener('message', (event) => {
  let notification = event.data;
  self.registration.showNotification(
    notification.title,
    notification.options
  ).catch((error) => {
    console.log(error);
  });
});

以下是快速说明:

  • self 是对 Service Worker 本身的引用。

  • 尽管 Service Worker 现在负责显示通知,但主应用界面仍负责从用户那里获取通知权限。如果未授予权限,showNotification 返回的 promise 会被拒绝。上面的代码使用 catch 块来避免未捕获的 Promise 拒绝错误,并更加妥善地处理此错误。

如果您遇到困难,请参阅 glitch.com/edit/#!/codelab-notifications-service-worker-completed,获取已完成的代码。

继续学习本系列中的下一个 Codelab:构建推送通知服务器