使用 Content Indexing API 将支持离线访问的网页编入索引

使 Service Worker 可以告知浏览器哪些网页可离线工作

什么是 Content Indexing API?

使用渐进式 Web 应用意味着 人们所关心的信息(如图片、视频、文章等) 网络连接的当前状态Service Worker 等技术, Cache Storage API, 和 IndexedDB 为您提供所需的基本功能,以便在需要访问相关数据时 与 PWA 直接交互。但是,构建高质量、离线优先的 PWA 只是故事的一部分。如果用户没有意识到 在离线状态下可用,无法充分利用 将精力放在实现该功能上。

这是一个发现问题;PWA 如何让用户知道 支持离线操作的内容,让他们能够发现和查看有哪些内容?通过 Content Indexing API 可以解决这个问题。面向开发者的部分 是对 Service Worker 的扩展, 将支持离线功能的网页的网址和元数据添加到 。Chrome 84 及更高版本提供该增强功能。

当索引填充了来自 PWA 以及其他 安装 PWA,浏览器将显示如下所示的信息。

<ph type="x-smartling-placeholder">
</ph> Chrome 新标签页上“下载内容”菜单项的屏幕截图。 <ph type="x-smartling-placeholder">
</ph> 首先,在 Chrome 新标签页上选择下载内容菜单项。
<ph type="x-smartling-placeholder">
</ph> 已添加到索引中的媒体和文章。
已添加到索引中的媒体和文章会显示在 为您推荐的文章部分。

此外,如果 Chrome 检测到 用户处于离线状态。

Content Indexing API 不是缓存内容的替代方式。时间是 用于提供已由您的服务缓存的页面的元数据 这样,当用户想要访问某网页时 查看权限。Content Indexing API 有助于发现以下内容: 缓存的网页。

查看实际案例

了解 Content Indexing API 的最佳方法是尝试使用示例 应用。

  1. 确保您使用的是受支持的浏览器和平台。目前, (仅限 Android 设备上的 Chrome 84 或更高版本)。前往 about://version 查看 您运行的 Chrome 版本。
  2. 访问 https://contentindex.dev
  3. 点击列表中一个或多个商品旁边的 + 按钮。
  4. (可选)停用设备的 WLAN 和移动数据网络连接,或启用 飞行模式,以模拟浏览器离线。
  5. 从 Chrome 菜单中选择下载内容,然后切换到为您推荐的文章标签页。
  6. 浏览您之前保存的内容。

您可以在 GitHub 上查看示例应用的源代码

另一个示例应用是 Scrapbook PWA。 展示了如何将 Content Indexing API 与 Web Share Target API 搭配使用。代码演示了一种技术 使 Content Indexing API 与 Web 应用存储的内容保持同步 使用Cache Storage API

使用此 API

如需使用 API,您的应用必须具有 Service Worker 和可导航的网址 离线使用。如果您的 Web 应用目前没有 Service Worker,Workbox 库可以简化 正在创建

哪些类型的网址可以作为离线功能编入索引?

该 API 支持将与 HTML 文档对应的网址编入索引。缓存内容的网址 无法直接编入索引。相反,您需要提供 显示媒体的网页的网址,可离线工作。

推荐的模式是创建一个“查看器”可接受 作为查询参数,然后将媒体网址的内容 文件,此类文件可能会包含网页上的其他控件或内容。

Web 应用只能向位于 范围 当前 Service Worker 的父对象。也就是说,Web 应用无法添加网址 完全不同的域包含在内容索引中。

概览

Content Indexing API 支持三种操作:添加、列出和 移除元数据。这些方法通过新属性 index 公开, 已添加到 ServiceWorkerRegistration 界面。

要将内容编入索引,第一步就是获取对当前 ServiceWorkerRegistration。使用 navigator.serviceWorker.ready 是最简单的方法:

const registration = await navigator.serviceWorker.ready;

// Remember to feature-detect before using the API:
if ('index' in registration) {
  // Your Content Indexing API code goes here!
}

如果您在 Service Worker 中调用 Content Indexing API, 而不是在网页中,而是可以参考ServiceWorkerRegistration 直接通过 registration 发送。系统将对它进行定义 作为ServiceWorkerGlobalScope.的一部分

