メッセージ受け渡し

コンテンツ スクリプトは拡張機能ではなくウェブページのコンテキストで実行されるため、多くの場合、 他の拡張機能との 通信手段を確立しますたとえば、RSS リーダー拡張機能は、 コンテンツ スクリプトを使用してページ上に RSS フィードがあることを検出し、 表示する必要があります

拡張機能とそのコンテンツ スクリプト間の通信は、メッセージの受け渡しによって行われます。どちらでもかまわない 側から送られるメッセージをリッスンし、同じチャネルで応答できます。メッセージは 有効な JSON オブジェクト(null、ブール値、数値、文字列、配列、オブジェクト)が含まれている。簡単な 1 回限りのリクエスト用の API と、長時間の有効期間を可能にする、より複雑な API 複数のメッセージを交換するための接続。スペース名をクリックして ID がわかっている場合は、別の拡張機能へのメッセージ転送もできます。ID については、 メッセージ] セクションに表示されます。

シンプルな 1 回限りのリクエスト

拡張機能の別の部分にメッセージを 1 つだけ送信するだけでよい場合(また、必要に応じて 簡潔な runtime.sendMessage または tabs.sendMessage を使用してください。 これにより、JSON でシリアル化可能な 1 回限りのメッセージをコンテンツ スクリプトから拡張機能に(またはその逆に)送信できます。 。オプションのコールバック パラメータを使用すると、 表示されます

コンテンツ スクリプトからリクエストを送信すると、次のようになります。

chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
  console.log(response.farewell);
});

拡張機能からコンテンツ スクリプトにリクエストを送信する方法もよく似ていますが、以下を行う必要があります。 送信先のタブを指定しますこの例では、コンテンツ スクリプトにメッセージを送信する方法を示しています。 クリックします。

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
    console.log(response.farewell);
  });
});

受信側では、このイベントを処理する runtime.onMessage イベント リスナーをセットアップする必要があります。 表示されます。これは、コンテンツ スクリプトまたは拡張機能ページで同じように見えます。

chrome.runtime.onMessage.addListener(
  function(request, sender, sendResponse) {
    console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
    if (request.greeting == "hello")
      sendResponse({farewell: "goodbye"});
  }
);

上記の例では、sendResponse が同期的に呼び出されています。非同期的に使用したい場合は sendResponse の場合は、return true;onMessage イベント ハンドラに追加します。

注: 複数のページが onMessage イベントをリッスンしている場合、特定のイベントに対して最初に sendResponse() を呼び出した場合にのみ、レスポンスの送信に成功します。そのイベントに対する他の回答はすべて無視されます。
注: sendResponse コールバックは、同期的に使用した場合、またはイベント ハンドラが非同期応答を示す true を返した場合にのみ有効です。ハンドラが true を返さない場合、または sendResponse コールバックがガベージ コレクションの対象となった場合、sendMessage 関数のコールバックは自動的に呼び出されます。

長時間接続

単一のリクエストとレスポンスよりも長く会話が続くと便利な場合があります。 この場合、コンテンツ スクリプトから拡張機能ページに、存続期間が長いチャンネルをオープンできます。 その逆に、それぞれ runtime.connect または tabs.connect を使用します。チャンネルは オプションには名前があり、接続のタイプを区別できます。

ユースケースの一例として、フォーム自動入力拡張機能があります。コンテンツ スクリプトは、 特定のログイン用の拡張機能ページを作成し、入力するたびに拡張機能にメッセージを送信できます。 要素を使用して、記入するフォームデータをリクエストします。共有接続により 拡張機能は コンテンツ スクリプトから送られる複数のメッセージをリンクして、共有状態を維持します。

接続を確立するとき、両端に runtime.Port オブジェクトが渡されます。このオブジェクトは、 その接続を介してメッセージを送受信します。

コンテンツ スクリプトからチャンネルを開き、メッセージを送信してリッスンする方法は次のとおりです。

var port = chrome.runtime.connect({name: "knockknock"});
port.postMessage({joke: "Knock knock"});
port.onMessage.addListener(function(msg) {
  if (msg.question == "Who's there?")
    port.postMessage({answer: "Madame"});
  else if (msg.question == "Madame who?")
    port.postMessage({answer: "Madame... Bovary"});
});

拡張機能からコンテンツ スクリプトにリクエストを送信する方法もよく似ていますが、以下を行う必要があります。 接続するタブを指定します上記の例の接続先の名前を tabs.connect.

受信接続を処理するために、runtime.onConnect イベントをセットアップする必要があります。 呼び出すことができます。これは、コンテンツ スクリプトまたは拡張機能ページで同じように見えます。データの他の部分が 拡張機能が「connect()」を呼び出すと、このイベントが runtime.Port オブジェクト( 接続を介したメッセージの送受信に使用されますこのように 受信接続:

chrome.runtime.onConnect.addListener(function(port) {
  console.assert(port.name == "knockknock");
  port.onMessage.addListener(function(msg) {
    if (msg.joke == "Knock knock")
      port.postMessage({question: "Who's there?"});
    else if (msg.answer == "Madame")
      port.postMessage({question: "Madame who?"});
    else if (msg.answer == "Madame... Bovary")
      port.postMessage({question: "I don't get it."});
  });
});

ポートの存続期間

ポートは、拡張機能の異なる部分間で双方向の通信方式として設計されています。 (最上位)フレームが最小部分として表示されます。 tabs.connectruntime.connect、または runtime.connectNative を呼び出した場合、ポート 作成されます。このポートは、次の宛先へのメッセージの送信に直ちに使用できます postMessage

タブに複数のフレームがある場合、tabs.connect を呼び出すと、 runtime.onConnect イベント(タブ内のフレームごとに 1 回)。同様に runtime.connect が使用された場合、onConnect イベントが複数回(毎回 1 回)発生する可能性があります。 (拡張プロセスの最前線)

接続がいつ閉じられたかを確認する必要がある場合があります。たとえば、個別の 状態を記録します。このために、runtime.Port.onDisconnect イベントをリッスンします。この イベントは、チャネルの反対側に有効なポートがないときに発生します。これは 次のような状況になります。

  • もう一方の端には runtime.onConnect のリスナーがありません。
  • ポートを含むタブがアンロードされた(タブを移動した場合など)。
  • connect が呼び出されたフレームがアンロードされた。
  • runtime.onConnect を介して)ポートを受信したすべてのフレームがアンロードされました。
  • runtime.Port.disconnect相手側によって呼び出されます。なお、connect 呼び出しの結果は 受信側の複数のポートで受信され、これらのポートのいずれかで disconnect() が呼び出された場合、 onDisconnect イベントは送信者のポートでのみ発生し、他のポートでは発生しません。

