Chrome瀏覽器擴展插件教程:從MV2遷移到Manifest V3

語言: CN / TW / HK

Chrome Web Store於2021年1月已經開始接受Manifest V3擴展的提交。如果你還在使用MV2版本,那麼一定要在官方棄用之前,儘快更新到MV3版本。

Chrome瀏覽器從88版本開始支持MV3啦(即Manifest Version 3),目前查看官方文檔時默認已經是MV3版本。

我們這篇文章主要了解3個問題

1、MV2的棄用時間表

2、瞭解MV3的新特性

3、如何將MV2遷移到MV3

一、Manifest V2棄用時間表

此圖表指定了棄用Manifest V2(MV2)的時間表

  • 2022年1月份開始不接受新的MV2版本(除了”私人”可見類型),開發者可以更新已經存在的MV2擴展插件
  • 2022年6月份不接受新的MV2版本,開發者可以更新已經存在的MV2擴展插件
  • 2023年1月份開始,開發者不能更新MV2的擴展插件,MV2也不能在Chrome瀏覽器運行(除了個別的企業版)
  • 2023年6月份MV2版本將不能在Chrome瀏覽器運行

二、Manifest V3新特性

Manifest V3是十年前推出擴展平台以來最大的轉變之一。Manifest V3的新的擴展規範將在安全性、私密性和性能方面得到增強;也可以使用Manifest V3中採用的更現代的開放網絡技術,比如Service Worker和Promises。並會逐步淘汰Manifest V2。

MV3新特性概要

declarativentrequest API

三、如何將MV2遷移到MV3

1、修改manifest.json

1)manifest.json版本號

顯而易見第一步需求修改 manifest.json 文件

{
    ...,
    "manifest_version": 3,
    ...
}

2)Host Permissions

在Manifest V2中,有兩種方法為你的api或任何主機獲得權限,要麼在 permissions 數組或 optional_permissions 數組。

在Manifest V3中,所有主機權限現在都單獨存在一個新數組中,該數組的鍵為 host_permissions 。主機權限不再與其他權限一起添加。

MV2

{
    ...,
    "permissions": [
        "http://tahub.app/*"
      ],
    ...
}

MV3

{
    ...,
    "host_permissions": [
        "http://tahub.app/*"
      ],
    ...
}

3)Background Scripts

Manifest V3用Service Worker替換了 background scripts。

MV2 Background對象目前看起來是這樣的:

{
    ...,
    "background": {
        "scripts": ["assets/js/background.js"],
        "persistent": false
      },
    ...
}

我們需要做的是把 script 數組的鍵改為 service_worker ,替換多個background pages或scripts。所以,它應該是這樣的:

{
    ...,
    "background": {
        "service_worker": "assets/js/background.js"
      },
    ...
}

注意,我們不再需要添加 persistent 了。

4)Actions

Actions 過去是 browser_actionpage_action ,但現在它們在Manifest V3中統一為 Actions 。這是因為隨着時間的推移,分開他們變得沒有必要。

MV2

// Manifest V2

// manifest.json
{
  "browser_action": { … },
  "page_action": { … }
}

// background.js
chrome.browserAction.onClicked.addListener(tab => { … });
chrome.pageAction.onClicked.addListener(tab => { … });

MV3

// Manifest V3

// manifest.json
{
  "action": { … }
}

// background.js
chrome.action.onClicked.addListener(tab => { … });

5)Content Security Policy (CSP)

你需要改變它從一個String(在Manifest V2)到一個Object(在Manifest v3)。

MV2

// Manifest V2

"content_security_policy": "..."

MV3

// Manifest V3

"content_security_policy": {
  "extension_pages": "...",
  "sandbox": "..."
}

6)Web-Accessible Resources

web_accessible_resources 數組更改為一個詳細描述所有資源的對象,每個對象都可以映射到到一組url或擴展id。下面是V3版本的一個例子:

MV2

// Manifest V2

"web_accessible_resources": [
  RESOURCE_PATHS
]

MV3

// Manifest V3

"web_accessible_resources": [{
  "resources": [RESOURCE_PATHS]
}]

此外還支持其它的屬性,用於設定不同的規則: matchesextension_idsuse_dynamic_url

2、將 Background Scripts 改造成 Service Workers

首先,什麼是service worker,它和background scripts有什麼不同?

background scripts在幾乎所有擴展中都是必不可少的。允許執行一些操作或執行代碼,而不需要用户打開某個頁面或執行某些操作。這可以用於發送通知、與content scripts通信等等。後台腳本通常總是在後台運行。

Service worker在需要的時候被執行。與後台腳本不同,它們並不總是在後台運行。在最頂層,service worker將監聽器註冊到一些事件中,以允許它們稍後被執行。