添加到索引

使用 add() 方法将网址及其关联的元数据编入索引。上限为 您可以选择何时将项添加到索引中。您可能需要将 为响应输入而创建索引,例如点击“离线保存”按钮。或者您 每次通过一种机制更新缓存数据时,可能自动添加商品 例如定期后台同步

await registration.index.add({
  // Required; set to something unique within your web app.
  id: 'article-123',

  // Required; url needs to be an offline-capable HTML page.
  url: '/articles/123',

  // Required; used in user-visible lists of content.
  title: 'Article title',

  // Required; used in user-visible lists of content.
  description: 'Amazing article about things!',

  // Required; used in user-visible lists of content.
  icons: [{
    src: '/img/article-123.png',
    sizes: '64x64',
    type: 'image/png',
  }],

  // Optional; valid categories are currently:
  // 'homepage', 'article', 'video', 'audio', or '' (default).
  category: 'article',
});

添加条目只会影响内容索引;并不会向 cache

极端情况:如果图标依赖于 fetch 处理程序,请从 window 上下文调用 add()

当您呼叫 add() 时,Chrome 会向 每个图标的网址,以确保它拥有图标的副本,以便在 显示已编入索引内容的列表。

  • 如果您从 window 上下文(换句话说,从您的网页中)调用 add() 页面),此请求将在您的 Service Worker 上触发 fetch 事件。

  • 如果您在 Service Worker 中(可能在另一个事件内)调用 add() 处理程序时,请求不会触发 Service Worker 的 fetch 处理程序。 系统将直接提取这些图标,无需任何 Service Worker 参与。保留 如果您的图标依赖于 fetch 处理程序,请谨记这一点,这可能是因为 仅存在于本地缓存中,而不存在于网络中。如果有,请确保 您只能从 window 上下文调用 add()

列出索引的内容

getAll() 方法会针对索引条目的可迭代列表返回一个 promise 及其元数据返回的条目将包含 add()

const entries = await registration.index.getAll();
for (const entry of entries) {
  // entry.id, entry.launchUrl, etc. are all exposed.
}

从索引中移除项

如需从索引中移除某个项,请使用该项的 id 调用 delete(), 移除:

await registration.index.delete('article-123');

调用 delete() 只会影响索引,它不会从 cache

处理用户删除事件

当浏览器显示已编入索引的内容时,其中可能包含自己的用户 界面,其中包含 Delete 菜单项,让用户有机会表示 便可继续观看之前已编入索引的内容删除过程就是这样 Chrome 80 中的界面外观:

删除菜单项。

当有人选择该菜单项时,您的 Web 应用的 Service Worker 将收到 contentdelete 事件。虽然处理此事件是可选的, Service Worker 进行“清理”的机会内容,例如本地缓存的媒体 有人表示已处理完毕的文件。

您无需在registration.index.delete() contentdelete 处理程序;如果事件已被触发,则相关索引 删除操作。

self.addEventListener('contentdelete', (event) => {
  // event.id will correspond to the id value used
  // when the indexed content was added.
  // Use that value to determine what content, if any,
  // to delete from wherever your app stores it—usually
  // the Cache Storage API or perhaps IndexedDB.
});

有关 API 设计的反馈

API 是否存在尴尬或无法按预期运行的地方?或 是否有遗漏的环节需要你付诸实施?

Content Indexing API 说明文档 GitHub 代码库中提交问题,或添加您的想法 现有问题。

实施时遇到问题?

您在 Chrome 的实现过程中是否发现了错误?

访问 https://new.crbug.com 提交 bug。尽可能多包含 并提供简单的重现说明,并设置组件 发送至 Blink>ContentIndexing

打算使用该 API?

打算在您的 Web 应用中使用 Content Indexing API?你的公开支持 帮助 Chrome 优先处理各项功能,并向其他浏览器供应商展示该功能的重要性 为他们提供支持

内容索引编制对安全性和隐私权有哪些影响?

查看相关解答 根据 W3C 的安全和隐私调查问卷提供的内容。如果您 如果您还有其他问题,请通过项目的 GitHub 代码库发起讨论。

主打图片:Maksym Kaharlytskyi 拍摄于 Un 直达游戏。