更新

您已发布 PWA:一些用户通过浏览器使用该 PWA,其他用户则是在他们的设备上安装该 PWA。在更新应用时,请务必采用最佳实践,以避免出现问题。

您可以更新:

  • 应用数据。
  • 资源已缓存在设备中。
  • Service Worker 文件,或其依赖项。
  • 清单元数据。

我们来看一下每个元素的最佳做法。

更新数据

如需更新数据(例如存储在 IndexedDB 中的数据),您可以使用 Fetch、WebRTC 或 WebSockets API 等工具。如果您的应用支持任何离线功能,请务必也更新支持相应功能的数据。

在兼容的浏览器中,不仅有用户打开 PWA 时同步数据的选项,还有在后台同步数据的选项。这些选项包括:

  • 后台同步:保存失败的请求,并使用 Service Worker 中的同步重试这些请求。
  • 网络定期后台同步:在特定时间在后台定期同步数据,让应用能够提供更新后的数据,即使用户尚未打开应用也是如此。
  • 后台提取:下载大文件,即使在 PWA 关闭的情况下也可以。
  • Web 推送:从服务器发送一条消息,以唤醒 Service Worker 并通知用户。这通常称为“推送通知”。此 API 需要用户的许可。

所有这些 API 都是从 Service Worker 上下文执行的。此功能目前仅适用于基于 Chromium 的浏览器、Android 和桌面设备操作系统。使用这些 API 之一时,您可以在 Service Worker 线程中运行代码;例如,从服务器下载数据并更新 IndexedDB 数据。

正在更新资产

更新资产包括对用于呈现应用界面的文件(例如 HTML、CSS、JavaScript 和图片)所做的任何更改。例如,应用逻辑的更改、界面中的图片或 CSS 样式表。

更新模式

以下是一些处理应用更新的常见模式,但您随时可以根据自己的需求自定义该流程:

  • 完全更新:所有更改(即使是细微更改)都会触发替换整个缓存内容。此模式模拟了特定于设备的应用处理更新的方式,并且会占用更多带宽并花费更多时间。
  • 已更改资产更新:只有自上次更新以来发生更改的资产才会在缓存中替换。它通常使用 Workbox 等库实现。此过程涉及创建缓存文件列表、文件的哈希表示以及时间戳。有了此信息,Service Worker 便会将此列表与已缓存资产进行比较,并决定要更新的资产。
  • 单独更新:每项资产在发生变化时单独更新。“投放”章节中描述的“在重新验证策略时过时”就是单独更新素材资源的一个示例。

何时更新

另一个好的做法是找个好时机检查更新并应用更新。您可以做出如下选择:

  • Service Worker 唤醒时。此刻没有要监听的事件,但浏览器唤醒时,会执行 Service Worker 全局作用域内的任何代码。
  • 在 PWA 的主窗口上下文中,浏览器加载页面后,以免降低应用加载速度。
  • 触发后台事件时,例如 当 PWA 收到推送通知或触发后台同步时。然后,您可以更新缓存,您的用户将在下次打开应用时看到资源的新版本。

实时动态

您还可以选择在应用处于打开(已发布)或关闭状态时应用更新。采用应用关闭方法时,即使应用已下载新的资源,也不会做出任何更改,并在下次加载时使用新版本。

实时更新意味着,一旦资源在缓存中更新,PWA 便会替换当前加载中的资源。这是一项复杂的任务,本课程未涉及到它。一些工具可以帮助您实现此更新:livereload-js 和 CSS 素材资源更新 CSSStyleSheet.Replace() API

更新 Service Worker

当您的 Service Worker 或其依赖项发生变化时,浏览器会触发更新算法。浏览器通过将缓存文件和来自网络的资源进行逐字节比较来检测更新。

然后,浏览器尝试安装新版 Service Worker,新 Service Worker 将处于 waiting 状态,如 Service Worker 一章中所述。新安装操作会针对新 Service Worker 运行 install 事件。如果您在该事件处理脚本中缓存资源,那么也会重新缓存资源。

检测 Service Worker 的变化

为了检测新的 Service Worker 是否已就绪并安装,我们会使用 Service Worker 注册中的 updatefound 事件。当新的 Service Worker 开始安装时会触发此事件。我们需要等待 statechange 事件将其状态更改为 installed;请参阅以下内容:

