您已发布了 PWA:一些用户通过浏览器使用它,另一些用户将其安装在设备上。当您更新应用时,务必应用最佳实践来避免陷阱。
您可能会更新
- 应用数据。
- 设备中已缓存的资源。
- Service Worker 文件或其依赖项。
- 清单元数据。
让我们来看看这些元素的最佳实践。
更新数据
要更新数据(例如存储在 IndexedDB 中的数据),您可以使用 Fetch、WebRTC 或 WebSockets API 等工具。如果您的应用支持任何离线功能,请记住也要保持支持这些功能的数据处于最新状态。
在兼容的浏览器上,有多种选项可以同步数据,不仅在用户打开 PWA 时同步,而且还可以在后台同步。这些选项包括
- 后台同步:保存失败的请求,并使用来自 Service Worker 的同步重试这些请求。
- Web 定期后台同步:在后台按特定时间定期同步数据,即使在用户尚未打开应用的情况下,也允许应用提供更新的数据。
- 后台 Fetch:下载大型文件,即使 PWA 已关闭。
- Web Push:从服务器发送消息,唤醒 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 将处于等待状态,如 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());
});
当控制当前页面的 Service Worker 发生更改时,会触发 controllerchange
事件。例如,新的 Worker 已跳过等待并成为新的活动 Worker。
navigator.serviceWorker.addEventListener("controllerchange", event => {
// The service worker controller has changed
});
更新元数据
您还可以更新应用元数据,这些元数据主要在 Web 应用清单中设置。例如,更新其图标、名称或启动 URL,或者您可以添加新功能,例如应用快捷方式。但是,对于所有已在其设备上安装了带有旧图标的应用的用户,会发生什么情况?他们如何以及何时获得更新的版本?
答案取决于平台。让我们介绍一下可用的选项。
iOS、iPadOS 和 Android 浏览器上的 Safari 浏览器
在这些平台上,获取新清单元数据的唯一方法是从浏览器重新安装应用。
Android 上带有 WebAPK 的 Google Chrome 浏览器
当用户在 Android 上使用已激活 WebAPK 的 Google Chrome 浏览器安装您的 PWA 时(大多数 Chrome PWA 安装都是这种情况),更新将根据算法进行检测和应用。请查看此清单更新文章中的详细信息。
关于此过程的一些其他说明
如果用户未打开您的 PWA,则其 WebAPK 不会被更新。如果服务器未响应清单文件(出现 404 错误),则 Chrome 将至少 30 天内不检查更新,即使用户打开了 PWA 也是如此。
转到 Android 版 Chrome 浏览器中的 about:webapks
以查看“需要更新”标志的状态,并请求更新。在《工具和调试》章节中,您可以阅读有关此调试工具的更多信息。
Android 上带有 WebAPK 的 Samsung Internet 浏览器
该过程与 Chrome 版本类似。在这种情况下,如果 PWA 清单需要更新,则在接下来的 24 小时内,WebAPK 将在通过 Wi-Fi 在铸造更新后的 WebAPK 后进行更新。
桌面设备上的 Google Chrome 和 Microsoft Edge 浏览器
在桌面设备上,当 PWA 启动时,浏览器会确定上次检查本地清单以查找更改的时间。如果自浏览器上次启动以来清单尚未审核,或者在过去 24 小时内未检查过,则浏览器将对清单发出网络请求,然后将其与本地副本进行比较。
当选定的属性更新时,将在所有窗口关闭后触发更新。
提醒用户
某些更新策略需要客户端重新加载或进行新的导航。您需要让用户知道有更新正在等待,但让他们有机会在最适合他们的时候更新页面。
要通知用户,有以下选项
- 使用 DOM 或 Canvas API 在屏幕上呈现通知。
- 使用 Web Notifications API。此 API 是推送权限的一部分,用于在操作系统中生成通知。即使您不使用来自服务器的推送消息协议,也需要请求 Web Push 权限才能使用它。如果 PWA 未打开,这是我们唯一的选择。
- 使用 Badging API 显示 PWA 的已安装图标中是否有可用更新
.
有关 Badging API 的更多信息
Badging API 允许您在兼容的浏览器上用徽章编号或徽章点标记 PWA 的图标。徽章点是已安装图标中的一个微小标记,表示应用内部有内容正在等待。
您需要在 navigator
对象上调用 setAppBadge(count)
以设置徽章编号。当您知道有更新要提醒用户时,可以从窗口或 Service Worker 的上下文中执行此操作。
let unreadCount = 125;
navigator.setAppBadge(unreadCount);
要清除徽章,您需要在同一对象上调用 clearAppBadge()
navigator.clearAppBadge();