拡張機能のページ間のユニバーサルメッセージング

こんにちは 今日は、さまざまなブラウザーでの拡張機能の開発を大幅に簡素化できる小さな趣味のプロジェクトを紹介します。 私はすぐに警告したい、これはどこでも同じことをするフレームワークではなく、すべての拡張ページ間の単一の通信方法を編成するライブラリであり、それを使用するには、少なくとも一般的な用語であなたが書くブラウザAPIの操作を理解する必要があります

そして、はい、私はほとんど忘れていました、それはChromeから拡張機能の移植を大いに促進します!



主な機能:

-バックグラウンドページと応答を送信する機能を備えたメッセージング。

-すべてのページに単一のリポジトリ。



はじめに



拡張機能を現在のすべてのブラウザーに移植する必要に直面したとき、すべてがどこでも異なることがわかりました。 また、単一のコードを使用するには、ストレージとページとの対話を統合する軽量のラッパーを作成する必要があります。



クロムAPIに似たものにすべてをもたらしたかったのです。 バックグラウンドページにメッセージを送信して返信できると非常に便利です。 どこにでも単一のリポジトリがあり、任意のページから呼び出すことができる場合に便利です。



一般に、議論されるのはまさにこの統一である。



メッセージングの仕組み



既に述べたように、メッセージングは​​ほとんどChromeに似ていますが、大きな変更はありません。



この図は、拡張ページ間の相互作用のメカニズムを示しています。



挿入されたページ -拡張スクリプトが接続されているページは、バックグラウンドページにのみメッセージを送信し、応答関数を介してのみ応答を受信できます。



ポップアップページ -ポップアップページ。メッセージはバックグラウンドページにのみ送信できます。



オプションページ -拡張機能設定ページ、つまり 拡張機能内のhtmlページは、設定項目(Chromeなど)をクリックすると開き、バックグラウンドページにのみメッセージを送信できます。



バックグラウンドページ -メッセージを送信するときの拡張機能のバックグラウンドページ-メッセージは、ポップアップメニューとオプションページにすぐに届きます。 ただし、Injectedページには届きませんが、アクティブなタブにメッセージを送信できます。

* Firefoxでは、背景ページからポップアップメニューおよびオプションページへの送信は、別のフラグによって有効になります。 この機能はほとんど必要ありません。



また、SafariとFirefoxでは、ポップアップページが一度読み込まれ、常に動作しますが、ChromeとOpera 12では、拡張ボタンをクリックするとページが読み込まれます。



* Firefoxでは、閉じたページまたは非アクティブなページにメッセージを送信できません。



メッセージ受信コード:

mono.onMessage(function onMessage(message, response) { console.log(message); response("> "+message); });
      
      





メッセージ送信コード:

 mono.sendMessage("message", function onResponse(message) { console.log(message); });
      
      





アクティブなタブにメッセージを送信するためのコード(バックグラウンドページからのみ):

 mono.sendMessageToActiveTab("message", function onResponse(message) { console.log(message); });
      
      





一般的に、すべては可能な限りChromeに似ています。



保管



すべてのブラウザで、ストレージは異なります。

Firefox:シンプルストレージ。

Opera:widget.preferences、localStorage。

Chrome:chrome.storage.local、chrome.storage.sync、localStorage。

Safari:localStorage。



ライブラリはストレージインターフェイスを統合します。



リポジトリコード:

 mono.storage.set({a:1}, function onSet(){ console.log("Dune!"); }); mono.storage.get("a", function onGet(storage){ console.log(storage.a); }); mono.storage.clear();
      
      







同期クロムストレージを使用するには、コードの見た目が少し異なり、他のブラウザーではローカルストレージを使用します。

 mono.storage.sync.set({a:1}, function onSet(){ console.log("Dune!"); }); mono.storage.sync.get("a", function onGet(storage){ console.log(storage.a); }); mono.storage.sync.clear();
      
      







仕組み:


リポジトリは次のように機能します。

ブラウザ\ページ バックグラウンド オプション ポップアップ 注入された
クロム localStorage メッセージを介したlocalStorage
Opera 12(localStorage)
サファリ
Chrome(ストレージ) chrome.storage
Firefox シンプルな収納 メッセージを介したシンプルなストレージ
Opera 12 widget.preferences


この表では、「via messages」というプレフィックスが付いているものはすべて、リポジトリがサービスメッセージをバックグラウンドページに送信することで機能することを意味します。もちろん、バックグラウンドページは着信メッセージをリッスンする必要があります。 その他の場合、ストレージの操作は直接です。



拡張機能への接続



Chrome、Safari、Opera 12

mono.jsを拡張機能の各ページに接続する必要があります。



Firefox (Addons-sdkのみ)

ここではすべてが少し複雑です。Addons-sdkの仕組みを知る必要があります。

lib / main.jsでは、requireを介してmonoLib.jsファイルに接続し、background.js(つまり、バックグラウンドページ)と同様に他のすべてのページに接続する必要があります。



