更新代码

与其他问题无关的更新

这是三个部分中的第一部分,用于说明非扩展 Service Worker 的代码需要进行的更改。此部分用于说明与其他问题无关的必需代码更改。接下来的两个部分将介绍如何替换阻塞的网络请求和提升安全性。

将 tabs.executeScript() 替换为 scripting.executeScript()

在 Manifest V3 中,executeScript() 从 tabs API 移至 scripting API。这不仅需要更改实际代码,还需要更改清单文件中的权限。

对于 executeScript() 方法,您需要:

  • "scripting" 权限。
  • 主机权限或 "activeTab" 权限。

scripting.executeScript() 方法与 tabs.executeScript() 的工作方式类似。不过,两者之间还是存在一些差异。

  • 旧方法只能接受单个文件,而新方法可以接受文件数组。
  • 您还需要传递 ScriptInjection 对象,而不是 InjectDetails。两者之间存在多项差异。例如,tabId 现在作为 ScriptInjection.target 的成员传递,而不是作为方法实参传递。

该示例展示了如何执行此操作。

Manifest V2
async function getCurrentTab() {/* ... */}
let tab = await getCurrentTab();

browser.tabs.executeScript(
  tab.id,
  {
    file: 'content-script.js'
  }
);

在后台脚本文件中。

Manifest V3
async function getCurrentTab()
let tab = await getCurrentTab();

browser.scripting.executeScript({
  target: {tabId: tab.id},
  files: ['content-script.js']
});

在扩展 Service Worker 中。

将 tabs.insertCSS() 和 tabs.removeCSS() 替换为 scripting.insertCSS() 和 scripting.removeCSS()

在 Manifest V3 中,insertCSS() 和 removeCSS() 从 tabs API 移至 scripting API。除了代码更改之外,还需要更改清单文件中的权限:

  • "scripting" 权限。
  • 主机权限或 "activeTab" 权限。

scripting API 上的函数与 tabs 上的函数类似。不过,两者之间还是存在一些差异。

  • 调用这些方法时,您需要传递 CSSInjection 对象,而不是 InjectDetails。
  • 现在,tabId 作为 CSSInjection.target 的成员传递,而不是作为方法实参传递。

该示例展示了如何针对 insertCSS() 执行此操作。removeCSS() 的流程相同。

Manifest V2
browser.tabs.insertCSS(tabId, injectDetails, () => {
  // callback code
});

在后台脚本文件中。

Manifest V3
const insertPromise = await browser.scripting.insertCSS({
  files: ["style.css"],
  target: { tabId: tab.id }
});
// Remaining code. 

在扩展 Service Worker 中。

将浏览器操作和网页操作替换为操作

在 Manifest V2 中,浏览器操作和网页操作是不同的概念。虽然它们最初的角色各不相同,但随着时间的推移,它们之间的差异逐渐缩小。在 Manifest V3 中,这些概念已整合到 Action API 中。这需要在 manifest.json 和扩展程序代码中进行更改,而这些更改与您在 Manifest V2 后台脚本中放置的内容不同。

Manifest V3 中的操作最类似于浏览器操作;不过,action API 不像 pageAction 那样提供 hide() 和 show()。如果您仍然需要网页操作,可以使用声明性内容来模拟这些操作,也可以使用标签页 ID 调用 enable() 或 disable()。

将“browser_action”和“page_action”替换为“action”

在 manifest.json 中,将 "browser_action" 和 "page_action" 字段替换为 "action" 字段。如需了解 "action" 字段的相关信息,请参阅参考文档。

Manifest V2
{
  ...
  "page_action": { ... },
  "browser_action": {
    "default_popup": "popup.html"
   }
  ...
}
Manifest V3
{
  ...
  "action": {
    "default_popup": "popup.html"
  }

  ...
}

将 browserAction 和 pageAction API 替换为 action API

