独自のブラウザー拡張機能を作成する: 第 2 回、Firefox を拡張する

Firefox 用のベーシックなブラウザー拡張機能を作成する

どのブラウザーにも、それぞれに固有の長所と短所があり、支持する人もいれば、批判する人もいます。そのなかで、すべてのブラウザーに共通して言えることは、人々がブラウザーで費やす時間がますます増えているということです。この連載では、Chrome、Firefox、および Safari のベーシックな拡張機能を作成する方法を調べていきます。それによって、それぞれのブラウザーを拡張する作業とはどのようなものなのか、また共通して必要となる作業の難易度はどの程度なのか、さらには拡張機能をどのように配布するのか、といったことを学びます。今回の記事で作成するのは、Firefox の拡張機能です。

Duane O'Brien, Software developer, Freelance

Ảnh của Duane O'BrienDuane O'Brien は、へとへとに疲れたコンピューター・サイエンティストです。これまで、Web アプリケーションの開発やさまざまな PHP フレームワークに関する多数の記事を書いています。Duane についての詳細は、彼のブログツイートを調べてください。



2013年 7月 18日

この連載について

この全 4 回からなる連載では、3 つのブラウザー (Chrome、Firefox、Safari) を対象に Gawkblocker と名付けた拡張機能を作成します。

  • 第 1 回では、Google Chrome の拡張機能を作成するところから、Chrome ウェブストアに配置するまでのプロセスを説明しています。
  • 今回の記事では、Mozilla Firefox 用のアドオン (拡張機能) を作成します。
  • 第 3 回では、この拡張機能を Safari ブラウザー用に調整します。
  • 第 4 回では、作成したコードを特定のブラウザーに依存しないように微調整します。

この記事は、全 4 回にわたってブラウザーの拡張機能を作成する方法を説明する連載の第 2 回として、Mozilla Firefox 用のアドオン (拡張機能) を作成する方法を説明します。「独自のブラウザー拡張機能を作成する: 第 1 回、Chrome を拡張する」では、Gawkblocker と名付けた Chrome の拡張機能を作成しました。今回の記事では、Chrome の拡張機能である Gawkblocker を Firefox に移植します (完全なソース・コードを入手するには、「ダウンロード」を参照してください)。

Gawkblocker の復習

Gawkblocker は、ユーザーがアクセスしたくない特定のドメイン (例えば、表示に時間のかかるブログなど) をブロックできるようにするための拡張機能です。Gawkblocker には以下のコンポーネントがあります。

  • ポップアップ・ウィンドウ (ブロック中のサイトを表示)
  • ブラウザーに表示されるアイコン (この拡張機能のエントリー・ポイント)
  • オプション選択ページ (ブロックするドメインと、リダイレクト先を構成するページ)

Chrome での Gawkblocker 拡張機能は、個々のタブまたはウィンドウにリスナーをアタッチし、URL をブロック対象のドメイン・リストと突き合わせます。そして、URL がブロック対象のドメインと一致する場合には、リクエストをローカル・ページにリダイレクトします。今回は、この Gawkblocker 拡張機能を Firefox 用に作成すると、どのように変わるのかを学びます。

Gawkblocker は、特定の方法でブラウザー内部に入り込み、この連載で作成するすべての拡張機能で実行することになる処理を行います。今回も第 1 回と同じく、皆さんは以下の質問に回答する必要があります。

  • ブラウザーの UI のどこかにその拡張機能の存在を示すようにする難易度はどの程度か?
  • ブラウザーのセッション間でデータを保持するために必要なものは何か?
  • 拡張機能を構成するコンポーネント同士はどのような方法でやりとりするのか?
  • ユーザーのデータのどこまでアクセスできるようにするのか?

Firefox 用の Gawkblocker を作成するプロセスを完了すると、以上の質問の答えが見つかるはずです。


始める前に

アドオンとは拡張機能のことです

Firefox の拡張機能は、「アドオン」と呼ばれています。拡張機能を表す言葉として、Chrome では「拡張機能」を、Safari では「機能拡張」を、Internet Explorer では「アドオン」を用いています。この連載では、これらの言葉を同じ意味で使用します。

この記事の説明に従うには、Firefox バージョン 12 以降 (「参考文献」を参照) をダウンロードしてインストールしてください (この記事で使用するサンプル・コードは、バージョン 12 をベースとしています)。また、HTML、CSS、および JavaScript を編集するためのツールも必要です。Firefox や何らかの Firefox アドオンを使用した経験があると、この記事を理解するのに役立ちます。そのような経験がない場合は、Mozilla による Firefox アドオンのページ (「参考文献」を参照) で入手可能な拡張機能をブラウズして、この記事のコンテキストに沿った拡張機能をいくつか試してみてください。

