Safari 拡張機能における通信


やたらにはまったので,一応,動いているところまでをメモしておきます.

以下のコードは,Safari 拡張のグローバルHTMLとinjectedコードで共通に実行されるものです.同じコードを別々の名前空間で実行しているので,いずれで実行しているのかを判定する必要があります.素直な方法があるといいのですが,わからなかったので,以下の怪しげな方法を用いています.

 var is_injected = typeof(safari.application) === 'undefined';

次に,メッセージを受信するための設定.ここでは,ev.name に応じて,handler で処理を分配しています.このコードで唯一,handler に登録された処理は ‘alert’ です.文字通り,画面にメッセージの内容を表示してから,グローバルコードの場合だけ,injected コードに返事をしています.

 var handler = {};
 ((is_injected ? safari.self : safari.application)
   .addEventListener('message', function (ev) {
         if (ev.name === 'alert') do_alert(ev);
     }, false));

 handler.alert = function (ev) {
   alert(ev.message);
   if (!is_injected)
     ev.target.page.dispatchMessage('alert', 'Hello from global code.');
 };

以下は送信部です.送信するときは,ウェブページのプロクシオブジェクトを用います.グローバルコードの場合は,アクティブタブに向って送信するためのプロクシを選択していますが,場合によってはアクティブなものがないことがある点は要注意です.この例では,グローバルコードはinjectedコードへ返信する以外にメッセージの送信をしていません.

 function proxy() {
   return (is_injected ?
     safari.self.tab : safari.application.activeBrowserWindow.activeTab.page);
 }

以下はinjectedコードから,メッセージを送信するコードです.

 function start_injected_code() {
   proxy().dispatchMessage('alert', 'Hello from injected code.');
 }

 if (is_injected) $(start_injected_code);

ブログを書くのもいいものですね.例題の説明を書いているうちに,無駄なコードを除去して,二割くらい短くなりました.