ユーザー設定とは、アドオンの設定を管理する機能です。
設定システムにアクセスするには、XPCOMを使用します。
nsIPrefBranchは、次のようにすることで取得できます。
var prefBranch = Components.classes[ '@mozilla.org/preferences-service;1' ]
.getService( Components.interfaces.nsIPrefBranch );
またはnsIPrefServiceから、getBranch()でも取得できます。
| メソッド | |
|---|---|
| void | addObserver( in string aDomain, in nsIObserver aObserver, in boolean aHoldWeak ) |
| void | removeObserver( in string aDomain, in nsIObserver aObserver ) |
| void | getChildList( in string aStartingAt, [optional] out unsigned long aCount, [array, size_is(aCount), retval] out string aChildArray ) |
| void | deleteBranch( in string aStartingAt ) |
| void | resetBranch( in string aStartingAt ) |
| long | getPrefType( in string aPrefName ) |
| boolean | prefHasUserValue( in string aPrefName ) |
| void | clearUserPref( in string aPrefName ) |
| void | lockPref( in string aPrefName ) |
| void | unlockPref( in string aPrefName ) |
| boolean | prefIsLocked( in string aPrefName ) |
| 区分 | メソッド | |
|---|---|---|
| 取得 | long | getIntPref( in string aPrefName ) |
| string | getCharPref( in string aPrefName ) | |
| boolean | getBoolPref( in string aPrefName ) | |
| 設定 | void | setIntPref( in string aPrefName, in long aValue ) |
| void | setCharPref( in string aPrefName, in string aValue ) | |
| void | setBoolPref( in string aPrefName, in long aValue ) | |
| メソッド | |
|---|---|
| void | getComplexValue( in string aPrefName, in nsIIDRef aType, [iid_is(aType), retval] out nsQIResult aValue ) |
| void | setComplexValue( in string aPrefName, in nsIIDRef aType, in nsISupports aValue ) |
nsIPrefServiceは、次のようにすることで取得できます。
var prefService = Components.classes[ '@mozilla.org/preferences-service;1' ]
.getService( Components.interfaces.nsIPrefService );
| メソッド | |
|---|---|
| nsIPrefBranch | getBranch( in string aPrefRoot ) |
| nsIPrefBranch | getDefaultBranch( in string aPrefRoot ) |
| void | resetPrefs() |
| void | resetUserPrefs() |
| void | savePrefFile( in nsIFile aFile ) |
| void | readUserPrefs( in nsIFile aFile ) |
ユーザー設定へアクセスするためのnsIPrefBranchを取得します。
nsIPrefBranch getBranch(
in string aPrefRoot
);
getBranch() - nsIPrefService - XPCOM Interface Reference | MDN
about:configで、既存のアドオンの設定を確認できます。設定値の使用方法は、これが参考になります。
設定値の名前は、
のいずれかの形式から始めるのが慣習のようです。しかしアドオンを配布することを考えるならば、1番目の書式とすべきです。
all preference names should begin with "extensions.", followed by the add-on name or some other unique identifier
Review Process :: Add-on Documentation :: Developer Hub :: Add-ons for Firefox
また設定名はドット区切りで記述されることが多いようですが、システム上はこのドットに意味はなく、文字列の一部とみなされます。設定 "木" についての詳細 - Preferences - Code snippets | MDN
| 型 | 取得 | 設定 |
|---|---|---|
| 整数※1 | getIntPref() | setIntPref() |
| 文字列 | getCharPref() | setCharPref() |
| 論理値 | getBoolPref() | setBoolPref() |
※1 浮動小数点数は使用できません。よってその必要があるならば文字列として定義し、使用時に文字列と数値を変換します。
これらのメソッドは、設定値の型に応じて正しく使い分けなければなりません。さもなくば例外が発生します。
long getIntPref(
in string aPrefName
);
getIntPref() - nsIPrefBranch - Mozilla | MDN
void setIntPref(
in string aPrefName,
in long aValue
);
setIntPref() - nsIPrefBranch - Mozilla | MDN
オブジェクトは、JSONに変換することで文字列として処理できます。また文字列に変換できる要素から構成される配列ならば、Array.join()でも同様です。
var prefService = Components.classes[ '@mozilla.org/preferences-service;1' ]
.getService( Components.interfaces.nsIPrefService );
var branch = prefService.getBranch( 'extensions.MyAddon.' );
var value = branch.getIntPref( 'pref1' );
設定名のドット区切りに意味はないため、次のように指定しても同じです。
var branch = prefService.getBranch( '' ); var value = branch.getIntPref( 'extensions.MyAddon.pref1' );
またnsIPrefServiceではなくnsIPrefBranchを取得することで、
var prefBranch = Components.classes[ '@mozilla.org/preferences-service;1' ]
.getService( Components.interfaces.nsIPrefBranch );
var value = prefBranch.getIntPref( 'extensions.MyAddon.pref1' );
のようにも記述できます。
有効な値が存在しない設定名から読み込もうとすると「NS_ERROR_UNEXPECTED: Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPrefBranch.getIntPref]」として例外が発生します。その設定名で記録する処理が存在していても、既定の設定で初期値が指定されていないと、ユーザーのリセットの操作により設定値が削除されることがあります。
よって設定の取得時には例外に備えるか、さもなくば既定値を設定します。
書き込みも読み込みと同様で、nsIPrefBranchのメソッドを呼び出します。
var prefBranch = Components.classes[ '@mozilla.org/preferences-service;1' ]
.getService( Components.interfaces.nsIPrefBranch );
prefBranch.setCharPref( 'extensions.MyAddon.pref1', 'abc' );
たとえば文字列として作成されたユーザー設定を、整数用のメソッドであるgetIntPref()で読もうとすると、「Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPrefBranch.getIntPref]」として例外が発生します。
この問題には、ユーザー設定の型を事前に調べることで対処できます。それを行うのが次のgetPrefType()です。
long getPrefType(
in string aPrefName
)
getPrefType() - nsIPrefBranch - XPCOM Interface Reference | MDN
branch.getPrefType( aPrefName )として設定名を指定して呼び出すと、その設定の型に応じて定数が返されます。このメソッドの用法は、以下のサンプルを参考にしてください。
var prefService = Components.classes[ '@mozilla.org/preferences-service;1' ]
.getService( Components.interfaces.nsIPrefService );
var branch = prefService.getBranch( 'extensions.MyAddon.' );
var value = null;
var prefName = 'pref1';
switch( branch.getPrefType( prefName ) )
{
case branch.PREF_STRING:
value = branch.getCharPref( prefName );
break;
case branch.PREF_INT:
value = branch.getIntPref( prefName );
break;
case branch.PREF_BOOL:
value = branch.getBoolPref( prefName );
break;
case branch.PREF_INVALID:
break;
}
複合型では単純型の3つの型、つまり整数、文字列、論理値以外の型を扱えます。
| 取得 | 設定 |
|---|---|
| getComplexValue() | setComplexValue() |
void getComplexValue(
in string aPrefName,
in nsIIDRef aType,
[iid_is(aType), retval] out nsQIResult aValue
);
getComplexValue() - nsIPrefBranch - XPCOM Interface Reference | MDN
void setComplexValue(
in string aPrefName,
in nsIIDRef aType,
in nsISupports aValue
);
aTypeには、次のいずれかの値を指定します。
about:configで、設定値の確認や編集を行えます。
作成した設定値は、直接削除することはできません。その設定値を作成しないようにコードを修正し、設定値が既定値であることを確認してからFirefoxを再起動することで、設定ファイル (prefs.js) から削除されます。
なお設定値を既定値に戻すには、対象の値を右クリックしコンテキストメニューから[リセット]を実行します。