参考になるドキュメントは、Mozilla Add-on SDK の開発者向けガイドです (「参考文献」を参照)。作業のほとんどは、Add-on Builder で行います。Add-on Builder は、Firefox の拡張機能を作成するための Web ベースのツールです。Add-on Builder は、Firefox プロジェクトの 1 つである Jetpack の一部となっています。Jetpack の目的は、(Chrome 拡張機能を作成したときと同じく) HTML、CSS、JavaScript だけを使って簡単に拡張機能の作成を開始できるようにすることです。Firefox の拡張機能を作成する方法には、この記事で説明する以外の方法もあります。

完全なソース・コードを入手するには、「ダウンロード」を参照してください。


Firefox 拡張機能の構成内容

Firefox 拡張機能を作成する、その他の方法

この記事で説明するプロセスの他にも、Firefox の拡張機能を作成する方法がいくつかあります。Add-on Builder が使用する SDK ファイルは、Developer Hub (「参考文献」を参照) から直接ダウンロードすることができます。この SDK ファイルをダウンロードすると、アドオンを作成するときにお好みの IDE を使用できるようになります。

従来の方法 (つまり昔ながらの XUL を使用した方法) で、拡張機能を作成することもできます。ただし、この方法で拡張機能を作成することには、いくつかの欠点があります。それは、拡張機能のインストールに再起動が必要になること、そして拡張機能を作成するプロセスが複雑になることです。けれどもその見返りとして、Add-on Builder や Add-on SDK では不可能な方法でブラウザーに変更を加えることができます。例えば、XUL では、拡張機能のアイコンをアドオン・バー以外の場所に配置することができます。XUL 拡張機能については、Mozilla Developer Network (「参考文献」を参照) に詳しい説明が記載されています。

Add-on Builder で作成する Firefox 拡張機能は、CommonJS の慣例に従って必要なライブラリーを読み込みます。拡張機能では HTML、CSS、および JavaScript のファイルをどのように組み合わせることもできますが、すべての始まりは main.js ファイルです。

main.js ファイルは、Firefox 拡張機能の中核です。このファイルは Firefox に対し、どのモジュールを読み込むかを指示するため、拡張機能の初期化タスクはこのファイルで行います。main.js は、第 1 回で作成した Chrome 拡張機能の background.html ページと同じようなものです。つまり、起動時に一度だけ実行されると、あとはバックグラウンドで実行され、この main.js ファイルと直接やりとりが行われることはありません。

作成する Firefox 拡張機能の内部には、表示するページを panels に多数含めることができます。この拡張機能ではそのようなページの 1 つとして、図 1 に示すポップアップとオプション選択を組み合わせたページを使用します。

図 1. ポップアップ/オプション選択ページ
Gawkblocker のポップアップ/オプション選択ページのスクリーン・キャプチャー

さらに、Firefox でもコンテンツ・スクリプトを使用することができ、その方法は基本的に Chrome での場合と変わりません。コンテンツ・スクリプトとは、Web ページとやりとりするためにそのページに注入される JavaScript ファイルのことです。Firefox では、コンテンツ・スクリプトはページのコンテキスト内で効率的に実行されますが、セキュリティー上の問題を防ぐために、DOM へのアクセスおよび操作はプロキシーを介して行われます。拡張機能の残りの部分に対しては、コンテンツ・スクリプトは port を使用してやりとりすることができます。

Gawkblocker には、以下のものを使用します。

  • main.js ファイル
  • コア機能が含まれる JavaScript ファイル (コア機能の大半は Chrome 拡張機能から移植可能)
  • ポップアップとオプション選択を結合したページ
  • アイコン (1 つ、または 2 つ)

実装は、Chrome での場合よりも少し簡潔になりますが、ユーザー・エクスペリエンスは実質的に同じです。この拡張機能のさまざまな部分についての説明を読みながら、拡張機能の動作を確かめるには、私の Add-on Builder プロファイル (「参考文献」を参照) から実際に動作する Gawkblocker 拡張機能をダウンロードすることができます。


Add-on Builder の使用方法

https://builder.addons.mozilla.org/ に用意されている Add-on Builder (図 2) を使用するには、無料の登録プロセスを実行する必要があります。このプロセスを完了すれば、Add-on Builder にログインして独自のアドオンを作成することができます。

図 2. Add-on Builder
Mozilla Add-on Builder のスクリーン・キャプチャー

