このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。

View in English Always switch to English

runtime.onMessage

このイベントを使って、拡張機能の別の部品からのメッセージを受け取ることができます。

例えば、次のような場面で使います。

  • コンテンツスクリプトの中で、 バックグラウンドスクリプトからのメッセージを受け取る。
  • バックグラウンドスクリプトの中で、コンテンツスクリプトからのメッセージを受け取る。
  • オプションページまたはポップアップのスクリプトの中で、バックグラウンドスクリプトからのメッセージを受け取る。
  • バックグラウンドスクリプトの中で、オプションページやポップアップのスクリプトからのメッセージを受け取る。
  • **拡張機能ページ**内のスクリプトで、ページ内のスクリプトでのコード実行をリクエストするメッセージを待ち受けします。

onMessage() リスナーに受信させるメッセージを送るには、runtime.sendMessage()、または (コンテンツスクリプトにメッセージを送るときは) tabs.sendMessage() を使います。

メモ: 同じ種類のメッセージに対する onMessage() リスナーを複数作ることは避けてください。複数のリスナーが実行される順番は保証されていないからです。

特定のエンドポイントへのメッセージ配信を保証したいときは、メッセージ交換のコネクションベースのアプローチを使ってください。

メッセージ本体の他に、リスナーは次のものを受け取ります。

  • sender オブジェクト。メッセージ送信側の詳細情報です。
  • sendResponse 関数。送信側への応答を送るために使います。

メッセージに対して同期的に応答するには、sendResponse 関数をリスナーの中で実行します。同期的な応答の送信の例を参照してください。

非同期に応答するには、二つの方法があります。

メモ: また、コネクションベースのメッセージを使うこともできます。

構文

js
browser.runtime.onMessage.addListener(listener)
browser.runtime.onMessage.removeListener(listener)
browser.runtime.onMessage.hasListener(listener)

イベントには 3 つの関数があります。

addListener(listener)

リスナーをこのイベントに追加する。

removeListener(listener)

このイベントの受け取りを中止する。listener 引数は削除するリスナーです。

hasListener(listener)

リスナーがこのイベントに登録されているかどうかを確認する。登録されている場合は true を、そうでない場合は false を返す。

addListener の構文

引数

listener

このイベントが発生した際に呼び出される関数です。この関数には、以下の引数が渡されます。

message

object 型。メッセージです。これは JSON 化できるオブジェクトです(データクローンアルゴリズムを参照)。

sender

runtime.MessageSender オブジェクト。メッセージの送信側を表します。

sendResponse

message に対して応答を返すために、最大 1 回呼び出される関数です。この関数は 1 つの引数を受け取ります。その引数は、シリアライズ可能な任意のオブジェクトです(データ複製アルゴリズムを参照してください)。この引数は、メッセージの送信者に渡されます。

同じ文書中に onMessage() リスナーが 2 つ以上ある場合、応答を返すことができるのは 1 つだけです。

同期的に応答するには、リスナー関数が復帰する前に sendResponse() を実行してください。

非同期的に応答するには、次のどちらかを実行します。

  • リスナー関数から Promise を返して、応答の準備ができたときにそのプロミスを解決する。こちらがより好ましい方法です。

  • sendResponse() に対する参照を保持したままリスナー関数から true を返す。そうすると、リスナー関数から復帰した後でも sendResponse() が実行できます。

    メモ: Chrome バグ 1185241 が解決されるまで、Chrome では返値としての Promise は対応していません。代替手段として、true を返して sendResponse を使用してください

リスナー関数は、論理値または Promise のいずれかを返します。

メモ: addListener() に非同期関数を渡すと、リスナーはメッセージを受け取るたびにプロミスを返すため、他のリスナーが応答できなくなります。

js
// このようにしないでください
browser.runtime.onMessage.addListener(async (data, sender) => {
  if (data.type === "handle_me") {
    return "done";
  }
});

リスナーに特定の種類のメッセージに対してのみ反応させたい場合を想定しましょう。その場合、リスナーを非 async 関数として定義し、リスナーが反応すべきメッセージに対してのみプロミスを返し、それ以外の場合は false または undefined を返す必要があります。

js
browser.runtime.onMessage.addListener((data, sender) => {
  if (data.type === "handle_me") {
    return Promise.resolve("done");
  }
  return false;
});

単純な使用例

次のコンテンツスクリプトは、ウェブページ上のクリックイベントを待ち受けます。リンクがクリックされた場合、対象の URL をバックグラウンドページにメッセージ送信します。

js
// content-script.js

window.addEventListener("click", notifyExtension);

function notifyExtension(e) {
  if (e.target.tagName !== "A") {
    return;
  }
  browser.runtime.sendMessage({ url: e.target.href });
}