從background scripts到service worker的轉換依賴於擴展中的代碼。一些擴展可能需要大量的工作,而另一些則不需要這麼多。

需要做的第一步是將以前作為background scripts文件移動到根目錄。

{
    ...,
    "background": {
        "service_worker": "background.js"
      },
    ...
}

現在,讓我們看看代碼。以前的background script如下:

chrome.runtime.onMessage.addListener(function(message, sender, senderResponse){
  if(message.msg === "image"){
    fetch('http://some-random-api.com/img/xxx')
          .then(response => response.text())
          .then(data => {
            let dataObj = JSON.parse(data);
            senderResponse({data: dataObj, index: message.index});
          })
          .catch(error => console.log("error", error))
      return true; 
  }
});

基本上,我們的後台腳本使用 chrome.runtime.onMessage.addListener 來監聽一個消息,如果該消息請求一個圖片,它將向API發送一個請求,然後將數據返回給我們的content script。

這個background script實際上不需要任何額外的更改。因為service worker的後台腳本只是註冊了一個事件監聽器,並在事件發生時執行代碼,這正是service worker應該做的。

但並不是所有的擴展都是這樣的,因為有不同的情況。以下是你在background script中需要檢查和修改的內容:

1) 全局變量

以前的後台腳本總是在後台運行。如果有以下代碼:

let count = 0;

chrome.runtime.onMessage.addListener( (message) => {
    count++;
    console.log(count);
});

每當service worker收到一條消息時,count就會增加。一開始是0,然後是1,然後是2,以此類推。

在service worker中,這將不再有效。service worker只會在需要時運行,並在完成工作時終止。因此,上述代碼將始終在控制枱打印“1”。

在上面的例子中,計數可以在background script和content script之間來回傳遞,以獲得所需的結果。更好的方法是使用Chrome的存儲API。

2) Timers and Alarms

Timers 在後台腳本中使用沒有問題,因為它們總是在後台運行。然而,這不適用於服務工作者。你應該用 Alarms API 替換所有的計時器。

3) 訪問DOM

Service worker不能訪問windows或DOM。如果你的擴展需要,你可以使用類似 jsdom 的庫或使用chrome.windows.create和chrome.tabs.create。這取決於你的具體使用場景。

如果你的background scripts有錄製音頻或視頻,這也是需要修改的,因為這在service worker中是不可以的。

4) 創建Canvas

如果你的background scripts之前創建了畫布,你仍然可以用 offscreenenccanvas API 來做。你所要做的就是用 OffscreenCanvas 替換 document

MV2

let canvas = document.createElement('canvas');

MV3

let canvas = new OffscreenCanvas(width, height);

在完成這些修改之後,需要將你的background scripts 修改為service worker,在瀏覽器中重新加載你的擴展,看看它是否正常工作。

5) 執行腳本executeScript

如果你的代碼使用executeScript的code屬性執行任意字符串,有兩種方法來更改它。同時,不使用chrome.tabs.execute腳本,需要用 script 替換標籤,這樣它將是 chrome.script .executeScript

將代碼移植到文件

你需要將代碼的值移動到一個新文件,並使用executeScript的 file 屬性。

之前

chrome.tabs.executeScript({
    code: alert("Hello, World!")
});

修改為

alert(“Hello, World!”) 放到一個新文件(讓我們叫它 Hello - World .js ):

alert("Hello, World!");
chrome.scripting.executeScript({
    file: 'hello-world.js'
});

將代碼放到Function中

如果你的代碼可以放在一個函數中,可以將它移動到同一個文件中的一個函數中,然後將execute escripts的 function 屬性賦值給你創建的函數:

function greeting() {
    alert("Hello, World!");
}

chrome.scripting.executeScript({
    function: greeting
});

3、其它需求檢查的

這裏有一個列表,列出了你需要在代碼中尋找的要更改的內容:

1、如果你的擴展使用 webRequest API ,它通常用於強制安裝擴展的企業設置,你需要用 declarativentrequest API 替換它。

2、如果你在內容腳本中發出任何CORS請求,請將它們移動到service worker中。

3、不再允許遠程託管代碼。你需要找到另一種方法來執行遠程託管的代碼。Chrome的文檔建議使用 配置驅動功能和邏輯 ,這個意思就是説將配置本地化,然後執行用遠程的web服務來執行。

4、請查看 API參考 ,瞭解可能正在使用的已棄用的API或方法。

好了,以上就是本篇主要內容,Manifest V3的新特性讓擴展更安全,其實長遠看是有好處的,這樣瀏覽器擴展也不會被濫用,只是之前的MV2一些用法和寫法需要做一些調整,工作量應該不會很大,逐條檢查自己產品中存在的問題,相信問題一定能夠解決,祝大家產品越做越好!