Chrome Extension 訊息傳遞

FunTester發表於2024-09-09

在之前的 Chrome Extension 開發的初探文章當中,我對 訊息傳遞 的認識還比較淺,最近又雙叒叕學到了一點點這方便的新知識,也在一次又一次的功能實踐當中也體會到了訊息傳遞在實用當中重要性。所以還是再寫一篇關於訊息傳遞的內容,另外個人覺得這個方向非常不錯,也推薦給各位。

重新認識 message

在 Chrome 擴充套件開發中,message 通訊機制是核心技術之一,它允許擴充套件的不同元件(如內容指令碼、後臺指令碼、彈出頁面、選項頁面等)透過傳送和接收訊息來進行互動和協作。這種通訊方式打破了擴充套件元件之間的孤立狀態,使得它們能夠像團隊一樣高效地協同工作,共享資料,觸發操作,甚至執行復雜的邏輯處理。

透過 message 通訊,內容指令碼可以向後臺指令碼請求資料或執行後臺任務,而後臺指令碼則可以根據接收到的訊息作出響應,並將結果傳回給內容指令碼或其他元件。此外,彈出頁面可以透過訊息向後臺指令碼傳送使用者指令,更新擴充套件的狀態,或與當前網頁內容進行互動。

這種機制不僅提高了擴充套件的靈活性和功能性,還增強了擴充套件在處理非同步任務和使用者互動時的響應能力。例如,當使用者在彈出頁面中點選按鈕時,後臺指令碼可以即時接收訊息,執行相關操作,如訪問遠端 API、更新儲存的資料或通知內容指令碼在當前頁面上進行某些操作。

message 通訊機制在 Chrome 擴充套件開發中扮演了關鍵角色,使得複雜的擴充套件能夠以模組化的方式構建,每個元件各司其職,又能夠透過訊息傳遞無縫協作,實現擴充套件整體功能的最大化。

使用場景

在 Chrome 擴充套件開發中,message 通訊有多種常見的應用場景,每種場景都涉及擴充套件不同元件之間的訊息傳遞。這些場景通常包括內容指令碼與後臺指令碼的通訊、彈出頁面與後臺指令碼的互動、擴充套件各部分之間的廣播訊息等。以下是一些典型的message 通訊場景:

1. 內容指令碼與後臺指令碼的通訊

  • 場景描述: 內容指令碼通常用於與當前網頁的 DOM 進行互動,但由於其在一個獨立的環境中執行,無法直接訪問後臺指令碼的資料或功能。因此,內容指令碼需要透過訊息傳遞與後臺指令碼通訊。
  • 應用示例: 內容指令碼檢測到網頁上的特定元素變化後,向後臺指令碼傳送訊息,請求後臺指令碼抓取或更新資料。內容指令碼從後臺指令碼請求使用者的設定資料,獲取後根據設定動態修改網頁內容。

    2. 彈出頁面與後臺指令碼的通訊

  • 場景描述: 彈出頁面是使用者與擴充套件互動的入口,通常需要根據使用者的操作觸發後臺指令碼執行某些任務。由於彈出頁面只在被開啟時存在,因此需要與持久執行的後臺指令碼通訊來保持狀態和執行操作。

  • 應用示例: 使用者在彈出頁面中點選按鈕後,向後臺指令碼傳送訊息,後臺指令碼接收後執行相應的操作,如儲存資料或觸發通知。彈出頁面在載入時請求後臺指令碼獲取當前狀態資訊,以便顯示最新的應用狀態或使用者資料。

3. 後臺指令碼與多個內容指令碼的通

  • 場景描述: 當擴充套件需要在多個標籤頁或視窗中的內容指令碼之間同步資訊時,後臺指令碼可以充當訊息中心,接收一個內容指令碼的訊息並將其轉發給其他內容指令碼。
  • 應用示例: 一個內容指令碼更新了網頁上的某些資料,並將此更新透過後臺指令碼通知其他所有開啟的標籤頁,使它們的內容同步。使用者在某個標籤頁上執行操作後,後臺指令碼透過廣播將此操作通知給所有相關的內容指令碼,讓它們根據需要做出相應更新。

