Manifest V3 中的扩展程序操作

西蒙·文森特
Simeon Vincent

自 Chrome 扩展程序推出以来,该平台允许开发者使用操作直接在顶层 Chrome 界面中提供扩展程序功能。操作就是一个图标按钮,可以打开弹出式窗口或触发扩展程序中的某些功能。过去,Chrome 支持两种类型的操作:浏览器操作和网页操作;Manifest V3 通过将操作功能整合到新的 chrome.action API 中改变了这一点。

扩展程序操作的简短历史记录

虽然 chrome.action 本身是 Manifest V3 中的新增功能,但它提供的基本功能可以追溯到 2010 年 1 月扩展程序首次发布稳定版之时。Chrome 扩展程序平台的第一个稳定版本支持两种不同类型的操作:浏览器操作网页操作

借助浏览器操作,扩展程序开发者可以在“Google Chrome 主工具栏中的地址栏右侧”显示一个图标(来源),并为用户提供一种简单的方法,让他们能够在任何页面上触发扩展程序功能。另一方面,网页操作旨在“表示可在当前网页上执行,但并非适用于所有网页的操作”(来源)。

多功能框中会显示网页操作(左侧),表示该扩展程序可以在此页面上执行某些操作。浏览器操作(右侧)始终可见。

换言之,浏览器操作为扩展程序开发者提供了浏览器中持久的界面界面,而页面操作仅在扩展程序可在当前页面上执行某些实用操作时才显示。

由于这两种操作都是可选的,因此扩展程序开发者可以选择提供不执行任何操作、网页操作或者提供浏览器操作(不允许指定多项操作)。

大约 6 年后,Chrome 49 为扩展程序引入了新的界面范式。为了帮助用户了解自己安装的扩展程序,Chrome 开始在多功能框右侧显示所有有效的扩展程序。用户可以根据需要将扩展程序“溢出”到 Chrome 菜单中。

隐藏的扩展程序图标会显示在 Chrome 菜单中。

为了为每个扩展程序显示一个图标,此次更新还针对扩展程序在 Chrome 界面中的行为方式做出了两项重要变更。首先,所有扩展程序都开始在工具栏中显示图标。如果扩展程序没有图标,Chrome 会自动为其生成一个图标。其次,页面操作与浏览器操作一起移到工具栏中,并提供一种方式来区分其“显示”和“隐藏”状态。

停用的页面操作(左)在工具栏中显示为灰度图片,而已启用的页面操作(右)以全彩色显示。

此更改让附加网页操作信息能够继续按预期运行,但网页操作的作用也随着时间的推移而逐渐减弱。重新设计界面所带来的影响之一是,页面操作确实被浏览器操作所取代。由于所有扩展程序都显示在工具栏中,用户希望点击扩展程序的工具栏图标会调用该扩展程序,因此浏览器操作已成为 Chrome 扩展程序越来越重要的互动。

Manifest V3 变更

2016 年扩展程序界面经过重新设计之后,Chrome 界面和扩展程序继续发展,但浏览器操作和网页操作基本保持不变。也就是说,至少直到我们开始规划如何使用 Manifest V3 对扩展程序平台进行现代化改造。

扩展程序团队很明显,浏览器操作和网页操作越来越像是毫无意义的区别。更糟糕的是,它们细微的行为差异导致开发者难以确定使用哪一个。我们意识到,通过将浏览器操作和网页操作合并为一项“操作”,可以解决这些问题。

输入 Action API;chrome.actionchrome.browserAction 最直接类似,但两者之间存在一些显著差异。

首先,chrome.action 引入了一个名为 getUserSettings() 的新方法。此方法使扩展程序开发者能够检查用户是否已将其扩展程序操作固定到工具栏。

let userSettings = await chrome.action.getUserSettings();
console.log(`Is the action pinned? ${userSettings.isOnToolbar ? 'Yes' : 'No'}.`);

与“isPinned”等相比,“getUserSettings”对于此功能而言似乎有点不寻常,但 Chrome 中的操作历史记录显示,浏览器界面的更改速度比扩展程序 API 更快。因此,我们使用此 API 的目标是在通用界面上公开与操作相关的用户偏好,以最大限度地减少未来 API 流失。此外,它还允许其他浏览器供应商在此方法返回的 UserSettings 对象中提供特定于浏览器的界面概念。

其次,可以使用声明式 Content API 控制相应扩展程序操作的图标和启用/停用状态。这一点非常重要,因为扩展程序可以让扩展程序对用户的浏览行为做出反应,而无需访问用户所访问的内容甚至网址。例如,我们来看看扩展程序如何在用户访问 example.com 上的网页时启用其操作。

// Manifest V3
chrome.runtime.onInstalled.addListener(() => {
  chrome.declarativeContent.onPageChanged.removeRules(undefined, () => {
    chrome.declarativeContent.onPageChanged.addRules([
      {
        conditions: [
          new chrome.declarativeContent.PageStateMatcher({
            pageUrl: {hostSuffix: '.example.com'},
          })
        ],
        actions: [new chrome.declarativeContent.ShowAction()]
      }
    ]);
  });
});

以上代码与扩展程序处理网页操作的代码几乎完全相同。唯一的区别在于,在 Manifest V3 中,我们在 Manifest V2 中使用了 declarativeContent.ShowAction,而非 declarativeContent.ShowPageAction

最后,内容拦截器可以使用 declarativeNetRequest API 的 setExtensionActionOptions 方法显示给定标签页上被扩展程序屏蔽的请求数量。此功能非常重要,因为它可以让内容拦截器告知最终用户,而无需将可能敏感的浏览元数据暴露给扩展程序。

小结

对 Chrome 扩展程序平台进行现代化改造是我们开发 Manifest V3 的主要原因之一。在许多情况下,这意味着切换到新技术,但也意味着简化我们的 API Surface;这正是我们的目标。

希望这篇帖子能够帮助您了解 Manifest V3 平台的具体一个方面。如需详细了解 Chrome 团队如何走向浏览器扩展程序的未来,请参阅开发者文档中的平台愿景Manifest V3 概览页面。您还可以与 chromium-extensions Google 网上论坛中的其他开发者讨论 Chrome 扩展程序。