async function detectSWUpdate() {
  const registration = await navigator.serviceWorker.ready;

  registration.addEventListener("updatefound", event => {
    const newSW = registration.installing;
    newSW.addEventListener("statechange", event => {
      if (newSW.state == "installed") {
         // New service worker is installed, but waiting activation
      }
    });
  })
}

强制覆盖

新的 Service Worker 将会安装,但默认情况下正在等待激活。等待时间可防止新 Service Worker 接管可能与新版本不兼容的旧客户端。

尽管不建议这样做,新 Service Worker 可以跳过该等待期并立即开始激活。

self.addEventListener("install", event => {
   // forces a service worker to activate immediately
   self.skipWaiting();
  });

self.addEventListener("activate", event => {
  // when this SW becomes activated, we claim all the opened clients
  // they can be standalone PWA windows or browser tabs
  event.waitUntil(clients.claim());
});

controllerchange 事件会在控制当前页面的 Service Worker 发生变更时触发。例如,新 Worker 已经跳过等待,成为新的活跃 Worker。

navigator.serviceWorker.addEventListener("controllerchange", event => {
   // The service worker controller has changed
 });

更新元数据

您还可以更新应用的元数据,这主要在 Web 应用清单中设置。例如,更新应用的图标、名称或启动网址,或者您可以添加应用快捷方式等新功能。 但是,如果用户已经在其设备上安装了带有旧图标的该应用,那么他们会怎样呢?他们如何以及何时获得更新版本?

答案取决于平台。下面我们来介绍可用的选项。

iOS、iPadOS 和 Android 浏览器上的 Safari

在这些平台上,获取新清单元数据的唯一方法是从浏览器重新安装应用。

Android 版 Google Chrome 浏览器(使用 WebAPK)

当用户在 Android 上使用 WebAPK 安装您的 PWA(大多数 Chrome PWA 安装时)时,系统会根据算法检测并应用更新。如需了解详情,请参阅这篇清单更新文章。

关于此流程的一些其他说明:

如果用户没有打开您的 PWA,其 WebAPK 也不会更新。 如果服务器未返回清单文件做出响应(出现 404 错误),则 Chrome 至少在 30 天内不会检查更新,即使用户打开 PWA 也是如此。

在 Android 设备上前往 Chrome 中的 about:webapks,查看“需要更新”标记的状态,然后请求更新。在工具和调试一章中,您可以详细了解此调试工具。

Android 版三星互联网(采用 WebAPK)

处理过程与 Chrome 版本类似。在这种情况下,如果 PWA 清单需要更新,在接下来的 24 小时内,系统会在创建更新后的 WebAPK 后通过 Wi-Fi 更新 WebAPK。

桌面版 Google Chrome 和 Microsoft Edge

在桌面设备上,当 PWA 启动时,浏览器会确定上次检查本地清单是否存在更改的时间。如果自浏览器上次启动以来未审核该清单,或者在过去 24 小时内未检查该清单,则浏览器将对该清单发出网络请求,然后将其与本地副本进行比较。

如果更新所选房源,所有窗口均关闭后会触发更新。

提醒用户

某些更新策略需要从客户端重新加载或执行新的导航。您需要告知用户有更新等待,但要让他们有机会在最适合自己的时间更新网页。

为了通知用户,可以使用以下选项:

  • 使用 DOM 或 canvas API 在屏幕上呈现通知。
  • 使用 Web Notifications API。此 API 是推送权限的一部分,用于在操作系统中生成通知。即使您不使用来自服务器的推送消息传递协议,也需要请求 Web 推送权限才能使用它。如果 PWA 未打开,这是我们唯一的选项。
  • 使用 Badging API 显示 PWA 的已安装图标中有可用更新

DOM 中显示的更新通知。.

详细了解 Badging API

利用 Badging API,您可以在兼容的浏览器上使用标记编号或标记圆点来标记 PWA 的图标。标记点是已安装图标内的一个小标记,表示应用中有内容正在等待。

示例:显示有八条通知的 Twitter 应用,以及显示旗帜类型标志的另一个应用。

您需要对 navigator 对象调用 setAppBadge(count) 来设置徽章编号。当您知道有更新要提醒用户时,可以从窗口或 Service Worker 的上下文中执行此操作。

let unreadCount = 125;
navigator.setAppBadge(unreadCount);

如需清除标记,请对同一对象调用 clearAppBadge()

navigator.clearAppBadge();

资源