4. 擴充套件選項頁面與後臺指令碼的通訊

  • 場景描述: 選項頁面通常用於擴充套件的配置設定,使用者在此頁面上修改的設定需要持久儲存並立即生效。透過訊息通訊,選項頁面可以與後臺指令碼互動,實現設定的儲存和應用。
  • 應用示例: 使用者在選項頁面修改擴充套件的配置後,透過訊息通知後臺指令碼,後臺指令碼更新配置並將新設定應用到所有活動的內容指令碼中。選項頁面在載入時請求後臺指令碼提供當前設定資料,以便使用者檢視和修改。

5. 使用廣播訊息

  • 場景描述: 當擴充套件需要在其所有部分(內容指令碼、彈出頁面、後臺指令碼等)之間傳遞訊息時,可以使用廣播訊息。這種方式可以將訊息傳送給擴充套件的所有元件,而不必指定特定的接收者。
  • 應用示例: 擴充套件在某個部分(如彈出頁面)執行某個操作後,透過廣播訊息通知擴充套件的所有其他部分(如內容指令碼、後臺指令碼),確保整個擴充套件的一致性。當後臺指令碼監測到某個全域性事件(如網路連線變化)時,透過廣播訊息通知所有相關的擴充套件元件,以便它們採取相應的措施。

這些場景展示了message 通訊機制在 Chrome 擴充套件開發中的廣泛應用,它使得擴充套件能夠有效地管理和協調其不同部分,確保功能的順暢執行和使用者體驗的一致性。

message 型別

Chrome 擴充套件的 message 通訊機制主要包括以下幾種情況,每種情況都對應了擴充套件內部不同元件之間的訊息傳遞方式。這些通訊方式確保了擴充套件的各個部分能夠高效協作,實現複雜功能和良好的使用者體驗。

單向訊息傳遞

單向訊息傳遞 是 Chrome 擴充套件中的一種基本通訊方式,它指的是訊息從一個元件傳送到另一個元件後,不需要立即收到回覆或反饋。這種方式適用於簡單的通知或觸發操作場景,在擴充套件的各個部分之間傳遞資訊時非常常見。

單向訊息傳遞 是 Chrome 擴充套件中的一種基本通訊方式,它指的是訊息從一個元件傳送到另一個元件後,不需要立即收到回覆或反饋。這種方式適用於簡單的通知或觸發操作場景,在擴充套件的各個部分之間傳遞資訊時非常常見。

應用場景

  1. 內容指令碼向後臺指令碼傳送資料: 當內容指令碼檢測到某個事件(如使用者點選按鈕或網頁元素變化)時,它可以透過單向訊息將這個事件通知後臺指令碼。後臺指令碼接收到訊息後可以執行相應的操作,如記錄日誌或更新擴充套件的狀態。
  2. 彈出頁面通知後臺指令碼執行操作: 使用者在彈出頁面中進行的操作(如點選某個按鈕)可能需要觸發後臺指令碼執行某些任務。在這種情況下,彈出頁面可以透過單向訊息將指令傳送給後臺指令碼,然後繼續處理使用者的其他操作,而無需等待後臺指令碼的回應。
  3. 後臺指令碼向內容指令碼廣播資訊: 如果後臺指令碼監測到某個全域性事件(如擴充套件狀態變化或使用者設定更新),它可以透過單向訊息通知所有活動的內容指令碼,內容指令碼可以根據需要更新頁面顯示或執行相關操作。

單向訊息傳遞 的優點:

  • 簡潔: 只需傳送訊息而不需要處理返回值,簡化了通訊邏輯。
  • 高效: 適合需要快速觸發操作或傳送通知的場景。

注意事項: 由於是單向訊息傳遞,傳送方無法確認接收方是否成功處理了訊息。因此,這種方式更適用於無需確認的簡單通訊場景。

演示

下面是一個關於 Chrome 擴充套件中單向訊息傳遞的簡單例子,展示了內容指令碼向後臺指令碼傳送訊息的過程。

1. 內容指令碼 (content.js)

內容指令碼偵聽網頁上的按鈕點選事件,並在按鈕被點選時向後臺指令碼傳送一條訊息。

