原生訊息傳遞

擴充功能可以使用與其他傳送訊息 API 類似的 API,與原生應用程式交換訊息。支援這項功能的原生應用程式必須註冊可與擴充功能通訊的原生訊息傳遞主機。Chrome 會在獨立程序中啟動主機,並使用標準輸入和標準輸出串流與之進行通訊。

內建訊息傳遞主機

如要註冊原生訊息主機,應用程式必須儲存定義原生訊息主機設定的檔案。

檔案範例如下:

{
  "name": "com.my_company.my_application",
  "description": "My Application",
  "path": "C:\\Program Files\\My Application\\chrome_native_messaging_host.exe",
  "type": "stdio",
  "allowed_origins": ["chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"]
}

原生訊息主機資訊清單檔案必須是有效的 JSON,並包含下列欄位:

name
內建訊息傳遞主機的名稱。用戶端會將這個字串傳送至 runtime.connectNative()runtime.sendNativeMessage()。這個名稱只能包含小寫英數字元、底線和半形句號。名稱的開頭或結尾不得為半形句號,且半形句號後不得再接半形句號。
description
簡短的應用程式說明。
path
原生訊息傳遞主機二進位檔的路徑。在 Linux 和 macOS 上,路徑必須是絕對路徑。在 Windows 上,此路徑可以相對於包含資訊清單檔案的目錄。主機程序會從目前設定為包含主機二進位檔的目錄啟動主機程序。舉例來說,如果這個參數設為 C:\Application\nm_host.exe,則會以目前目錄 `C:\Application` 啟動。
type
用來與原生訊息傳遞主機通訊的介面類型,這個參數有一個可能的值:stdio。這表示 Chrome 應使用 stdinstdout 與主機通訊。
allowed_origins
應具備原生訊息主機存取權的擴充功能清單。allowed-origins不得包含萬用字元。

內建訊息傳遞主機位置

資訊清單檔案的位置會因平台而異。

Windows 上,資訊清單檔案可位於檔案系統的任何位置。應用程式安裝工具必須建立登錄機碼 (HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_applicationHKEY_CURRENT_USER\SOFTWARE\Google\Chrome\NativeMessagingHosts\com.my_company.my_application),並將該機碼的預設值設為資訊清單檔案的完整路徑。例如,使用下列指令:

REG ADD "HKCU\Software\Google\Chrome\NativeMessagingHosts\com.my_company.my_application" /ve /t REG_SZ /d "C:\path\to\nmh-manifest.json" /f

或使用以下 .reg 檔案:

Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Google\Chrome\NativeMessagingHosts\com.my_company.my_application]
@="C:\\path\\to\\nmh-manifest.json"

Chrome 尋找原生訊息主機時,會先查詢 32 位元登錄檔,然後再查詢 64 位元登錄檔。

macOSLinux 上,原生訊息傳遞主機的資訊清單檔案位置會因瀏覽器 (Google Chrome 或 Chromium) 而異。系統層級原生訊息傳遞主機會在固定位置查詢,而使用者層級原生訊息傳遞主機會在使用者設定檔目錄NativeMessagingHosts/ 子目錄中查詢。

macOS (整個系統)
Google Chrome:/Library/Google/Chrome/NativeMessagingHosts/com.my_company.my_application.json
Chromium:/Library/Application Support/Chromium/NativeMessagingHosts/com.my_company.my_application.json
macOS (使用者專屬,預設路徑)
Google Chrome:~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.my_company.my_application.json
Chromium:~/Library/Application Support/Chromium/NativeMessagingHosts/com.my_company.my_application.json
Linux (整個系統)
Google Chrome:/etc/opt/chrome/native-messaging-hosts/com.my_company.my_application.json
Chromium:/etc/chromium/native-messaging-hosts/com.my_company.my_application.json
Linux (使用者專屬,預設路徑)
Google Chrome:~/.config/google-chrome/NativeMessagingHosts/com.my_company.my_application.json
Chromium:~/.config/chromium/NativeMessagingHosts/com.my_company.my_application.json

原生訊息傳遞通訊協定

Chrome 會在個別程序中啟動每個原生訊息主機,並使用標準輸入 (stdin) 和標準輸出 (stdout) 與其進行通訊。兩個方向都會使用相同的格式傳送訊息;每則訊息都會使用 JSON 序列化,並以原生位元組順序編碼,前面加上 32 位元訊息長度。來自原生訊息傳遞主機的單一訊息大小上限為 1 MB,主要用於防止 Chrome 對原生應用程式無法正常運作。傳送至原生訊息主機的訊息大小上限為 4 GB。

原生訊息主機的第一個引數是呼叫端的來源,通常是 chrome-extension://[ID of allowed extension]。如此一來,當您在原生訊息傳遞主機資訊清單allowed_origins 金鑰中指定多項擴充功能時,原生訊息傳遞主機就能識別訊息來源。

在 Windows 上,內建訊息傳遞主機也會傳遞指令列引數,其中包含對呼叫 Chrome 原生視窗的句柄:--parent-window=<decimal handle value>。這可讓原生訊息傳遞主機建立正確父項的本機 UI 視窗。請注意,如果呼叫內容為服務工作者,這個值會是 0。

