runtime.onMessage
このイベントを使って、拡張機能の別の部品からのメッセージを受け取ることができます。
例えば、次のような場面で使います。
- コンテンツスクリプトの中で、バックグラウンドスクリプトからのメッセージを受け取る。
- バックグラウンドスクリプトの中で、コンテンツスクリプトからのメッセージを受け取る。
- オプションページやポップアップのスクリプトの中で、バックグラウンドスクリプトからのメッセージを受け取る。
- バックグラウンドスクリプトの中で、オプションページやポップアップのスクリプトからのメッセージを受け取る。
onMessage()
リスナーに受信させるメッセージを送るには、runtime.sendMessage()
、または (コンテンツスクリプトにメッセージを送るときは)tabs.sendMessage()
を使います。
メモ:同じ種類のメッセージに対するonMessage
リスナーを複数作ることは避けてください。複数のリスナーが実行される順番は保証されていないからです。
特定のリスナーへのメッセージ伝送を保証したいときは、コネクションベースのメッセージを使ってください。
メッセージ本体の他に、リスナーは次のものを受け取ります。
sender
オブジェクト。メッセージ送信側の詳細情報です。sendResponse
関数。送信側への応答を送るために使います。
メッセージに対して同期的に応答するには、sendResponse
関数をリスナーの中で実行します。例を参照してください。
非同期的に応答するには、二つの方法があります。
- イベントリスナーから
true
を返す。こうすることで、リスナーから復帰した後でもsendResponse
関数が有効なままになるため、後で実行することができます。例を参照してください。 - イベントリスナーから
Promise
を返して、応答が準備できた後にそれを解決する (またはエラーの場合は拒否する)。例を参照してください。
メモ:また、コネクションベースのメッセージを使うこともできます。
構文
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
メッセージに対する応答を送るために、最大で一回実行できる関数。この関数は引数を一つ受け取り、それは JSON 化できるオブジェクトのはずです(データクローンアルゴリズムを参照)。その引数はメッセージ送信側に返送されます。
同じ文書中に
onMessage()
リスナーが 2 つ以上ある場合、応答を返すことができるのは 1 つだけです。同期的に応答するには、リスナー関数が復帰する前に
sendResponse()
を実行してください。非同期的に応答するには、次のどちらかを実行します。
sendResponse()
に対する参照を保持したままリスナー関数からtrue
を返す。そうすると、リスナー関数から復帰した後でもsendResponse()
が実行できます。- リスナー関数から
Promise
を返して、応答の準備ができたときにその Promise を解決する。こちらがより好ましい方法です。
リスナー関数は、論理値または
Promise
のいずれかを返します。メモ:
addListener()
に非同期関数を渡すと、リスナーはメッセージを受け取るたびにプロミスを返すため、他のリスナーが応答できなくなります。js// このようにしないでくださいbrowser.runtime.onMessage.addListener(async (data, sender) => { if (data.type === "handle_me") { return "done"; }});
もし、リスナーが特定の種類のメッセージにのみ応答したい場合は、リスナーを
async
ではない関数として定義し、リスナーが応答するメッセージに対してのみプロミスを、それ以外は false または undefined を返してください。jsbrowser.runtime.onMessage.addListener((data, sender) => { if (data.type === "handle_me") { return Promise.resolve("done"); } return false;});
ブラウザーの互換性
例
単純な使用例
次のコンテンツスクリプトは、ウェブページ上のクリックイベントを待ち受けます。リンクがクリックされた場合、対象の URL をバックグラウンドページにメッセージ送信します。
// content-script.jswindow.addEventListener("click", notifyExtension);function notifyExtension(e) { if (e.target.tagName !== "A") { return; } browser.runtime.sendMessage({ url: e.target.href });}
バックグラウンドスクリプトはこのメッセージが送信されるまで待ち、notifications
API を使って通知を表示します。
// background-script.jsbrowser.runtime.onMessage.addListener(notify);function notify(message) { browser.notifications.create({ type: "basic", iconUrl: browser.extension.getURL("link.png"), title: "リンクをクリックしました!", message: message.url, });}
同期的な応答の送信
次のコンテンツスクリプトは、ユーザーがページ上をクリックしたとき、バックグラウンドスクリプトにメッセージを送信します。また、バックグラウンドスクリプトから送信された応答があればログ出力します。
// content-script.jsfunction 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);
これが対応するバックグラウンドスクリプトで、リスナー内部から同期的に応答を返します。
// background-script.jsfunction handleMessage(request, sender, sendResponse) { console.log( `コンテンツスクリプトがメッセージを送信しました: ${request.content}`, ); sendResponse({ response: "バックグラウンドスクリプトからの応答です" });}browser.runtime.onMessage.addListener(handleMessage);
これは同期的に応答を返す別の方法で、Promise.resolve() を使うものです。
// background-script.jsfunction handleMessage(request, sender, sendResponse) { console.log( `コンテンツスクリプトがメッセージを送信しました: ${request.content}`, ); return Promise.resolve({ response: "バックグラウンドスクリプトからの応答です", });}browser.runtime.onMessage.addListener(handleMessage);
sendResponse を使用した非同期の応答の送信
次は直前の例のバックグラウンドスクリプトの別バージョンです。これは、リスナーが復帰した後、非同期的に応答を送ります。リスナーの中のreturn true;
に注目してください。このようにすることで、リスナーが復帰した後にsendResponse
引数を使う意図があることをブラウザーに伝えています。
// background-script.jsfunction handleMessage(request, sender, sendResponse) { console.log( `コンテンツスクリプトがメッセージを送信しました: ${request.content}`, ); setTimeout(() => { sendResponse({ response: "非同期的なバックグラウンドスクリプトからの応答です", }); }, 1000); return true;}browser.runtime.onMessage.addListener(handleMessage);
プロミスを使用した非同期の応答の送信
次のコンテンツスクリプトは、まずページ上の<a>
リンクを取得し、そしてそのリンクの場所がブックマークされているかどうかを尋ねるメッセージを送信します。このスクリプトは、その場所がブックマークされている場合はtrue
を、そうでない場合はfalse
というような、論理型の応答が返ってくることを想定しています。
// content-script.jsconst firstLink = document.querySelector("a");function handleResponse(isBookmarked) { if (isBookmarked) { firstLink.classList.add("bookmarked"); }}browser.runtime .sendMessage({ url: firstLink.href, }) .then(handleResponse);
これが対応するバックグラウンドスクリプトです。
を使うことで、リンクがブックマークされているかを確認するbookmarks.search()
Promise
を返します。
// background-script.jsfunction isBookmarked(message, sender, response) { return browser.bookmarks .search({ url: message.url, }) .then((results) => results.length > 0);}browser.runtime.onMessage.addListener(isBookmarked);
非同期的なハンドラーがプロミスを返さない場合、明示的にプロミスを作ることができます。これは少し不自然な例ですが、setTimeout()
を使って 1 秒の遅延を発生させた後に応答を返します。
// background-script.jsfunction handleMessage(request, sender, sendResponse) { return new Promise((resolve) => { setTimeout(() => { resolve({ response: "非同期的なバックグラウンドスクリプトからの応答です", }); }, 1000); });}browser.runtime.onMessage.addListener(handleMessage);
Example extensions
- beastify
- content-script-register
- cookie-bg-picker
- devtools-panels
- export-helpers
- find-across-tabs
- imagify
- mocha-client-tests
- notify-link-clicks-i18n
- store-collected-images
- user-script-register
- userScripts-mv3
- webpack-modules
メモ:この API は Chromium のchrome.runtime
API. このドキュメントはruntime.json
における Chromium のコードに基づいています。