Chrome拡張機能には大きく分けて「Content Scripts」、「popup」、「background」の3つで構成されている。

それぞれ使える機能に制限があり、chrome.runtime.sendMessage, chrome.tabs.sendMessage, chrome.runtime.onMessage.addListenerを使って相互に通信して連帯することが必要。

Content Scriptを呼び出す

Content Scriptはユーザーが開いているタブの一つ一つで稼働しているから、どのタブを呼び出すか決めて狙い撃ちしないと行けない。

送信側(background, popup)

var send_data = { type: 'fugafuga', data: 'hogehoge' };
chrome.tabs.query({ active: true, currentWindow: true }, aim_message);
function aim_message(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, send_data);
}

まず送信するデータ(send_data)を決める。

次の「chrome.tabs.query」は、開かれているタブの情報を取得するためのメソッド。
第一引数は設定値。ココでは開かれているウィンドウかつアクティブになっているタブを指定している。
第二引数は取得が終わった後に自動的に呼ぶための関数。
ここでは設定値「aim_message」を指定している。

システムがタブを調べ終わり次第、aim_messageが呼ばれる。引数にはさっき設定した条件に合うタブ情報が配列で格納されている。

chrome.tabs.sendMessageは指定したタブにリクエストを送るメソッド。
第一引数は送信するタブのID。tabsは配列なので、0番目の要素を指定する。
第二引数は送信する情報(自由に決めて可)。

ちなみにpopupはユーザーがアイコンをクリックした瞬間にhtmlが読み込まれる。あと引数を指定する時にaim_message()とかやらないように。これするとaim_message関数の返り値が引数になってしまう。

受信側(Content Script)

chrome.runtime.onMessage.addListener((request, sender) => {
    console.log('呼び出されたわ!受信したデータは', request.data);
    //何かの処理
});
//出力:呼び出されたわ!受信したデータは hogehoge

第一引は送信時のデータ。

callbackを利用する方法

chrome.tabs.sendMessageの第三引数に関数を指定する。

var send_data = { type: 'say-hello', data: 'hoge' };
chrome.tabs.query({ active: true, currentWindow: true }, aim_message);
function aim_message(tabs) {
  chrome.tabs.sendMessage(tabs[0].id, send_data, callback);
}
function callback(text) {
  alert(text);
}

受信側の第三引数にその関数が格納される。

chrome.runtime.onMessage.addListener((request, sender, callback) => {
  console.log('呼び出されたわ!受信したデータは', request.data);
  callback('終わったわよ');
  //何かの処理
  return true;
});

こうすれば、popupでcallback(‘終わったわよ’);と実行したことのようになる。

また「何かの処理」の時に非同期処理をしていて、それを待たないといけない場合はreturn trueをする。

backgroundを呼び出す

送信側(background, popup, content script)

これは一文でできる。chrome.runtime.sendMessageの第一引数に送信したいデータを指定する。

var send_data = {type: 'fugafuga', data:'hoge'};
chrome.runtime.sendMessage(send_data);

ただ、受け取り場所を複数設定している場合でも無差別にデータを送信するので、受け取り場所で判別したほうが良い。

受信側(background)

chrome.runtime.onMessage.addListener((request, sender) => {
	if(request.type == 'fugafuga'){//ここで判別
		console.log('hello');
		return true;
	}
});

所感

プログレスバーをpopupに積んで、popupを呼び出すこともやろうと思ったが、考えてみたらpopupはアクティブでないと受信できないしそれもすぐ閉じちゃうしで意味がないと思いやめた。