如果您的 Manifest V2 使用了 browserAction 和 pageAction API,现在应使用 action API。

Manifest V2
browser.browserAction.onClicked.addListener(tab => { ... });
browser.pageAction.onClicked.addListener(tab => { ... });
Manifest V3
browser.action.onClicked.addListener(tab => { ... });

用 Promise 替换回调

在 Manifest V3 中,许多扩展程序 API 方法都会返回 promise。Promise 是异步方法返回的值的代理或占位符。如果您从未用过 Promise,可以在 MDN 上了解相关信息。本页介绍了在 Chrome 扩展程序中使用这些 API 时需要了解的事项。

为了实现向后兼容性,在添加 promise 支持后,许多方法仍继续支持回调。请注意,您无法在同一函数调用中同时使用这两个参数。如果您传递回调,该函数将不会返回 promise;如果您希望返回 promise,请勿传递回调。某些 API 功能(例如事件监听器)仍需要回调。如需检查方法是否支持 promise,请在其 API 参考文档 中查找“promise”标签。

如需从回调转换为 promise,请移除回调并处理返回的 promise。以下示例摘自可选权限示例,具体来说是 newtab.js。回调版本展示了示例对 request() 的调用在添加回调后的样子。请注意,Promise 版本可以使用 async 和 await 进行重写。

回拨电话
browser.permissions.request(newPerms, (granted) => {
  if (granted) {
    console.log('granted');
  } else {
    console.log('not granted');
  }
});
Promise
const newPerms = { permissions: ['topSites'] };
browser.permissions.request(newPerms)
.then((granted) => {
  if (granted) {
    console.log('granted');
  } else {
    console.log('not granted');
  }
});

替换需要 Manifest V2 后台上下文的函数

其他扩展程序上下文只能使用消息传递与扩展程序服务工作器进行交互。因此,您需要替换预期使用后台上下文的调用,具体如下:

  • browser.runtime.getBackgroundPage()
  • browser.extension.getBackgroundPage()
  • browser.extension.getExtensionTabs()

扩展程序脚本应使用消息传递在 service worker 和扩展程序的其他部分之间进行通信。目前,您可以使用 sendMessage() 并在扩展 Service Worker 中实现 browser.runtime.onMessage 来完成此操作。从长远来看,您应该计划将这些调用替换为 postMessage() 和 Service Worker 的 message 事件处理脚本。

替换不受支持的 API

以下列出的方法和属性需要在 Manifest V3 中进行更改。

Manifest V2 方法或属性 替换为
browser.extension.connect() browser.runtime.connect()
browser.extension.connectNative() browser.runtime.connectNative()
browser.extension.getExtensionTabs() browser.extension.getViews()
browser.extension.getURL() browser.runtime.getURL()
browser.extension.lastError 如果方法返回 promise,请使用 promise.catch()
browser.extension.onConnect browser.runtime.onConnect
browser.extension.onConnectExternal browser.runtime.onConnectExternal
browser.extension.onMessage browser.runtime.onMessage
browser.extension.onRequest browser.runtime.onMessage
browser.extension.onRequestExternal browser.runtime.onMessageExternal
browser.extension.sendMessage() browser.runtime.sendMessage()
browser.extension.sendNativeMessage() browser.runtime.sendNativeMessage()
browser.extension.sendRequest() browser.runtime.sendMessage()
browser.runtime.onSuspend(后台脚本) 扩展程序服务工作线程不支持此功能。请改用 beforeunload 文档事件。
browser.tabs.getAllInWindow() browser.tabs.query()
browser.tabs.getSelected() browser.tabs.query()
browser.tabs.onActiveChanged browser.tabs.onActivated
browser.tabs.onHighlightChanged browser.tabs.onHighlighted
browser.tabs.onSelectionChanged browser.tabs.onActivated
browser.tabs.sendRequest() browser.runtime.sendMessage()
browser.tabs.Tab.selected browser.tabs.Tab.highlighted