テスト拡張機能からmain.jsの例を示します。

main.js
 (function() { var monoLib = require("./monoLib.js"); var ToggleButton = require('sdk/ui/button/toggle').ToggleButton; var panels = require("sdk/panel"); var self = require("sdk/self"); // ,      settingsBtn   -  options.html var simplePrefs = require("sdk/simple-prefs"); simplePrefs.on("settingsBtn", function() { var tabs = require("sdk/tabs"); tabs.open( self.data.url('options.html') ); }); //   port  , .. options.html   mono.js var pageMod = require("sdk/page-mod"); pageMod.PageMod({ include: [ self.data.url('options.html') ], contentScript: '('+monoLib.virtualPort.toString()+')()', contentScriptWhen: 'start', onAttach: function(tab) { monoLib.addPage(tab); } }); //    injected page pageMod.PageMod({ include: [ 'http://example.com/*', 'https://example.com/*' ], contentScriptFile: [ self.data.url("js/mono.js"), self.data.url("js/inject.js") ], contentScriptWhen: 'start', onAttach: function(tab) { monoLib.addPage(tab); } }); //      var button = ToggleButton({ id: "monoTestBtn", label: "Mono test!", icon: { "16": "./icons/icon-16.png" }, onChange: function (state) { if (!state.checked) { return; } popup.show({ position: button }); } }); //     var popup = panels.Panel({ width: 400, height: 250, contentURL: self.data.url("popup.html"), onHide: function () { button.state('window', {checked: false}); } }); //    monoLib * ,   ,    onAttach monoLib.addPage(popup); //   addon    var backgroundPageAddon = monoLib.virtualAddon(); //     monoLib monoLib.addPage(backgroundPageAddon); //   ,   var backgroundPage = require("./background.js"); //   addon   backgroundPage.init(backgroundPageAddon); })();
      
      





しかし、悲しいかな、これだけではありません。 一般的なbackground.jsページはモジュールモードで動作するはずです。 そして、mono.jsを接続する必要があります。



これを行うには、ページの上部に次を追加します。

background.js
 (function() { //     if (typeof window !== 'undefined') return; //  window ( ) window = require('sdk/window/utils').getMostRecentBrowserWindow(); //     ,    window.isModule = true; var self = require('sdk/self'); //     data/js mono = require('toolkit/loader').main(require('toolkit/loader').Loader({ paths: { 'data/': self.data.url('js/') }, name: self.name, prefixURI: self.data.url().match(/([^:]+:\/\/[^/]+\/)/)[1], globals: { console: console, _require: function(path) { //   require   mono.js switch (path) { case 'sdk/simple-storage': return require('sdk/simple-storage'); case 'sdk/window/utils': return require('sdk/window/utils'); case 'sdk/self': return require('sdk/self'); default: console.log('Module not found!', path); } } } }), "data/mono"); })(); var init = function(addon) { if (addon) { mono = mono.init(addon); } console.log("Background page ready!"); } if (window.isModule) { //  ,  init . exports.init = init; } else { //    -  init(); }
      
      





init関数が実行された後、monoに依存する他のすべてを既に実行できます。



*モジュールモードでは、スコープにはウィンドウさえないため、すべてを個別に接続する必要があります。



松葉杖



各ブラウザでネイティブAPIを使用するには、それらを識別する方法が必要です。

ライブラリには、次の変数のリストが用意されています。





ここでは、これらのフラグを使用して、ブラウザーに取り込むAPIを選択できます。



Firefoxのユーティリティ



Firefoxでは、メッセージを送信できるのはページ(モジュールでない場合、つまりバックグラウンドページ)のみです。 そのため、私にとって役立つ多くのサービスを追加しました。



ポップアップウィンドウでメッセージを送信する:

 mono.sendMessage('Hi', function onResponse(message){ console.log("response: "+message); }, "popupWin");
      
      





ポップアップページのサイズ変更:

 mono.sendMessage({action: "resize", width: 300, height: 300}, null, "service");
      
      





新しいタブを開く:

 mono.sendMessage({action: "openTab", url: "http://.../"}, null, "service");
      
      





一般に、コードを見ると、APIとの対話の便宜のために「サービス」を追加することは難しくないと確信しています。



組立



ライブラリは、便宜上複数のファイルに分割されています。 すべてはAntを使用してアセンブルされます。アセンブリファイルは「/ src / vendor / Ant」にあります。 その中で、不要なブラウザを削除できます。



おわりに



ここにそのようなシンプルなライブラリがあります。 もちろん、彼女にはあらゆる種類のバグや欠点があります。 しかし、うまくいくようです。 コードを理解し、自分でファイルを保存する必要がある場所を理解することは難しくないと確信しています。

これらすべてが複雑すぎると思われる場合は、Chrome、Opera 12、Safari、Firefox用に構築されたgitの単純な拡張の例があります。 拡張機能のいくつかでモノを使用していますが、これは私にとって不可欠になりました。



読んでくれてありがとう!



Github



All Articles