はじめての Jetpack SDK 0.2
先日 Mozilla Labs のサイトにて Jetpack SDK の新バージョンである SDK 0.2 が公開されました。SDK 0.2 では、 SDK 0.1 で見つかった Windows 上での不具合などが修正されています。 SDK 0.2 は依然として API は充実しておらず、実用的な機能を手軽に作ることはできませんが、 SDK を用いた開発の雰囲気を一通り味わうことができます。
この記事では SDK 0.2 による開発環境のセットアップから始め、 SDK 0.2 を使用して実際に簡単な機能を開発するための手順を解説します。なお、 OS は Windows を前提としますが、おおよその手順は他の OS でも大差無いと思います。
Python インストール
Jetpack SDK を動作させるには Python のインストールが必要となります。インストール方法は OS によって異なると思いますが、 Windows の場合、 Python Japan User’s Group のサイトから Windows 用インストーラの「python-2.6.2.msi」をダウンロードし、ウィザードに従ってインストールを実施します。ここでは、インストール先を「C:\Python26\」とします。
インストール完了後、コマンドラインにて「python」コマンドを有効にするため、 Windows のユーザー環境変数の変数「Path」へ値「C:\Python26」を追加(すでに別の値が存在する場合は「;」で区切って追加)し、 Python インストール先フォルダへのパスを通します。スタートメニューの「ファイル名を指定して実行」で「cmd」と入力してコマンドプロンプトを起動し、「python -V」と入力して「Python 2.6.2」と出力されることを確認します。
C:\>python -V Python 2.6.2
なお、 Jetpack SDK Docs には Python 2.5 以上のバージョンが必要と記載されていますが、現在のところ Python 3.0.1 には対応していないようです。また、 Windows の場合は「Windows 用拡張モジュール」が必要と記載されていますが、実際はインストールしなくても問題ないようです。
Jetpack SDK セットアップ
次に、 Jetpack SDK のセットアップを行います。 Mozilla Labs のサイトから Jetpack SDK 0.2 のパッケージをダウンロードし、お好みの位置へ展開します。ここでは、「C:\jetpack-sdk-0.2」へ展開するものとします。
Jetpack SDK を使用する際は、毎回最初に「活性化」させる必要があります。コマンドプロンプトを起動し、 Jetpack SDK パッケージ展開先フォルダへ移動し、「bin\activate」と入力します。
C:\jetpack-sdk-0.2>bin\activate Welcome to the Jetpack SDK. Run 'cfx docs' for assistance. (C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2>
引き続き、「cfx docs」コマンドを入力して SDK ドキュメントをブラウザで表示します。SDK ドキュメントはポート8888を待ち受けポートとしたローカルのWebサーバ上で表示されます。
(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2>cfx docs One moment. Opening web browser to http://127.0.0.1:8888.
パッケージのフォルダ構成
Jetpack SDK で開発する機能の単位をパッケージと呼びます。ここからは、単純な hello-world パッケージを作成する手順へと移りますが、その前に hello-world パッケージが最終的にどのようなフォルダ構成となるかを、下表に示します。
フォルダ/ファイル | 概要 |
---|---|
jetpack-sdk-0.2 | Jetpack SDK 展開先フォルダ |
packages | パッケージ格納フォルダ |
hello-world | パッケージのルートフォルダ |
package.json | マニフェストファイル |
README.md | ドキュメントファイル |
lib | プログラム格納フォルダ |
main.js | メインプログラム |
simple-dialog.js | 自作ライブラリ |
Jetpack SDK を展開したフォルダの下の「packages」フォルダ内に個々のパッケージのルートフォルダがあり、その下には「package.json」という名前のマニフェストファイルがあります。「README.md」はパッケージの詳細を記述するためのドキュメントファイルで、必要に応じて配置します。「lib」フォルダ内には、パッケージのメインプログラムや自作ライブラリのプログラムを格納します。
パッケージの作成
それでは、「C:\jetpack-sdk-0.2\packages」フォルダ下に hello-world パッケージ用の「hello-world」フォルダを作成します。次に、パッケージのルートフォルダ内にマニフェストファイル「package.json」を作成します。マニフェストファイルにはパッケージに関するメタ情報を JSON 形式で記述します。拡張機能を作成したことのある方であれば、インストールマニフェスト「install.rdf」に近いものと考えてください。ここでは、以下のような内容を記述します。
{
"id": "helloworld@xuldev.org",
"version": "0.1",
"description": "This is my first package.",
"author": "Gomita <gomita@xuldev.org>"
}
"id"
プロパティはすべての拡張機能および Jetpack パッケージを一意に識別するための文字列で、一般的にはメールアドレスのような形式にします。拡張機能のインストールマニフェストの <em:id>
タグに相当します。
次に、さきほどブラウザで開いた SDK ドキュメントのページを更新し、「Package Reference」に「hello-world」が追加されたことを確認してください。
プログラムの作成
引き続き、 hello-world パッケージへメインプログラムを追加して、動作できるようにします。パッケージのルートフォルダの下に「lib」フォルダを作成します。「lib」フォルダ内にメインプログラムである「main.js」ファイルを作成し、以下のような内容を記述してください。
exports.main = function(options, callbacks) {
console.log("Hello, World!");
};
メインプログラムは「main」という名前のひとつのモジュールとなっており、 CommonJS 形式の exports.main = ...
という記法によって main
プロパティのみをモジュール外部からアクセス可能にします。また、 console.log
は Jetpack 標準のグローバル関数のひとつで、 Jetpack SDK のコマンドプロンプトへデバッグ用文字列を出力します。
なお、現時点では console.log("こんにちは");
のように日本語を記述しても、正常に動作しません。将来的に提供されるはずのローカライズ用APIを利用することになるはずです。
テスト実行
メインプログラムを作成したら、さっそくテスト実行してみます。テスト実行するには SDK のコマンドプロンプトへ「cfx run -a firefox」コマンドを入力します。「cfx run」コマンドへ「-a firefox」オプションを付加することで、新規の Firefox プロファイルへ先ほど作成したパッケージのみがインストールされた状態で Firefox が起動します。
(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2>cd packages\hello-world (C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2\packages\hello-world>cfx run -a firefox info: Hello, World! OK Total time: 1.531000 seconds Program terminated unsuccessfully.
Firefox 起動後、コマンドプロンプトに「info: Hello, World!」と表示されることを確認してください。Firefox のウィンドウをすべて閉じると、テスト実行も終了します。
標準ライブラリの使用
ここからは、 Jetpack 標準ライブラリのひとつである timer ライブラリを使用して、さきほどのプログラムを少し変更してみます。 timer ライブラリはタイマー関連の処理をひとまとめにしたモジュールで、 DOM の window.setTimeout
, window.clearTimeout
などとほぼ同等の機能を提供します。ライブラリの詳細を調べるには、 SDK ドキュメントを参照してください。なお、 SDK ドキュメントには記載されていませんが、 timer.setInterval
, timer.clearInterval
も利用可能です。
メインプログラム内でライブラリをインポートして利用可能にするには、 CommonJS 形式の require
関数を使用します。メインプログラム「main.js」を下記のように修正してください。
var timer = require("timer");
exports.main = function(options, callbacks) {
timer.setInterval(function() {
console.log(new Date().toLocaleTimeString());
}, 1000);
};
修正後、「cfx run -a firefox」コマンドでテスト実行し、以下のように SDK のコマンドプロンプトへ1秒おきに現在時刻が出力されることを確認してください。
(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2\packages\hello-world>cfx run -a firefox info: 10:37:21 info: 10:37:22 info: 10:37:23 info: 10:37:24 info: 10:37:25
自作ライブラリの作成
ここからは、 Jetpack 標準ライブラリには無い機能を、自作ライブラリとして作成する手順に移ります。拡張機能や Jetpack パッケージ内でファイル読み書きなどの高度な処理を行う場合、 XPCOM と呼ばれるコンポーネントを呼び出す必要があります。 Jetpack には、 XPCOM を使用する高度な処理はモジュール化してメインプログラムから切り離すという設計思想があります。今のところ、ライブラリだけでなくメインプログラム内でも制限なく XPCOM を利用可能ですが、もしかすると将来的にはメインプログラム内では XPCOM 使用不可となる可能性があります。したがって、 XPCOM を使用する処理は極力ライブラリとして実装した方がいいと思われます。
ここでは、 DOM の window.alert
のような単純なモーダルダイアログを表示する simple-dialog ライブラリを実装してみます。 Jetpack のプログラムのコンテクストには DOM でおなじみの window
や document
といったオブジェクトが無いため、 window.alert
関数も使用できません。このようなコンテクストでダイアログを表示するためには、 nsIPromptService という XPCOM を使用します(参考)。まず、パッケージのルートフォルダ下の「lib」フォルダ内に「simple-dialog.js」ファイルを作成します。メインプログラム同様にライブラリは exports.メソッド名 = function(...) { ... };
のような CommonJS 形式で実装していきます。
ここでは、 simple-dialog ライブラリに下表の2つのメソッドを実装します。
メソッド | 概要 |
---|---|
alert(text) |
引数 text のラベルとOKボタンを有する警告ダイアログを表示する。DOM の window.alert と同等。 |
confirmYesNo(text) |
引数 text のラベルと「はい」「いいえ」ボタンを有する確認ダイアログを表示する。メソッドの戻り値は真偽値で、ユーザが「はい」ボタン押下時は true を返す。 |
「simple-dialog.js」には、以下のように記述します。
var promptSvc = Cc["@mozilla.org/embedcomp/prompt-service;1"].
getService(Ci.nsIPromptService);
exports.alert = function(text) {
promptSvc.alert(null, "[Jetpack]", text);
};
exports.confirmYesNo = function(text) {
var pos = promptSvc.confirmEx(
null, "[Jetpack]", text, promptSvc.STD_YES_NO_BUTTONS,
null, null, null, null, {}
);
return pos == 0;
};
1~2行目は、 nsIPromptService を呼び出す処理です。なお、 Cc
, Ci
はそれぞれ Components.classes
, Components.interfaces
への参照であり、 Jetpack 標準のグローバル変数として定義済みです。4~6行目は simple-dialog ライブラリの alert
メソッドの実装で、 nsIPromptService の alert メソッドを使って警告ダイアログを表示します。8~14行目は simple-dialog ライブラリの confirmYesNo
メソッドの実装で、 nsIPromptService の confirmEx メソッドを使って「はい」「いいえ」ボタン付きの確認ダイアログを表示します。 nsIPromptService の confirmEx メソッドはユーザが押したボタンの番号(「はい」は 0
、「いいえ」は 1
)を返す仕様ですので、 confirmEx メソッドの戻り値が 0
なら confirmYesNo メソッドは true
を返すようにします。
自作ライブラリの使用
先ほど作成した simple-dialog ライブラリをメインプログラムで呼び出し、正常に動作するかを確認します。「main.js」を下記のように修正してください。
var simpleDialog = require("simple-dialog");
exports.main = function(options, callbacks) {
var adult = simpleDialog.confirmYesNo("Are you over 18 years old?");
if (adult) {
simpleDialog.alert("Welcome!");
}
else {
simpleDialog.alert("Good bye!");
}
};
「cfx run -a firefox」コマンドでテスト実行し、以下のように「はい」「いいえ」ボタン付き確認ダイアログが表示されることを確認してください。また、「はい」「いいえ」それぞれのボタン押下時に適切な警告ダイアログが表示されることを確認してください。
オフライン状態監視機能の実装
ここからは、 hello-world パッケージを修正して、もう少し実用的な機能を実装してみます。 Jetpack 標準ライブラリのひとつである observer-service ライブラリを使い、 Firefox のオンライン/オフライン状態の変化を監視する機能を実装します。
Firefox の内部ではアプリケーションに関する色々なイベントを nsIObserverService という XPCOM によってオブザーバへ通知しています。 Firefox がオフライン状態になったとき、トピック名「network:offline-status-changed」の通知が送信されます。この通知を受けて何らかの処理を実行するには、 observer-service ライブラリの add
メソッドを使用します。add メソッドの第1引数には監視する通知のトピック名、第2引数には通知を受けた際に実行するコールバック関数を設定します。コールバック関数には、2つの引数が渡されますが、オフライン状態が変化した際には、第2引数に「online
」または「offline
」の文字列が渡されます。ここでは、この文字列の値を調べて、状況に応じた内容のダイアログを simple-dialog ライブラリを使って表示させます。
var simpleDialog = require("simple-dialog");
var observer = require("observer-service");
exports.main = function(options, callbacks) {
observer.add("network:offline-status-changed", function(sbj, data) {
if (data == "online") {
simpleDialog.alert("Firefox is now online.");
}
else if (data == "offline") {
simpleDialog.alert("Firefox is now offline.");
}
});
};
「cfx run -a firefox」コマンドでテスト実行し、 Firefox 起動後に [ファイル] → [オフライン作業] のチェックボックスをオフにし、以下のようなダイアログが表示されることを確認してください。
ドキュメントの作成
各パッケージについての詳細なドキュメントを追加することで、 SDK ドキュメントの各パッケージのリンクをクリックしたときに表示されるようになります。ドキュメントを追加するには、パッケージのルートフォルダの下に「README.md」ファイルを作成してください。「README.md」は以下のように markdown という記法にて記述します。
This is my *first* package. * foo * bar * baz
「cfx docs」コマンドで SDK ドキュメントをブラウザで表示し、「hello-world」のリンクをクリックするとパッケージのメタ情報とともにドキュメントの内容が整形表示されることを確認してください。
インストーラの作成
これまで作成してきたような Jetpack のパッケージから、一般的な Firefox 拡張機能と同等の XPI インストーラ形式を作成することができます。 XPI インストーラを作成するには、 SDK のコマンドプロンプトでパッケージのルートフォルダへ移動し、「cfx xpi」コマンドを入力します。
(C:\jetpack-sdk-0.2) C:\jetpack-sdk-0.2\packages\hello-world>cfx xpi Exporting extension to hello-world.xpi.
すると、「hello-world.xpi」というファイル名の XPI インストーラが生成されます。これを適当な Firefox のウィンドウへドラッグ&ドロップして、通常の拡張機能としてインストールされることを確認してください。