設定値をブラウザのロード時に初期化している場合、ユーザーに設定ウィンドウで設定を変更されても、その設定はブラウザを再起動するまで反映されません。この問題に対処するには、設定の変更を監視するようにします。
addObserver()で、設定値の変更を監視 (オブザーブ) できます。このとき監視する対象は、他の拡張の設定でも、ブラウザの既定の設定でも構いません。
addObserver(
in string aDomain, // 監視対象の設定値の名前
in nsIObserver aObserver, // 変更の通知を受け取るオブジェクト
in boolean aHoldWeak // trueならばaObserverの弱い参照を、さもなくば強い参照を保持する
)
addObserver() - nsIPrefBranch - XPCOM Interface Reference | MDN
引数のaDomainには、getBranch()で指定した設定名に続く文字を指定します。たとえば、
という設定名があるとき、
var branch = prefService.getBranch( 'MyAddon.' ); branch.addObserver( 'a', this, false );
とすると、[MyAddon.a]から始まる「MyAddon.aa」と「MyAddon.ab」の2つが監視対象となります。一方で第1引数のaDomainを空文字とすると、[MyAddon.]から始まる「MyAddon.bb」も含めた3つが対象となります。
addObserver()でオブザーバを追加したならば、それが不要になったときにはremoveObserver()でそれを取り除く必要があります。さもなくば監視対象が変更されるたびに、observe()が呼ばれ続けることになります。
void removeObserver(
in string aDomain, // 監視対象としてあった設定値の名前
in nsIObserver aObserver // 変更の通知を受け取るオブジェクト
);
removeObserver() - nsIPrefBranch - XPCOM Interface Reference | MDN
addObserver()で追加したオブザーバーを削除するならば、引数のaDomainとaObserverは、addObserver()で指定した同名の引数と同じものとします。
var prefObserver =
{
branch: null,
register: function()
{
var prefService = Components.classes[ '@mozilla.org/preferences-service;1' ]
.getService( Components.interfaces.nsIPrefService );
// ユーザー設定へアクセスするためのnsIPrefBranchを取得する
this.branch = prefService.getBranch( 'extensions.MyAddon.' );
// … そのユーザー設定に、オブザーバーを追加する
// … 第2引数にthisを渡すことで、通知をthis.observe()が受け取ることになる
this.branch.addObserver( '', this, false );
},
unregister: function()
{
this.branch.removeObserver( '', this );
},
// 監視対象の設定が変更されると、呼び出されるメソッド
observe: function( aSubject, aTopic, aData )
{
switch( aData )
{
case 'pref1':
// 'extensions.MyAddon.pref1' が変更された
break;
case 'pref2':
// 'extensions.MyAddon.pref2' が変更された
break;
}
}
};
window.addEventListener(
'load', function() { prefObserver.register(); }, false );
window.addEventListener(
'unload', function() { prefObserver.unregister(); }, false );
observe()は、addObserver()の第2引数で指定するオブジェクトにobserveの名前で定義することで、監視対象の設定が変更されるたびに呼び出されます。
void observe(
in nsISupports aSubject, // 監視対象のnsIPrefBranch
in string aTopic, // "nsPref:changed"などの値
in wstring aData // 変更された設定値の名前
);
nsIObserver - XPCOM Interface Reference | MDN
引数のaSubjectには、オブザーバを設定したnsIPrefBranchが渡されます。つまり、
aSubject.getIntPref( aData );
のようにすることで、新しい設定値を取得できます。このとき引数のaDataには、getBranch()で指定した設定名に続く文字列が渡されます。たとえば「extensions.MyAddon.pref1」という設定名があるとして、
branch = prefService.getBranch( 'extensions.MyAddon.' ); branch.addObserver( 'p', this, false );
のようにオブザーバが追加されているとします。このとき「extensions.MyAddon.pref1」に変更があると、observe()の引数aDataには'pref1'という文字列が渡されます。一方で、もし
branch = prefService.getBranch( 'exten' ); branch.addObserver( '', this, false );
のようにオブザーバが追加されているとすると、'sions.MyAddon.pref1'が渡されます。
既定の設定は、defaults\preferences\フォルダに拡張子を「js」としてファイルを配置します。配置するフォルダと拡張子が重要であり、ファイル名は意味を持ちません。複数のファイルを配置した場合は、それらのすべてが読み込まれます。
値の設定は、pref()関数で行います。
pref('name', value);
この関数では設定名と値のみを指定し、型を指定する必要はありません。それはvalueの型に応じて適切に設定されます。設定値が複数ある場合には、セミコロンで区切ってこの関数を複数記述します。なお、このファイルに記述できるのはこの関数とコメントのみで、それは次のようにします。
/* comment */ pref( 'extensions.MyAddon.a', 1 ); // 整数値 pref( 'extensions.MyAddon.c', 'foo' ); // 文字列 pref( 'extensions.MyAddon.d', true ); // 真偽値
記述に誤りがあると、それ以降の設定が無効となります。
拡張子はjsでありJavaScript風に記述しますが、これはJavaScriptではありません。よって変数や式は記述できず、文末のセミコロンを省略できないなど文法も異なります。
about:configでリセットされたときは、この既定の設定の値が設定されます。もしこの既定の設定がなければその設定値は無効な状態となり、その値を読み込もうとすると「NS_ERROR_UNEXPECTED: Component returned failure code: 0x8000ffff (NS_ERROR_UNEXPECTED) [nsIPrefBranch.getIntPref]」として例外が発生します。
値に文字列を指定する場合、文字列を「'」で囲った場合には、文字列中に「'」を直接記述することはできません。これは「"」で文字列を囲むか、「\'」のようにエスケープすることで解決できます。このような問題は、JavaScriptの文字列リテラルをエスケープすることと同じです。
設定用のウィンドウも他のUIと同様に、XULで定義します。そのときルート要素は<prefwindow>とし、その子要素に<prefpane>でペインを配置します。
設定項目は<preferences>のなかで<preference>で定義します。<preference>のname属性が設定値の名前となり、typeで下表のいずれかの型を指定します。
| 種類 | 設定値 | 意味 |
|---|---|---|
| 単純型 | bool | 真偽値 |
| int | 整数値 | |
| string | 文字列 | |
| 複合型 | unichar | Unicode文字列 |
| wstring | ローカライズされた文字列 | |
| file | ファイル |
typeと異なる型の値が設定された場合は、typeの型に変換されて設定に格納されます。たとえばtypeをintとしたときに"12AB34"が設定されると、"12"が格納されます。
すでに存在する設定と同名で、しかし型が異なる設定値は設定できません。設定しようとしても無視されます。
<textbox>などの入力要素で、設定対象の<preference>のid属性をpreference属性で指定します。こうすることで設定ウィンドウに現在の設定値が自動で表示され、また設定を変更したときにはその値が保存されます。
<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="chrome://global/skin/"?>
<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="pref">
<prefpane>
<preferences>
<preference type="bool" id="AAA" name="extensions.MyAddon.A" />
<preference type="int" id="BBB" name="extensions.MyAddon.B" />
</preferences>
<checkbox preference="AAA" label="A" />
<textbox preference="BBB" />
</prefpane>
</prefwindow>