// 偵聽頁面上按鈕的點選事件
document.getElementById('myButton').addEventListener('click', function() {
    // 向後臺指令碼傳送訊息
    chrome.runtime.sendMessage({ action: 'buttonClicked', data: 'Hello from content script' });
});

2. 後臺指令碼 (background.js)

後臺指令碼接收內容指令碼傳送的訊息,並處理該訊息(例如,記錄日誌或執行其他操作)。

// 監聽來自內容指令碼的訊息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    if (message.action === 'buttonClicked') {
        // 處理收到的訊息
        console.log('Received message:', message.data);
        // 這裡可以執行其他操作,例如更新擴充套件狀態或傳送通知
    }
});

在這個例子中,當使用者點選網頁上的按鈕時,內容指令碼透過 chrome.runtime.sendMessage 方法向後臺指令碼傳送了一條訊息。後臺指令碼接收到訊息後,透過 chrome.runtime.onMessage.addListener 監聽器處理該訊息。

雙向長連線通訊

雙向長連線通訊 是 Chrome 擴充套件中一種高階的通訊機制,它允許擴充套件的兩個元件之間建立持久的連線,並進行持續的雙向資料交換。這種方式適用於需要實時更新、持續通訊的場景,如內容指令碼與後臺指令碼之間的實時資料同步或狀態監控。

應用場景

  1. 內容指令碼與後臺指令碼的實時資料同步: 當使用者在網頁上進行連續操作時,內容指令碼可以透過長連線實時將資料傳送給後臺指令碼,後臺指令碼可以立即響應並將處理結果返回給內容指令碼。
  2. 擴充套件的實時狀態監控: 擴充套件需要持續監控某些狀態變化並根據變化做出響應,長連線通訊可以保證狀態的實時同步,確保使用者操作的即時反饋。
  3. 實時聊天功能: 內容指令碼與後臺指令碼之間的長連線可以用於實現聊天應用的訊息實時傳輸。
  4. 實時資料分析: 使用者在網頁上的操作可以透過長連線實時傳送到後臺指令碼,進行資料分析和反饋。
  5. 遊戲擴充套件: 可以使用長連線來實現網頁遊戲中的實時資料傳輸和狀態同步。

雙向長連線通訊特點

  • 持久連線: 一旦連線建立,雙方可以在不需要重新建立連線的情況下相互傳送訊息,直到連線被顯式斷開。
  • 雙向通訊: 兩個端點可以在連線的生命週期內自由地傳送和接收訊息。
  • 低延遲: 適合實時性要求高的應用場景,如聊天應用、實時資料流等。

演示

內容指令碼 (content.js)

內容指令碼透過 chrome.runtime.connect 方法與後臺指令碼建立連線,並監聽連線埠上的訊息。

// 與後臺指令碼建立連線
const port = chrome.runtime.connect({ name: 'content-background' });

// 監聽來自後臺指令碼的訊息
port.onMessage.addListener(function(msg) {
    console.log('Received message from background:', msg);

    // 可以根據後臺指令碼的訊息更新頁面或執行操作
});

// 傳送訊息給後臺指令碼
port.postMessage({ action: 'init', data: 'Hello from content script' });

後臺指令碼 (background.js)

後臺指令碼透過 chrome.runtime.onConnect.addListener 監聽內容指令碼的連線請求,並在連線建立後監聽訊息和傳送響應。

// 監聽內容指令碼的連線請求
chrome.runtime.onConnect.addListener(function(port) {
    console.log('Connected:', port.name);

    // 監聽來自內容指令碼的訊息
    port.onMessage.addListener(function(msg) {
        console.log('Received message from content script:', msg);

        // 根據收到的訊息執行操作,併傳送回應
        if (msg.action === 'init') {
            port.postMessage({ response: 'Connection established' });
        }
    });

    // 連線關閉時執行操作
    port.onDisconnect.addListener(function() {
        console.log('Port disconnected');
    });
});