クロス拡張機能メッセージ

拡張機能のコンポーネント間でメッセージを送信するだけでなく、 他の拡張機能と通信します。これにより、他の Google Cloud サービスと 活用できます。

受信リクエストと接続のリッスンは、内部の場合と似ていますが、 runtime.onMessageExternal メソッドまたは runtime.onConnectExternal メソッド。これが それぞれ:

// For simple requests:
chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.id == blocklistedExtension)
      return;  // don't allow this extension access
    else if (request.getTargetData)
      sendResponse({targetData: targetData});
    else if (request.activateLasers) {
      var success = activateLasers();
      sendResponse({activateLasers: success});
    }
  });

// For long-lived connections:
chrome.runtime.onConnectExternal.addListener(function(port) {
  port.onMessage.addListener(function(msg) {
    // See other examples for sample onMessage handlers.
  });
});

同様に、別の拡張機能にメッセージを送信する方法は、拡張機能内からメッセージを送信する場合と同様です。 唯一の違いは、通信する拡張機能の ID を渡す必要があることです。次に例を示します。

// The ID of the extension we want to talk to.
var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
  function(response) {
    if (targetInRange(response.targetData))
      chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
  }
);

// Start a long-running conversation:
var port = chrome.runtime.connect(laserExtensionId);
port.postMessage(...);

ウェブページからのメッセージの送信

拡張機能間のメッセージと同様に、アプリや拡張機能は ブロックすることもできます。この機能を使用するには、まず manifest.json で 通信を許可するウェブサイトを指定します。例:

"externally_connectable": {
  "matches": ["*://*.example.com/*"]
}

これにより、指定した URL パターンに一致するすべてのページに Messaging API が公開されます。URL パターンには少なくとも第 2 レベルのドメインが含まれている必要があります。つまり、「*」のようなホスト名パターン、 「*.com」、「*.co.uk」、「*.appspot.com」拒否されます。ウェブページで、 runtime.sendMessage API または runtime.connect API を使用して、特定のアプリにメッセージを送信します。 あります。例:

// The ID of the extension we want to talk to.
var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";

// Make a simple request:
chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
  function(response) {
    if (!response.success)
      handleError(url);
  });

アプリや拡張機能では、 runtime.onMessageExternal API または runtime.onConnectExternal API(クロス拡張機能と同様) メッセージ。接続を開始できるのはウェブページのみです。以下に例を示します。

chrome.runtime.onMessageExternal.addListener(
  function(request, sender, sendResponse) {
    if (sender.url == blocklistedWebsite)
      return;  // don't allow this web page access
    if (request.openUrlInEditor)
      openUrl(request.openUrlInEditor);
  });

ネイティブ メッセージング

拡張機能やアプリは、プロバイダとして登録されているネイティブ アプリとメッセージを交換できますネイティブ メッセージング ホスト。この機能について詳しくは、ネイティブ メッセージングをご覧ください。

セキュリティ上の考慮事項

コンテンツ スクリプトの信頼性が低い

拡張機能のバックグラウンド ページ(悪意のあるウェブ ページなど)よりもコンテンツ スクリプトの信頼性が低い コンテンツ スクリプトを実行するレンダラ プロセスに悪影響が及ぶ可能性があります)。仮定 コンテンツ スクリプトからのメッセージは、攻撃者が作成したものである可能性があるため、 すべての入力をサニタイズします。コンテンツ スクリプトに送信されたデータがウェブページに漏洩する可能性があることを想定してください。 コンテンツから受信したメッセージによってトリガーできる特権操作の範囲を制限する 使用できます。

クロスサイト スクリプティング

コンテンツ スクリプトや他の拡張機能からメッセージを受信する場合、スクリプトは慎重に検討する必要があります。 クロスサイト スクリプティングの犠牲にならないようにする必要があります。この推奨事項は、Google Cloud コンソール内で実行されるスクリプトに 他のウェブオリジン内で実行されるコンテンツ スクリプトなど、拡張機能のバックグラウンド ページやコンテンツ スクリプトなど、 特に、次のような危険な API の使用は避けてください。

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be evaluating an evil script!
  var resp = eval("(" + response.farewell + ")");
});
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // WARNING! Might be injecting a malicious script!
  document.getElementById("resp").innerHTML = response.farewell;
});

代わりに、スクリプトを実行しないより安全な API を使用してください。

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // JSON.parse does not evaluate the attacker's scripts.
  var resp = JSON.parse(response.farewell);
});
chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
  // innerText does not let the attacker inject HTML elements.
  document.getElementById("resp").innerText = response.farewell;
});

メッセージを介したコミュニケーションの簡単な例は、examples/api/messaging にあります。 されます。ネイティブ メッセージング サンプルは、Chrome アプリが 提供しますその他の例とソースコードの表示については、サンプルをご覧ください。