拡張機能が何らかの永続的なローカルのストレージを必要とすることがよくあります。ローカルストレージを利用する場合は、少なくともエラーログを記録しておくことをお勧めします。デバッグが困難な問題に遭遇した時、ユーザにエラーデータを要求できます。このセクションでは、ログの記録について扱います。その前に、ローカルファイルを管理する正しい方法 (少なくとも一般的で応用できる方法) を見ていきましょう。
ローカルファイルは、Firefox のプロファイルディレクトリ内に保存することを強くお勧めします。そうしておかないと、複数のプロファイルに同じ拡張機能がインストールされた場合に問題が起こるでしょう。あなたのプロジェクト名のディレクトリをプロファイルフォルダの直下に作成し、その中にファイルを保存することが慣習になっています。ディレクトリ構造は次のようになります:
- s435L.default (あなたのプロファイルディレクトリ)
- XULSchool
- log.txt
- somedbfile.sqlite
- XULSchool
ローカルディレクトリを作成するには、Directory サービスと nsIFile インタフェースを使用します。私たちは次のように行っています。ルートディレクトリへの参照を返す関数を持ち、必要であればディレクトリを作成します。
getLocalDirectory : function() { let directoryService = Cc["@mozilla.org/file/directory_service;1"]. getService(Ci.nsIProperties); // プロファイルディレクトリへの参照 (ProfD) です let localDir = directoryService.get("ProfD", Ci.nsIFile); localDir.append("XULSchool"); if (!localDir.exists() || !localDir.isDirectory()) { // 読み書き権限を所有者とグループに与え、読み込み専用の権限を他者に与えます localDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0774); } return localDir; },
ProfD は、プロファイルディレクトリを表す特別な識別子です。プロファイルディレクトリの場所を探す必要はありません。一般的に、これはあなたが必要とするディレクトリのフラグでしかありませんが、時々、他のシステムディレクトリへアクセスする必要があるでしょう。拡張機能を実行しているオペレーティングシステムやシステムの言語を気にせずに、これらのディレクトリへアクセスしたいときは、Firefox のソースコードに定義されたディレクトリフラグのリストを参照してください。
上記の関数を書いた場所で、次のように使用します:
let myFile = XULSchool.getLocalDirectory(); myFile.append("someFile.txt"); // ファイルに対する操作
ファイルは、nsIFile インタフェースで扱います。上記の例のように、nsIFile は、必ずしも既存のファイルを指し示すとは限りません。はじめに、nsIFile を使用してファイルを指定し、次に、 create メソッドを使用して実際にディスクに書き出します。また、exists メソッドを使用して、nsIFile が存在するか確認することもできます。
ファイル内の情報を読み書きするには、ストリームオブジェクトを使用する必要があります。詳しくは、File I/O についてのページをお読みください。通常はディレクトリに対して読み書きを行う必要はありませんが、ファイルの読み書きについて知っておくと、あとで役立ちます。
最後に、拡張機能がアンインストールされた時にローカルファイルを削除する問題が残っています。これが必要であるかどうかは好みの問題です。拡張機能開発者によっては、ユーザが再びその拡張機能をインストールして以前の設定を復元したい時のために、設定を残しておくことを好む人もいます。これは、Firefox がアンインストールされた時のデフォルトの動作でもあります。プロファイル情報は、Firefox が再びインストールされるまで、そのまま残されます。他に、プライバシーに係わることやプライベートな情報が削除されずにローカルに保存されたままになることを懸念する人もいます。両者の議論が衝突してしまうため、この場合、どうすべきかを決めるのは開発者のあなた次第です。FUEL ライブラリには、アンインストール時の操作を行うときに使用できる uninstall イベントがあります。
ログの記録
ログを記録しておくことは、すべてのソフトウェアプロジェクトの基本です。Hello World よりさらに複雑な拡張機能は、エラーログを記録し、デバッガを起動せずにトレースを実行することを必要とします。
以前はログを記録するカスタムの対策が必要でしたが、それに対して、Mozilla Labs が Java プロジェクトで使用される Log4J loggerに似た、Log4Moz と呼ばれる JavaScript 実装のロガーを提供しています。このロガーは、JavaScript コードモジュールとして実装されているため、Firefox 3 以降でのみ動作します。
このロガーを使用するには、log4moz.js ファイルを拡張機能の modules ディレクトリへコピーする必要があります。"共通" のスタートアップオブジェクトの初期化メソッド内に、次のコードを追加してください:
let formatter = new Log4Moz.BasicFormatter(); let root = Log4Moz.repository.rootLogger; let logFile = this.getLocalDirectory(); // これは覚えていますね? let appender; logFile.append("log.txt"); // ロガーは階層構造をしており、ログレベルを下げるとすべての出力に影響します root.level = Log4Moz.Level["All"]; // この appender はファイルシステムに記録します appender = new Log4Moz.RotatingFileAppender(logFile, formatter); appender.level = Log4Moz.Level["All"]; root.addAppender(appender);
次に、あなたのプロジェクト内のオブジェクトに対する logger オブジェクトを作成してください:
this._logger = Log4Moz.repository.getLogger("XULSchool.SomeObject"); this._logger.level = Log4Moz.Level["All"];
そして、記録するメッセージの種類によって、次のいずれかのメソッドでログが記録されます。
this._logger.fatal("This is a fatal message."); this._logger.error("This is an error message."); this._logger.warn("This is a warning message."); this._logger.info("This is an info message."); this._logger.config("This is a config message."); this._logger.debug("This is a debug message."); this._logger.trace("This is a trace message.");
グローバルロガーの出力を絞り込んだり特定のログインスタンスを level プロパティの設定によって絞り込んだりすることができます。開発中は "All" レベルを使用すべきですが、リリースバージョンでは "Warn" レベルへ上げるとよいでしょう。ログの量が少なくなり、実行の効率が上がります。
SQLite
SQLite ストレージは、Firefox 2 で導入されました。これは、Firefox における優先されたストレージ機構です。このストレージシステムは、ブックマークと履歴を管理する Places API のために使用されます。また、cookie の保存やフォームの入力履歴、その他の用途にも使用されます。
SQLite は、軽量な SQL ベースのストレージシステムです。これは、プログラム内に組み込むためのもので、いくつかの有名なアプリケーションでも使用されています。また、拡張機能で使用されるお勧めのローカルストレージでもあります。
Storage のページに、SQLite API を使用するための詳しい説明があるため、ここでは説明しません。SQL に詳しくない方や SQLite に使用される構文の制限に興味のある方は、SQLite のサイトをご覧ください。
将来のバージョンで機能を追加する予定のある場合は、データベースの構造に注意して設計してください。新しいバージョンでデータベースの項目を追加したり削除したりしてデータベース構造を変更すると、古いバージョンにおけるユーザデータを破壊する原因になることがあります。古いデータベースのフォーマットから新しいものへデータを移行するコードを注意深く追加する必要がでてくるでしょう。新しいバージョンでデータベースを新しい構造に変更するだけで、コードの複雑さが増してしまいます。そのため、将来のバージョンのために、はじめに注意しながらデータベース構造の計画を立ててください。
拡張機能のために使用するローカルストレージを作成する方法は、2 通りあります。1 つは、ファイルとすべてのテーブル、初期データを拡張機能の初回起動時に生成することです。複雑なデータベースが必要な場合は、このために多くのコードと時間を費やさなければなりません。もう 1 つの選択肢は、初期データベースファイルを拡張機能の defaults ディレクトリに含めておき、ユーザのプロファイルにコピーできるようにしておくです。この方法は、ファイルをコピーするだけで済みます。defaults ディレクトリへは、ProfD/extensions/YOUR_EXTENSION_ID/defaults でアクセスできます。
RDF
RDF は、Firefox で優先的に利用されるストレージメカニズムになっています。ほとんどのデータソースで利用されていたため、install.rdf など、どこでも見ることができるでしょう。しかし、SQLite が代わりに利用されるようになったため、その座を奪われています。RDF API は、簡単なタスクでも多くのコードを必要とするため、将来のバージョンで削除されるかもしれません。現在は、あまりメンテナンスされていないため、本当に必要でない限り RDF の利用はお勧めしません。
少なくとも、テンプレートについてのドキュメントを読む場合は、RDF について理解しておく必要があります。
テンプレート
テンプレートは、Firefox におけるとても強力なツールです。データソースからの情報を使用して、XUL コンテンツを自動的に生成できます。これは、RDF データソースと共に設計されましたが、Firefox 3 以降のバージョンで SQLite データソースも同様にサポートするように拡張されました。
テンプレートの扱いは面倒になりがちですが、長いリストや複雑なデータを伴うツリーを表示する必要のあるときは、努力して実装する価値があります。テンプレートを使用して表示するコードを管理すれば、多くのコードを書かずに済みます。テンプレートは、ほとんどの拡張機能が必要とせず、複雑な対象であるため、専門家の書いたドキュメントから読むとよいでしょう。XUL テンプレートガイドに、とても詳しい説明があります。前述のように、テンプレートは RDF と共に作られたため、RDF がどのように動作するか理解する必要があります。ガイドには、SQLite テンプレートについてのセクションもありますが、これには、ガイドの残りを読んでおく必要のあるいくつかの概念が含まれています。
This tutorial was kindly donated to Mozilla by Appcoast.