例子的詳細解釋:

  • 連線建立: 內容指令碼透過 chrome.runtime.connect 方法與後臺指令碼建立連線,並指定一個連線名稱name,以便區分不同的連線。
  • 訊息傳送與接收: 一旦連線建立,內容指令碼和後臺指令碼可以透過連線埠 (port) 進行雙向訊息傳遞。port.postMessage 用於傳送訊息,port.onMessage.addListener 用於接收訊息。
  • 連線斷開: 當連線不再需要時,或者內容指令碼所在的頁面關閉時,連線會被自動斷開。可以透過 port.onDisconnect.addListener 監聽連線斷開事件。

跨擴充套件/應用的訊息傳遞

跨擴充套件/應用的訊息傳遞 是指在不同的 Chrome 擴充套件、應用或網頁之間傳遞訊息。這種通訊方式允許不同的擴充套件或應用之間進行資料交換或協作,實現更復雜的功能和整合。以下是跨擴充套件/應用訊息傳遞的主要方式和應用場景:

這種方式允許一個擴充套件向另一個擴充套件傳送訊息,但前提是這兩個擴充套件都需要宣告適當的許可權,並且訊息傳遞是透過擴充套件的 ID 實現的。

跨擴充套件/應用的訊息傳遞 有兩種實現方式,總結為 訊息模型連線模型 。這與前兩者訊息型別有相似的關係。

訊息模型

傳送訊息

要向另一個擴充套件傳送訊息,您需要知道目標擴充套件的 ID。可以使用 chrome.runtime.sendMessage 傳送訊息到指定的擴充套件。

// 向指定 ID 的擴充套件傳送訊息
chrome.runtime.sendMessage('TARGET_EXTENSION_ID', { action: 'someAction', data: 'Hello from extension A' });

接收訊息

目標擴充套件需要在其後臺指令碼或其他元件中監聽訊息,並作出相應的處理。

// 監聽來自其他擴充套件的訊息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    if (message.action === 'someAction') {
        console.log('Received message from another extension:', message.data);
        // 處理訊息
    }
});

連線模型

這種方法適用於建立持久的連線,可以用於跨擴充套件的持久通訊。

建立連線

擴充套件 A 透過 chrome.runtime.connect 建立與擴充套件 B 的連線(前提是擴充套件 B 允許此連線)。

// 擴充套件 A 中建立連線
const port = chrome.runtime.connect('TARGET_EXTENSION_ID', { name: 'extensionA-to-B' });

監聽連線

擴充套件 B 監聽來自擴充套件 A 的連線請求,並處理資料交換。

// 擴充套件 B 中監聽連線
chrome.runtime.onConnect.addListener(function(port) {
    console.log('Connected with port name:', port.name);

    port.onMessage.addListener(function(message) {
        console.log('Received message from extension A:', message);
        // 處理訊息
    });
});

許可權和宣告

要使跨擴充套件訊息傳遞功能正常工作,目標擴充套件需要在其 manifest.json 檔案中宣告許可權。通常需要宣告 *://*/* 或特定的 URL 許可權,以及 identity 許可權。

{
  "manifest_version": 3,
  "name": "Extension B",
  "version": "1.0",
  "permissions": [
    "identity",
    "https://FunTester.com/*" // 指定允許的 URL 或域名
  ],
  "background": {
    "service_worker": "background.js"
  }
}

應用場景

  1. 跨擴充套件整合: 例如,擴充套件 A 可以與擴充套件 B 交換資料,實現擴充套件功能的擴充套件或整合。
  2. 跨應用通訊: 一個擴充套件可以與網頁應用或桌面應用進行通訊,傳遞資訊或觸發操作。
  3. 外掛協作: 不同的擴充套件或外掛可以協同工作,共享狀態或功能,以增強使用者體驗。

注意事項:

  • 許可權: 跨擴充套件訊息傳遞需要適當的許可權配置,確保目標擴充套件的許可權允許接收訊息。
  • 安全性: 確保訊息傳遞機制的安全性,避免惡意擴充套件透過跨擴充套件通訊方式訪問敏感資料。

頁面與內容指令碼之間的訊息傳遞

頁面與內容指令碼之間的訊息傳遞 是在 Chrome 擴充套件中實現網頁(頁面指令碼)與內容指令碼之間的資料交換和互動的機制。內容指令碼執行在網頁的隔離環境中,而頁面指令碼是網頁本身的 JavaScript 程式碼,兩者之間不能直接共享變數或函式。因此,需要使用訊息傳遞機制進行通訊。

