Google Chromeブラウザーの拡張機能を開発する際のサンドボックスの概念

Google Chromeブラウザーの拡張機能を開発してきた5年間で、いくつかの経験が蓄積されており、一連の記事で共有し、可能であれば、微妙さ、落とし穴のいくつかを説明し、最新のフロントエンドテクノロジーがどのようにうまく適用されたかについて説明したいと思います。



パート1



はじめに



Amazonストアフロントから商品を積極的に購入していた2012年に、Google Chromeブラウザーの拡張機能に遭遇しました。ロシア連邦に商品を配送し、配送費用を考慮して最も収益性の高い販売者を探すのは非常に不便でした。 ここで、私は自分自身と他の顧客にとっても楽になるように、「Amazonがあなたに出荷する」拡張機能を作成することにしました 。 時間が経つにつれて、それは無関係になりました、なぜなら 数年後、通常のフィルターがAmazonのディスプレイウィンドウで作成され、出版物から削除しました。



それから、 Y.MuzykY.Radioのサービスを使用する時が来ました。Y.Muzykiがバックグラウンドタブでプレイしているとき、少なくともホットキーを使ってプレイするとき、私は本当にプレーヤーコントロールを欠いていました。 その結果、経験豊富な人として、アナログを見つけられなかったため、 Yandexから公式の拡張にもかかわらず、このための拡張機能「Yandex.Music-player control」を作成することにしました。



読者は、拡張要素の基本構造( manifest.json背景ページコンテンツスクリプトpopup )に既に精通している必要があります。 以下のネタバレの下での簡単な教育プログラム。



延長で好き
拡張機能は、ブラウザの機能を拡張するソフトウェアパッケージです。 公式のChrome Web Storeから配布されているchrome:// extensions / pageで開発者モードでローカル拡張機能をダウンロードすることもできますが、Googleはネジを締めることでますます苦労しています。



以前は、問題なくローカル拡張機能を使用することが可能でしたが、その後、ブラウザーはそのような拡張機能の存在を通知し始めましたが、ブラウザーの起動時に同様の拡張機能がデフォルトでオフになり、手動でアクティブ化する必要があります(アクティブな開発で拡張機能の開発者を悩ませました)。





すべての拡張メタデータはマニフェストに記述されていますが、それについて特別なことは何もありません。すべてはドキュメントに記述されています



拡張機能は、バックグラウンドページ( バックグラウンドページまたはイベントページ )、 ポップアップウィンドウ設定ページ 、ターゲットサイトに埋め込まれたコンテンツスクリプト 、および標準ブラウザーページを上書きする特定のオーバーライドページ(履歴、ブックマークマネージャー、新しいページなど)で構成されます。



UIの観点から見ると、拡張機能にはbrowserAction (またはpageAction )要素(アドレスバーの右側にあるブラウザパネルのアイコン)が含まれています。これをクリックすると、アクションを開始したり、別のUI要素を開くことができます(ポップアップウィンドウ) 。 また、このアイコンには、 バッジ 、たとえば未読メッセージの数を示すアイコンを表示できます。



ブラウザはさまざまなニーズに対応する複数のAPIを備えた拡張機能を提供します。たとえば、 chrome.tabs APIを使用すると、すべてのタブにアクセスしたり、新しいタブを閉じたり、開いたり、タブのメタデータを表示したりできます。



さらに、さまざまな拡張ページ間に特定のデータ転送メカニズムがあります。



サンドボックス



典型的な拡張タスクは、特定のサイトの機能を拡張することです。そのためには、ランディングページにコードを埋め込む必要があります。 Ya.Muzykuを例に挙げます(以下):ポップアップ拡張ウィンドウ(スクリーンショット1を参照)でサイトのプレーヤーを制御するには、ページの開始を追跡し、コードを埋め込みます。コードとDOMがショーケースを表示し、拡張機能へのすべての変更を転送するため、ポップアップウィンドウを開いたときに、常にショーケースにプレーヤーの現在の状態が表示されます。 これは、私が始めたい重要なものが現れる場所であり、そのセクションの名前はサンドボックスです。



画像

(スクリーンショット番号1)



メインの拡張コントローラーであるバックグラウンド拡張ページは、適切な拡張機能( tabs、activeTab )がある場合、 chrome.tabs.onUpdatedを使用してmusic.yandex.ruページの開始を追跡し、 chrome.tabs.executeScript介してコード(コンテンツスクリプト)をウィンドウに埋め込むことができます 。 ただし、埋め込みコードはサンドボックス(B)にあり、そこからストアフロントDOMドキュメントにアクセスできますが、サンドボックス(A)で実行されるストアフロントjs-codeにはアクセスできません。 理論的には、ウィンドウ上のDOM要素の変更を追跡して現在の状態を拡張機能に変換することは可能ですが(たとえば、トラックが変更されました-DOMからトラックの名前を取得します)、これは希望どおりに機能しません:ウィンドウの更新の遅延ではなく、ストアフロントの現在のディスプレイや、エクステンションを実際に使用しているときにストアフロントとエクステンションのディスプレイ間でデータの同期が取れないその他のものに、常にターゲットDOM要素を提示します。 ショーケースjsコード(サンドボックスA)にアクセスするにはどうすればよいですか?



