Chrome Extensionsをつくっていたところ、
same-origin policy
(同一生成元ポリシー)に阻まれてしまった。具体的にいうと、content_scriptsでとあるサイトの情報をIndexedDBに登録して、他のページでその情報を表示するということがしたかった。
いろいろググってみたところ、chrome.runtime.sendMessage, onMessageというものを使えば実現できるかもしれないと気づいた。
※ Chrome Extensions以外ならpostMessageやJSONPがヒントになるかも
前置きが長くなってしまったが、
chrome.runtime.sendMessage
、chrome.runtime.onMessage
を使ってcontent_scripts - background間で通信する方法をまとめる。manifest.json をつくる
Chrome Extensionsをつくるうえで、最初に必要となるのが「manifest.json」
今回は「Black Everyday Company」を訪れたときに「content_script.js」を実行し、「background.js」と通信するという簡単な拡張機能にする。
// manifest.json
{
"name": "ContentScriptとBackgroundの通信テスト",
"version": "0.0.1",
"manifest_version": 2,
"description": "ContentScriptとBackgroundをsendMessegaやonMessegeで通信できるか確認する",
"background": {
"scripts": ["./background.js"]
},
"content_scripts": [
{
"matches": ["http://kuroeveryday.blogspot.jp/*"],
"js": ["./content_script.js"]
}
]
}
backgroundは実行するjsファイルがひとつの場合でも「”scripts”: [“./hoge.js”]」と書かないとうまく動作しなかった。content_scripts をつくる
ブログ記事のタイトルを取得して、backgroundでデータベースに登録するというような内容。
コールバックは、アラートで表示させるだけ。
// content_script.js
var title = document.getElementsByClassName('post-title entry-title')[0].innerText;
chrome.runtime.sendMessage(
{
type: "add",
value: title
},
function (response) {
if (response) {
alert(response);
}
}
);
chrome.runtime.sendMessage(
{
type: "search",
value: title
},
function (response) {
if (response) {
alert(response);
}
}
);
今回は、例として2回sendMessageでメッセージを送信している。
別に1回でも良いし、条件に合わせて実行する方を決めても良いし、、、
追記:2015/07/03 11:30
sendMessageでメッセージを送信するとき、コールバックを指定しないと
Error in event handler for runtime.onMessage: Error: Attempting to use a disconnected port object
というエラーが出てしまう。onMessageはsendMessageで指定されたコールバックを返すためのものだから、コールバックがないとポートを切断してしまう(らしい)
※ 正式な回答ではなく、個人の見解(以下のリンク参照)
▶ sendMessageにcallbackを指定せずにonMessageのリスナーで非同期レスポンスをするとエラーが発生する - Google グループ
background をつくる
content_script.jsからのリクエストを受信するため、onMessageにイベントリスナーを登録する。
// background.js
chrome.runtime.onMessage.addListener(
function (request, sender, sendResponse) {
switch (request.type) {
case 'add':
add(request.value, sendResponse);
break;
case 'search':
search(request.value, sendResponse);
break;
default:
console.log('typeがわかんないよ');
console.log(request);
break;
}
}
);
function add(value, callback) {
// ここで登録処理
console.log('background:add_' + value);
callback("add:" + value);
}
function search(value, callback) {
// ここで検索処理
console.log('background:search_' + value);
callback("search:" + value);
}
request.typeには 'add' や 'search' が入ってくるので、それを条件に実行するメソッドを変えている。
request : sendMessageの第一引数が渡ってくる(今回は {type, value}ってやつ)
sender : idやurl、tab情報やframeIdが渡ってくる
sendResponse : sendMessageの第二引数のコールバックが渡ってくる
実行してみる
ここまでにつくった「manifest.json」「content_script.js」「background.js」をひとつのフォルダにまとめて、Chromeの拡張機能から「パッケージ化されていない拡張機能を読み込む」で読み込ませる。
そして、「ビューを検証」のバックグラウンドページのリンクをクリックして、開発者ツールを立ちあげておく。
「Black Everyday Company」のサイトに移動すると、以下のようなアラートが2回表示される。
このアラートは、content_script.jsで指定したコールバックによるもの。
バックグラウンドページのコンソールを確認すると、以下のようなログが表示される。
このログは、background.jsで実行された関数によるもの。
こんなかんじで、content_scriptsとbackground間で通信することができる。
本来の目的である「とあるサイトの情報をIndexedDBに登録して、他のページでデータを参照できるかどうか」は、投稿するかわからないが、実装できたら紹介する予定。
参考サイト
- Message Passing - Google Chrome
- chrome.runtime.sendMessage - Google Chrome
- chrome.runtime.onMessage - Google Chrome
以上
written by @bc_rikko
0 件のコメント :
コメントを投稿