應用場景

  • 資料交換: 在網頁的頁面指令碼和內容指令碼之間交換資料,比如從網頁中獲取使用者輸入併傳送到內容指令碼進行處理。
  • 實時更新: 實現網頁內容的實時更新,例如當內容指令碼修改了網頁上的內容,頁面指令碼需要做出相應的調整。
  • 跨元件通訊: 透過內容指令碼作為中介實現頁面指令碼與後臺指令碼的通訊。

透過這些機制,Chrome 擴充套件能夠在網頁和擴充套件的不同元件之間實現高效的資料交換和互動,增強使用者體驗和擴充套件功能。與 跨擴充套件/應用的訊息傳遞 類似,也有兩種不同風格的 API

window API

window.postMessage 是在頁面指令碼和內容指令碼之間傳遞訊息的主要方式。它允許不同的視窗(包括 iframe 和跨域視窗)之間傳送訊息。具體步驟如下:

內容指令碼 (content.js)

內容指令碼透過 window.postMessage 向網頁中的頁面指令碼傳送訊息。

// 向頁面指令碼傳送訊息
window.postMessage({ type: 'FROM_CONTENT_SCRIPT', data: 'Hello from content script' }, '*');

頁面指令碼 (page.js)

頁面指令碼監聽來自內容指令碼的訊息,並處理這些訊息。

// 監聽來自內容指令碼的訊息
window.addEventListener('message', function(event) {
    if (event.origin !== 'http://expected-origin.com') {
        // 驗證訊息來源
        return;
    }

    if (event.data.type === 'FROM_CONTENT_SCRIPT') {
        console.log('Received message from content script:', event.data.data);
        // 處理訊息
    }
});

chrome Message API

這種方式用於內容指令碼與背景指令碼之間的訊息傳遞,但在頁面指令碼和內容指令碼之間需要依賴內容指令碼作為中介。

內容指令碼 (content.js)

內容指令碼從頁面指令碼接收訊息,並可以透過 chrome.runtime.sendMessage 將其轉發給後臺指令碼。

// 監聽來自頁面指令碼的訊息
window.addEventListener('message', function(event) {
    if (event.data.type === 'FROM_PAGE_SCRIPT') {
        // 處理來自頁面指令碼的訊息
        chrome.runtime.sendMessage({ type: 'FROM_CONTENT_SCRIPT', data: event.data.data });
    }
});

頁面指令碼 (page.js)

頁面指令碼透過 window.postMessage 向內容指令碼傳送訊息。

// 向內容指令碼傳送訊息
window.postMessage({ type: 'FROM_PAGE_SCRIPT', data: 'Hello from page script' }, '*');

後臺指令碼 (background.js)

後臺指令碼接收內容指令碼轉發的訊息。

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    if (message.type === 'FROM_CONTENT_SCRIPT') {
        console.log('Received message from content script:', message.data);
        // 處理訊息
    }
});

訊息傳遞的步驟

  1. 頁面指令碼向內容指令碼傳送訊息: 使用 window.postMessage 從頁面指令碼傳送訊息到內容指令碼。
  2. 內容指令碼處理訊息並轉發: 內容指令碼使用 window.addEventListener 監聽來自頁面指令碼的訊息。內容指令碼可以選擇直接處理訊息,也可以透過 chrome.runtime.sendMessage 將訊息轉發到後臺指令碼。
  3. 內容指令碼向頁面指令碼傳送訊息: 內容指令碼使用 window.postMessage 向頁面指令碼傳送訊息。
  4. 頁面指令碼處理返回的訊息: 頁面指令碼使用 window.addEventListener 監聽來自內容指令碼的訊息。
FunTester 原創精華
  • 服務端功能測試
  • 效能測試專題
  • Java、Groovy、Go
  • 白盒、工具、爬蟲、UI 自動化
  • 理論、感悟、影片
如果覺得我的文章對您有用,請隨意打賞。您的支援將鼓勵我繼續創作!
打賞支援
暫無回覆。

相關文章