使用 runtime.connectNative() 建立訊息通訊埠時,Chrome 會啟動原生訊息主機程序,並持續執行,直到通訊埠遭到銷毀為止。另一方面,如果使用 runtime.sendNativeMessage() 傳送訊息,但未建立訊息端口,Chrome 會為每則訊息啟動新的原生訊息主機程序。在這種情況下,主機程序產生的首個訊息會視為對原始要求的回應,而 Chrome 會將該訊息傳遞至呼叫 runtime.sendNativeMessage() 時指定的回應回呼。在這種情況下,系統會忽略原生訊息傳遞主機產生的所有其他訊息。

連線至原生應用程式

與原生應用程式互傳訊息和跨擴充功能訊息非常相似。主要差異在於 runtime.connectNative() 取代 runtime.connect(),而 runtime.sendNativeMessage() 取代 runtime.sendMessage()

如要使用這些方法,您必須在擴充功能的資訊清單檔案中宣告「nativeMessaging」權限。

這些方法不適用於內容指令碼,只能用於擴充功能的頁面和服務工作者。如果希望從內容指令碼傳送至原生應用程式,請將訊息傳送至 Service Worker,以將訊息傳遞至原生應用程式。

以下範例會建立與原生訊息主機 com.my_company.my_application 連線的 runtime.Port 物件,並開始監聽該通訊埠的訊息,以及傳送一則外寄訊息:

var port = chrome.runtime.connectNative('com.my_company.my_application');
port.onMessage.addListener(function (msg) {
  console.log('Received' + msg);
});
port.onDisconnect.addListener(function () {
  console.log('Disconnected');
});
port.postMessage({text: 'Hello, my_application'});

使用 runtime.sendNativeMessage 傳送訊息至原生應用程式,不必建立通訊埠,例如:

chrome.runtime.sendNativeMessage(
  'com.my_company.my_application',
  {text: 'Hello'},
  function (response) {
    console.log('Received ' + response);
  }
);

對原生訊息傳遞進行偵錯

發生特定原生訊息傳送錯誤時,系統會將輸出內容寫入 Chrome 的錯誤記錄檔。包括原生訊息傳遞主機無法啟動、寫入 stderr 或違反通訊通訊協定時。在 Linux 和 macOS 上,您可以透過從指令列啟動 Chrome,並在終端機中查看輸出內容,來存取這份記錄。在 Windows 上,請使用 --enable-logging,如這篇文章所述。

以下列舉幾個常見錯誤和解決提示:

無法啟動內建訊息傳遞主機。

檢查您是否具備執行原生訊息傳遞主機檔案的足夠權限。

指定的內建訊息傳遞主機名稱無效。

檢查名稱是否包含無效字元。只能使用小寫英數字元、底線和半形句號。名稱的開頭或結尾不得為半形句號,且半形句號後不得接著另一個半形句號。

原生主機已結束執行。

在 Chrome 讀取訊息前,通往原生訊息主機的管道已中斷。這很可能是由原生訊息傳遞主機啟動。

找不到指定的原生訊息傳遞主機。

請檢查下列事項:

  • 擴充功能和資訊清單檔案中的名稱拼寫是否正確?
  • 資訊清單是否位於正確的目錄中?名稱是否正確?如要瞭解預期格式,請參閱原生訊息傳遞主機位置
  • 資訊清單檔案的格式是否正確?具體來說,JSON 是否有效且格式正確?值是否符合原生訊息主機資訊清單的定義?
  • path 中指定的檔案是否存在?在 Windows 上,路徑可以是相對路徑,但在 macOS 和 Linux 上,路徑必須是絕對路徑。

尚未註冊內建訊息傳遞主機主機名稱。(僅限 Windows)

Windows 登錄檔中找不到原生訊息傳遞主機。使用 regedit 再三確認金鑰是否確實已建立,且符合「原生訊息主機位置」所述的必要格式。

系統禁止存取指定的內建訊息傳遞主機。

擴充功能的來源是否列在 allowed_origins 中?

與原生訊息主機通訊時發生錯誤。

這表示原生訊息傳遞主機中通訊協定的實作方式不正確。

  • 請確認 stdout 中的所有輸出內容都符合原生訊息傳遞通訊協定。如要為了偵錯目的而列印部分資料,請寫入 stderr
  • 請確認 32 位元訊息長度採用平台的原生整數格式 (位元組由小到大/位元組由大到小)。
  • 訊息長度不得超過 1024*1024。
  • 訊息大小必須等於訊息中的位元組數。這可能會與字串的「length」不同,因為字元可能會以多個位元組表示。
  • 僅限 Windows:請確認程式的 I/O 模式已設為 O_BINARY。根據預設,I/O 模式為 O_TEXT,會將換行符號 (\n = 0A) 替換為 Windows 風格的換行符號 (\r\n = 0D 0A),導致訊息格式毀損。您可以使用 __setmode 設定 I/O 模式。