拡張間連携とEvent Driven JavaScript


click this and start slide

X / _ / X : SlideSwitch


拡張間連携とEvent Driven JS



Yusuke Suzuki

id:Constellation

自己紹介

  • Taberareloo
  • LDRFullFeed
  • ChromeFullFeed

れんけい!!

Chromeの拡張は連携ができる!!

Chrome拡張間連携

拡張間で連携できるAPIがある

受信側

chrome.extension.onConnectExternal
chrome.extension.onRequestExternal

送信側

chrome.extension.sendRequest
chrome.extension.connect

Background間の連携

background page同士で連携ができる. => 夢が広がる

用意しなくてもmigemoできる.

Key用EventListenerをいくつも引っ掛けるのは無駄

問題点

backgroundだけ?

content script間の連携

content script領域はそれぞれ別に分かれていて,

(IsolatedWorld参照)

Greasemonkeyのようにwindowが共有されてない

できるかなって 拡張連携

じゃあできないの?

できます.

Event Driven JS

Eventを使えばいける!

もともとEvent Drivenなやり方はcontentWindowがないChrome Extensionにおいて使われてきた.

独自のEventを定義して, Event の Dispatchを使って拡張同士がcontent script領域でやりとり

content scriptでのcontentWindow

content scriptからcontentWindowが消えた…

  • javascript: urlによる実行
  • script要素をpageにappend

結果を受け取りたかったらどうするの…

=> Event

MessageEvent

MessageEventを使えば, JSONにシリアライズ可能なデータをやり取り出来る

例によってnanto_viさんのblogを

Greasemonkey スクリプトとイベントで通信: Days on the Moon

送信側

ChromeFullFeedから抜粋

page上で実行されるscript(content scriptじゃなくて, script要素で作ったもの)

// event作成
var ev = document.createEvent('MessageEvent');
// text dataを載せて
ev.initMessageEvent('LDRFullFeed.load', true, false, text, location.protocol+"//"+location.host, "", window);
// container(DOM Element)からdispatch
container.dispatchEvent(ev);

MessageEventとstructured clone

ちなみに, Chrome 5からはMessageEventのdataに文字列以外(JSのObjectなど)が自動でcloneされて入るようになり, JSON.stringifyとJSON.parseの手間がなくなる. (structured clone)

http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#safe-passing-of-structured-data

受信側

window.addEventListener('LDRFullFeed.load', function(ev){
  // eventを受け取り
  // JSON.parse(ev.data)してobjectに変換
  // containerからdispatchしておくと,
  // ev.targetから対象のDOM Elementも送り付けられる
  fullfeed(JSON.parse(ev.data), ev.target);
}, false);

注意

eventのpropertyは, 通常のもの以外content script領域に入ったら見ることができません.

// event作成
var ev = document.createEvent('Event');
// text dataを載せて
ev.initEvent('LDRFullFeed.load', true, false);
// propertyに入れて
ev.text = text
document.body.dispatchEvent(ev);

この時のev.textはcontent scriptからじゃ見れない.

そのためにMessageEventをつかう.

Content Script上での連携

これを拡張間連携で使う

例: ChromeKeyConfig

ChromeKeyConfigにあらかじめbackground pageから呼び出して欲しいeventを登録する.

これのおかげでChromeKeyConfig上にTaberarelooのメニューがでてる.

実例(Taberareloo)

var CHROME_GESTURES = 'jpkfjicglakibpenojifdiepckckakgk';
var CHROME_KEYCONFIG = 'okneonigbfnolfkmfgjmaeniipdjkgkl';
var REGISTER = {
  'CHROME_GESTURES' : false,
  'CHROME_KEYCONFIG': false
};
var action = {
  group:'Taberareloo',
  actions:[
    {name:'Taberareloo.link'},
    {name:'Taberareloo.quote'},
    {name:'Taberareloo.general'}
  ]
};
chrome.extension.sendRequest(CHROME_GESTURES, action, function(res){
  REGISTER['CHROME_GESTURES'] = true;
});
chrome.extension.sendRequest(CHROME_KEYCONFIG, action, function(res){
  REGISTER['CHROME_KEYCONFIG'] = true;
});

Content Scriptでは

先程登録したEventをlistenする.

window.addEventListener('Taberareloo.link', TBRL.link, false);
window.addEventListener('Taberareloo.quote', TBRL.quote, false);
window.addEventListener('Taberareloo.general', TBRL.general, false);

このEventがChromeKeyConfigから登録されたキーが入力されるとdispatchされるので, あとはそれをこちら側で処理すればいい.

MessageEventなので, ev.dataには向こうから情報をこちらに送ってくることができる!!

まとめ

  • ChromeはIsolatedWorldで区切られた拡張の中で連携できる
    • クリーンな連携. 拡張同士のバッティングが起きにくい
  • sendRequestでbackground同士で拡張間連携ができる
    • IsolatedWorldで区切られているので, メッセージベースの非同期な連携
    • 同じ機能を持った拡張なんていくつもいらない
    • 協調行動
  • MessageEventを使ってEvent DrivenなJS
    • content scriptとcontentWindow (GM風に言うとunsafeWindow)を行き来できる
    • 拡張間で非同期な連携ができる

終わり

ありがとうございました

2 years ago
  1. innervisions reblogged this from otsune
  2. lagash reblogged this from syanaash
  3. syanaash reblogged this from otsune
  4. stardance reblogged this from otsune
  5. ukar reblogged this from otsune
  6. nashi-kyo reblogged this from otsune
  7. otsune reblogged this from utatane-constellation
  8. laclefyoshi reblogged this from utatane-constellation
  9. utatane-constellation posted this