Manifest V3 中的扩展程序操作

Simeon Vincent
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 中,我们使用了 declarativeContent.ShowAction,而不是 Manifest V2 中的 declarativeContent.ShowPageAction

最后,内容拦截器可以使用 declarativeNetRequest API 的 setExtensionActionOptions 方法显示扩展程序针对给定标签页拦截的请求数量。此功能非常重要,因为它可让内容拦截器让最终用户了解相关信息,而不会将可能敏感的浏览元数据暴露给扩展程序。

小结

对 Chrome 扩展程序平台进行现代化改造是我们开发 Manifest V3 的主要动机之一。在许多情况下,这意味着改用新技术,但也意味着简化 API 接口;这是我们在这里的目标。

希望这篇帖子能帮助大家了解 Manifest V3 平台的这一特定方面。如需详细了解 Chrome 团队如何打造浏览器扩展程序的未来,请参阅我们的开发者文档中的平台愿景Manifest V3 概览页面。您还可以在 chromium-extensions Google 群组上与其他开发者讨论 Chrome 扩展程序。