この記事では、Add-on Builder インターフェースの詳細については説明しませんが、ファイル構造について説明しておくべき点が 2 つあります。まず、Lib ディレクトリーは、require を使用してライブラリーを読み込むときに Firefox が検索する場所です。したがって、Gawkblocker のコア JavaScript クラスは、このディレクトリーに配置します。そして Data ディレクトリーは、拡張機能で提供することになる画像、HTML、CSS、およびその他のアセットを配置する場所です。

アドオンを作成してテストするときに、Add-on Builder ヘルパーをインストールするよう求めるプロンプトが出されます。アドオン開発時には、このヘルパーがアドオンのアンインストールとインストールの処理を行います。


Gawkblocker コア・クラスの更新

第 1 回では、ある程度の移植性を持った Gawkblocker のコア・クラス・ファイルのようなものを作成しました。今回はこのクラス・ファイルを Firefox 拡張機能で使用したいので、実際にそのクラス・ファイルにどの程度の移植性があるかがわかります。

明らかに、このクラス・ファイルには以下の重要な変更を加える必要があります。

  • localStorage の代わりに、Firefox の simple-storage 拡張 API を使用すること
  • exportsGB オブジェクトを追加すること

第 1 回のクラス・ファイルでは、セッション間で保持するデータを処理するために、localStorage のラッパーとして Storage Manager オブジェクト (SM と命名) を定義しました。そのコードは、Firefox 拡張機能の内部では動作しません。代わりに Firefox には、データを自動的に保持することが可能な simple-storage という API があります。第 1 回の Storage Manager オブジェクトは、リスト 1 に示すコードへと簡単に更新することができます。

リスト 1. SM オブジェクトを更新する
var SM = (function () {
    var SS = require("simple-storage");
    var my = {};
 
    my.get = function (key) {
        return SS.storage[key];
    }
    ...

    return my;

}());

GB オブジェクトは変更する必要がありませんが、CommonJS の慣例に従って、このオブジェクトを exports に追加する必要があります。そのタスクに対処するのが、リスト 2 の最後の行です。

リスト 2. exportsGB オブジェクトを追加する
var GB = (function (SM) {
   var my = {};

   my.blockTheseSites = {
       "gawker.com"        : "Gawker Media",
       "io9.com"           : "SciFi Blog",
       "gizmodo.com"       : "Gadget Blog",
       ...
   }

   ...

}(SM));

exports.GB = GB;

これらの変更はごくわずかなので、Firefox でも Chrome でも動作するように GB オブジェクトを変更するのは簡単です (そのための作業は、読者の皆さんがお望みであれば独自のプロジェクトとして行ってください)。

ファイル名を GB.js に変更してから Lib ディレクトリーにアップロードして、main.js 内でのこのオブジェクトの使用方法を確認できるようにしてください。


Gawkblocker の main.js ファイル

Chrome では、URL を背景ページと照らし合わせて、その URL がブロックの対象であるかどうかを調べました。Firefox の場合、このチェックは main.js ファイルの内部で行います。main.js が何らかの処理を行うためには、その前に一連の require ステートメントによって、使用する予定のモジュールと API を読み込む必要があります (リスト 3 を参照)。

リスト 3. require ステートメント
var data = require("self").data,
    tabs = require("tabs"),
    GB = require("GB").GB,
    popupPanel = require("panel").Panel({
        height: 500,
        contentURL: data.url("popup.html")
    });

リスト 3 のステートメントは順番に、main.js に以下のオブジェクトを読み込ように指示します。

  • Data ディレクトリーにアクセスするために使用するオブジェクト
  • タブを処理するためのオブジェクト
  • メイン・クラスからエクスポートした GB オブジェクト
  • ポップアップ・ウィンドウを格納する popupPanel オブジェクト。このコードは、ポップアップ・ウィンドウも作成します。

さらに作成するポップアップ・ウィンドウは、オプション選択ページとしても機能するため、いくつかのリスナーをセットアップする必要があります。Chrome では、背景ページにアクセスして、このページに対して実行する処理を指示しましたが、Firefox ではそれと同じ目的で、main.js にメッセージを送信します。例えば、リスト 4 に記載するリスナーは、ユーザーがブロック対象として選択したサイトのデフォルト・ランディング・ページを設定します。