画像






コンテンツスクリプトからサンドボックスAにjs-codeを埋め込むには、次の「ハック」が役立ちます(以降、es6表記)。



function injectCode(func, ...args) { let script = document.createElement('script'); script.textContent = 'try {(' + func + ')(' + args + '); } catch(e) {console.error("injected error", e);};'; (document.head || document.documentElement).appendChild(script); script.parentNode.removeChild(script); }
      
      





その結果、コンテンツスクリプトは、ショーケースAPIにアクセスするためにコードをショーケースjs-codeのサンドボックスに埋め込み、低レベルでプレーヤー、プレイリスト、その他のショーケースエンティティのオブジェクトとイベントにアクセスできます。 ただし、それだけではありません。たとえば、埋め込みコードがトラックの再生を開始したイベントを「キャッチ」しましたが、どのようにコンテンツスクリプトに送り返すことができますか?コンテンツスクリプトには、拡張機能のバックグラウンドページにデータを転送するメカニズムがあります?



画像






残念ながら、サンドボックスAからサンドボックスBへのアクセスはありません。いずれにしても、私には不明です。 しかし、これは恐ろしいことではありません。サンドボックスBのコンテンツスクリプトがストアフロントのDOMドキュメントにアクセスできることを覚えているからです。したがって、出力:サンドボックスAに埋め込まれたコードは任意のイベントを作成できます。



 document.dispatchEvent(new CustomEvent(CUSTOM_EVENT_NAME, {detail: payload}));
      
      





そして、コンテンツスクリプトはそれらをキャッチできます。



 document.addEventListener(CUSTOM_EVENT_NAME, e => { console.log(e.detail); //payload });
      
      





次のスキームが判明します。



画像






その後、コンテンツスクリプトは、 chrome.runtime.sendMessageまたはchrome.runtime.connectの いずれかのメカニズムを使用してこのイベントをバックグラウンドページに渡します。 それらの違いは、最初のメソッドはチャネルを開き、データを送信し、チャネルを閉じ、2番目のメソッドはデータが送信される永続的なチャネルを作成することです。 トラックを再生するとき、進行状況イベントは常に送信されています(現在の再生時間)。したがって、選択は明白になりました:コンテンツスクリプトとバックグラウンドページ間の通信の一定のチャネルを上げることで、明らかではない別のボーナスを提供します:さまざまな理由によるショーケースとの接続の喪失の制御タブを閉じる前のjsコードの例外(ただし、タブを閉じることはchrome.tabs.onRemovedで簡単に追跡できます )。



これらのサンドボックスは完成しましたが、それだけではありません。背景ページのサンドボックス(B)とポップアップウィンドウのサンドボックス(G)がまだあります。 ここではすべてが少しシンプルになり、これらのサンドボックスはAPIを介して相互にアクセスできます。





ただし、落とし穴があります。たとえば、ポップアップウィンドウはイベントリスナーをバックグラウンドページに追加できませんが、上記のメソッドは(同じスレッドで実行されているため)互いにウィンドウオブジェクトにアクセスできます。 相互通信の均一性と、ポップアップウィンドウコードからのバックグラウンドページコードの強制的な分離のために(そうでない場合、ポップアップはbgオブジェクトを変更し、コンテンツスクリプトからバックグラウンドページへの一方向のデータストリームを中断し、現在の状態をそこからポップアップウィンドウに保存します)、同じに切り替えましたチャンネルを上げるだけでなく、コンテンツスクリプトとバックグラウンドページの間で。



コードと例が少ないのは、 すべてはドキュメントにあります。メソッドとAPIについては可能な限り言及しますが、コードに関しては、ここに追加するものはありません。 チュートリアルステータスのふりをしません(コード全体をコピーして何かを獲得できる場合)。 しかし、コンセプト自体は噛む価値がありました。 プログラマーワークショップで同僚に繰り返し説明しました。 このセクションは次のように要約できます。



画像






次のパートでは、拡張機能「Yandex.Music-player control」の 、現在人気のあるReact + Reduxへの翻訳の履歴について説明します。これは、ポップアップ拡張ウィンドウにプレーヤーのステータスを表示するのに適していました。



All Articles