このサンプルでの設定値は、about:configで次のように確認できます。

prefwindow要素のid属性は必須です。このことは開発者センターの検証で、「<prefwindow>` elements without `id` attributes cause errors to be reported in the error console and prevent persistence of certain properties of the dialog.」のように記されています。
またXULは、XUL Editorでプレビューを確認しながら記述すると簡単です。そのとき設定値は、about:configで確認できます。
prefpane要素を複数定義することで、設定項目をペインごとにまとめられます。ペインの名前をlabel属性で、ペインのIDはid属性で定義します。このid属性は必須で、これを定義しないとペインの切替が機能しません。Using multiple prefpanes - prefpane - XUL | MDN
<prefpane id="pane1" label="Pane1">
<preferences>
<preference type="bool" id="AAA" name="aaa.A" />
</preferences>
<checkbox preference="AAA" label="A" />
</prefpane>
<prefpane id="pane2" label="Pane2">
...
</prefpane>

radioの値を記録するには、preferenceをradiogroupに設定します。そしてradioのそれぞれの値を、valueで指定しておきます。
<preferences> <preference type="int" id="AAA" name="extensions.MyAddon.A" /> </preferences> <radiogroup preference="AAA"> <radio label="A" value="0" /> <radio label="B" value="1" /> <radio label="C" value="2" /> </radiogroup>

アドオンマネージャ (Add-on Manager) のアドオンの項目に、

のような[設定]ボタンを追加するには、install.rdfのoptionsURLで
<em:optionsURL>chrome://myPackage/content/prefs.xul</em:optionsURL>Adding preferences to an extension | MDN
のように、設定ウィンドウのxulファイルを指定します。
拡張機能のルートにoptions.xulというファイルが置かれていると、この設定は無視され、そのファイルがインラインオプションとして開かれます。
プラットフォームによっては、アドオンマネージャから開くウィンドウはモーダル (他のウィンドウを操作できないウィンドウ) で表示されます。モードレスとするには、アドオンマネージャ以外からopenDialog()で開く必要があります。588720 – Addon preference dialog shouldn't be modal when opened from addon manager page
既定ではprefwindowの[OK]ボタンがクリックされたときに、preference要素のname属性で指定された設定に書き込まれます。
設定が変更されたタイミングでユーザー設定を更新したい場合には、その設定のpreference要素のinstantApply属性をtrueとします。
<preference instantApply="true" type="bool" id="A" name="extensions.MyAddon.A" />instantApply - Mozilla | MDN
設定画面を設定ウィンドウのようなウィンドウではなく、アドオンの詳細ページに埋め込む形で表示できます。

設定画面をインラインオプションとするには、
<em:optionsURL>chrome://myPackage/content/options.xul</em:optionsURL> <em:optionsType>2</em:optionsType>のように定義する
の2つの方法があります。UIとなるXULは、次のように定義します。
<?xml version="1.0"?>
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<setting type="bool" pref="extensions.MyAddon.A" title="設定項目1" />
<setting type="string" pref="extensions.MyAddon.B" title="設定項目2" />
</vbox>
ここでは設定ウィンドウのような<prefwindow>や<preferences>は不要で、ただ<setting>のみで記述します。