リスト 4. ユーザーがブロック対象として選択したサイトのデフォルト・ランディング・ページを設定するリスナー
popupPanel.port.on("watchthis", function () {
    GB.setWatchThisInstead(http://www.youtube.com/watch?v=N-uyWAe0NhQ);
    console.log("watchthis");
});

後でポップアップ・ページについて説明するところで、メッセージをこの port に渡します。

main.js ファイルでは、Gawkblocker がタブにアクセスして、ユーザーがブロック対象としている URL があるかどうか、ある場合にはどの URL であるかを調べる処理も行います。リスト 5 に、タブの更新をリッスンするコードを記載します。

リスト 5. タブの更新をリッスンするコード
tabs.on("ready", function checkForBlock(tab) {
    for (site in GB.getBlockedSites()) {

        if (tab.url.match(site)) {
            tab.url = GB.getWatchThisInstead();
        }
    }
});

関数およびパフォーマンスについては、Chrome での場合と同様です。API の使用方法 (メソッドを呼び出して、コールバックを渡すという方法) も Chrome での場合と変わりません。

最後に、この機能の小さなラベルをブラウザーの右下隅に追加するための Widget を作成します (リスト 6 を参照)。

リスト 6. Widget を作成する
require("widget").Widget({
    id: "GBBrowserAction",
    label: "Gawkblocker",
    contentURL: data.url("images/GB-19.png"),
    panel: popupPanel
});

main.js ファイルに必要なコードをすべて配置した後は、ポップアップ・ページに対する変更について詳しく探ります。


ポップアップ・ページ

Chrome 拡張機能でのポップアップ・ページは、ブロック済みドメインのリストに過ぎませんでした。このポップアップ・ページの設計に手を加えるには、今が絶好のタイミングです。Firefox 拡張機能では、オプション選択ページの機能をポップアップ・ページにマイグレーションします。その上で、クリック・ハンドラーをポップアップ・ページに表示されるタイトルに追加し、ドメイン・リストとオプション選択の div を切り替えられるようにします。このオプション選択の機能によって、ユーザーのサイトからブロック・リストにアクセスして、ブロック済みサイトに対するリダイレクト・アドレスを指定できるようになります。図 3 に、Gawkblocker ポップアップ・ページのオプション選択を示します。

図 3. Gawkblocker ポップアップ・ページのオプション選択
Gawkblocker ポップアップ・ページのオプション選択を表示する Add-on Builder のスクリーン・キャプチャー

リスト 4 の port をセットアップするときには、main.js の watchthis をリッスンすることを忘れないでください。リスト 7 では addon.port.emit を使用して、そのメッセージをポップアップ・ページから送信します。

リスト 7. addon.port.emit を使用してポップアップ・ページからメッセージを送信する
$("#watchthis").click(function () {
    addon.port.emit("watchthis");
    $("#status").text("YOU'RE GOOD MATE.  ");
});

同じく port を使用してリストをリッスンすることで、main.js からブロック対象サイトのリストを取得します。main.js では、ポップアップ・ページからレディー状態であることが通知された時点で、リストを送信します (リスト 8 を参照)。

リスト 8. ポップアップ・オブジェクトがレディー状態であることを通知した時点でリストを送信する
popupPanel.port.on("pop", function () {
    popupPanel.port.emit("blocklist", GB.getBlockedSites());
    ...
});

ポップアップ・オブジェクトの中で、ページをリッスンして、それを変更します (リスト 9 を参照)。

リスト 9. ページをリッスンして変更する
addon.port.on("blocklist", function (blocklist) {
    $("#blockedlist").children().remove();
    $.each(blocklist, function (index, value) {
        $("#blockedlist").append("<div class='siterow' title='"+value+"'>
<div class='sitename'>"+index+"</div><span class='sitedesc'> : 
"+value+"</span></div>");
        showBlockList(blocklist);
    });
});

ポップアップ・ページは、main.js にブロック対象サイトのリストを要求します。リストを取得すると、そのリストを繰り返し処理して、ブロック対象サイトに関する詳細をポップアップ・ウィンドウ内の表示 div に追加します。


リダイレクト先のランディング・ページ

Chrome では、ブロック対象サイトへのリクエストのリダイレクト先が、拡張機能に含まれるランディング・ページとなるようにしました。Firefox ではそれとは異なり、直接、ソース (ランディング・ページに組み込まれた「Hey You! Don't Watch That! Watch This!」という YouTube の URL) へとリダイレクトされるようにします。

main.js に、リスト 10 に示すリダイレクトの初期条件を設定します。

リスト 10. 初期条件を設定する
if (!GB.getWatchThisInstead()) {
   GB.setWatchThisInstead("http://www.youtube.com/watch?v=N-uyWAe0NhQ");
}

図 4 に、リダイレクト先のランディング・ページを示します。

図 4. リダイレクト先のランディング・ページ
Firefox でのリダイレクト先ランディング・ページである YouTube のページのスクリーン・キャプチャー

Add-on Builder を使用したテスト

Add-on Builder を使用する場合、Firefox では作業中に拡張機能を簡単にテストすることができます。エラー・コンソール、テスト・ボタン、そして拡張機能が保存されるたびに自動的にその最新の拡張機能をリロードする Add-on Builder ヘルパーが用意されています。図 5 に、Add-on Builder ヘルパーの動作を示します。

図 5. Add-on Builder のユーティリティー
エラー・メッセージを表示する Add-on Builder ヘルパーのスクリーン・キャプチャー

拡張機能の配布

作成した拡張機能を大勢の人々に配布する準備ができたら、そこで、いくつかの選択肢のなかから配布方法を選ぶことになります。プロファイルでアドオンを公開アドオンとしてマークした場合は、潜在的ユーザーにリンクを送信することで、そのユーザーがそのリンクからアドオンをインストールすることができます。あるいは、パッケージ化した拡張機能をダウンロードによって配布するという方法、拡張機能を addons.mozilla.org にアップロードするという方法もあります。

パッケージ化した拡張機能の配布

パッケージ化した拡張機能を配布する場合は、Add-on Builder からそのパッケージをダウンロードします。「Download (ダウンロード)」アイコンをクリックすると、誰でもインストール可能な XPI ファイルが取得されるので、このファイルをお好みの方法 (e-メール、ホスト形式、インストーラー、その他の方法) で配布することができます。ただし、更新とホスト方式の処理は責任を持って行う必要があります。

addons.mozilla.org へのアップロード

自分で拡張機能を配布する場合に比べると、addons.mozilla.org に拡張機能を配置するプロセスでは技術的な作業は減りますが、レビュー・プロセスとその他いくつかの処理を経ることになります。このプロセスを完了するには、プロファイルで拡張機能の隣にある「upload to AMO (AMO にアップロード)」リンクをクリックします (図 6 を参照)。

図 6. AMO へのアップロード
AMO へのアップロード・リンクが表示されたアドオン・ダッシュボードのスクリーン・キャプチャー

そこから、アップロード手順に従います。


質問に対する回答

Firefox アドオンが完成したところで、質問に対する答えが Chrome での答えと比べてどのような結果になるのかを検討してみましょう。

ブラウザーの UI のどこかにその拡張機能の存在を示すようにする難易度はどの程度か?
ブラウザーの一番下にアドオン・バーを表示するのは、Chrome での場合と比べ、それほど難しいことではありません。Firefox アドオンでは、main.js ファイル内で Widget を作成することで、アドオン・バーが表示されるようにしました。
ブラウザーのセッション間でデータを保持するために必要なものは何か?
それには、Firefox 固有の simple-storage API を使用します。1 つの Storage Manager クラスを Chrome と Firefox の両方に共通で動作させるには、何らかの機能検出メカニズムを実装します。
拡張機能を構成するコンポーネント同士はどのような方法でやりとりするのか?
この種の通信を作成するには port を使用し、リスナーとエミッターをセットアップします。
ユーザーのデータのどこまでアクセスできるようにするのか?
ユーザーからの明示的な許可がなくても、少なくともユーザーがアクセスするすべての URL にアクセスすることはできます。これはかなりの程度です。

まとめ

この拡張機能は、Firefox アドオン内で実現できることのごく初歩的な部分でしかありません。Add-on Builder が提供できる可能性の限界を試すには、まだ程遠いものです。その可能性をさらに追求することにした場合、Add-on Builder で利用できる機能はまだまだあります。Add-on Builder、Add-on SDK、そしてより複雑な XUL 拡張機能のなかで、Firefox を拡張する手段は数多くあります。

連載の第 3 回では、Gawkblocker を Safari ブラウザーに移植するのでお見逃しなく。


ダウンロード

内容ファイル名サイズ
Article source codefirefox-sourcecode.zip38KB

参考文献

学ぶために

製品や技術を入手するために

  • Mozilla Firefox: お使いのプラットフォーム対応の Firefox をダウンロードしてください。
  • Add-on SDK: SDK をダウンロードしてください。
  • Add-on Builder: ここから Add-on Builder にアクセスしてください。
  • Gawkblocker: 著者の Add-on Builder プロファイルから Gawkblocker をダウンロードしてください。

議論するために

  • developerWorks コミュニティーに参加ください。ここでは他の developerWorks ユーザーとのつながりを持てる他、開発者によるブログ、フォーラム、グループ、Wiki を調べることができます。

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Web development
ArticleID=937057
ArticleTitle=独自のブラウザー拡張機能を作成する: 第 2 回、Firefox を拡張する
publish-date=07182013