バックグラウンドスクリプトはこのメッセージが送信されるまで待ち、 notifications API を使って通知を表示します。

js
// background-script.js

browser.runtime.onMessage.addListener(notify);

function notify(message) {
  browser.notifications.create({
    type: "basic",
    iconUrl: browser.runtime.getURL("link.png"),
    title: "リンクをクリックしました!",
    message: message.url,
  });
}

同期的な応答の送信

次のコンテンツスクリプトは、ユーザーがページ上をクリックしたとき、バックグラウンドスクリプトにメッセージを送信します。また、バックグラウンドスクリプトから送信された応答があればログ出力します。

js
// content-script.js

function handleResponse(message) {
  console.log(`バックグラウンドスクリプトが応答しました: ${message.response}`);
}

function handleError(error) {
  console.log(`Error: ${error}`);
}

function sendMessage(e) {
  const sending = browser.runtime.sendMessage({
    content: "コンテンツスクリプトからのメッセージです",
  });
  sending.then(handleResponse, handleError);
}

window.addEventListener("click", sendMessage);

これが対応するバックグラウンドスクリプトで、リスナー内部から同期的に応答を返します。

js
// background-script.js

function handleMessage(request, sender, sendResponse) {
  console.log(
    `コンテンツスクリプトがメッセージを送信しました: ${request.content}`,
  );
  sendResponse({ response: "バックグラウンドスクリプトからの応答です" });
}

browser.runtime.onMessage.addListener(handleMessage);

これは同期的に応答を返す別の方法で、Promise.resolve() を使うものです。

js
// background-script.js

function handleMessage(request, sender, sendResponse) {
  console.log(
    `コンテンツスクリプトがメッセージを送信しました: ${request.content}`,
  );
  return Promise.resolve({
    response: "バックグラウンドスクリプトからの応答です",
  });
}

browser.runtime.onMessage.addListener(handleMessage);

sendResponse を使用した非同期の応答の送信

次は直前の例のバックグラウンドスクリプトの別バージョンです。これは、リスナーが復帰した後、非同期的に応答を送ります。リスナーの中の return true; に注目してください。このようにすることで、リスナーが復帰した後に sendResponse 引数を使う意図があることをブラウザーに伝えています。

js
// background-script.js

function handleMessage(request, sender, sendResponse) {
  console.log(
    `コンテンツスクリプトがメッセージを送信しました: ${request.content}`,
  );
  setTimeout(() => {
    sendResponse({
      response: "非同期的なバックグラウンドスクリプトからの応答です",
    });
  }, 1000);
  return true;
}

browser.runtime.onMessage.addListener(handleMessage);

警告: 関数の先頭に async を付けないでください。async を付けると、その意味がプロミスを使用した非同期の応答の送信に変更され、実質的に sendResponse(true) と同じ動作になります。

プロミスを使用した非同期の応答の送信

メモ: Chrome バグ 1185241 が解決されるまで、Chrome では返値としての Promise は対応していません。代替手段として、true を返して sendResponse を使用してください

次のコンテンツスクリプトは、まずページ上の <a> リンクを取得し、そしてそのリンクの場所がブックマークされているかどうかを尋ねるメッセージを送信します。このスクリプトは、その場所がブックマークされている場合は true を、そうでない場合は false というような、論理型の応答が返ってくることを想定しています。

js
// content-script.js

const firstLink = document.querySelector("a");

function handleResponse(isBookmarked) {
  if (isBookmarked) {
    firstLink.classList.add("bookmarked");
  }
}

browser.runtime
  .sendMessage({
    url: firstLink.href,
  })
  .then(handleResponse);

これが対応するバックグラウンドスクリプトです。bookmarks.search() を使うことで、リンクがブックマークされているかを確認する Promise を返します。

js
// background-script.js

function isBookmarked(message, sender, response) {
  return browser.bookmarks
    .search({
      url: message.url,
    })
    .then((results) => results.length > 0);
}

browser.runtime.onMessage.addListener(isBookmarked);

非同期的なハンドラーがプロミスを返さない場合、明示的にプロミスを作ることができます。これは少し不自然な例ですが、setTimeout() を使って 1 秒の遅延を発生させた後に応答を返します。

js
// background-script.js

function handleMessage(request, sender, sendResponse) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        response: "非同期的なバックグラウンドスクリプトからの応答です",
      });
    }, 1000);
  });
}

browser.runtime.onMessage.addListener(handleMessage);

Example extensions

ブラウザーの互換性

メモ: この API は Chromium の chrome.runtime API に基づいています。このドキュメントは runtime.json における Chromium のコードから派生しています。