更新程式碼

與其他問題無關的更新

本節是三個章節中的第一個,說明擴充功能 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 是非同步方法傳回值的 Proxy 或預留位置。如果您從未使用過 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 背景情境的函式

其他擴充功能情境只能使用訊息傳遞與擴充功能 Service Worker 互動。因此,您需要取代預期背景內容的呼叫,具體來說:

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

擴充功能指令碼應使用訊息傳遞,在 Service Worker 和擴充功能的其他部分之間進行通訊。目前,您可以透過 sendMessage() 達成這項操作,並在擴充功能 Service Worker 中實作 browser.runtime.onMessage。長期而言,您應規劃將這些呼叫替換為 postMessage() 和 Service Worker 的訊息事件處理常式。

替換不支援的 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 (背景指令碼) 不支援擴充功能 Service Worker。請改用 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