Android版Firefoxアドオン開発の基礎を学ぶ
デスクトップ版Firefox向けアドオン開発暦7年
※パソコンが高スペックならAndroidエミュレータでもいける?
ソース編集
▼
インストーラ作成
▼
MicroSDカードへコピー
MicroSDカードを装着
▼
file:///mnt/sdcard/ をFirefoxで開く
▼
インストール
ソース編集
▼
インストーラ作成
▼
Dropboxで共有
Web版DropboxをFirefoxで開く
▼
インストール
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>viewsource@xuldev.org</em:id>
<em:type>2</em:type>
<em:name>View Source</em:name>
<em:version>0.1</em:version>
<em:bootstrap>true</em:bootstrap>
<em:description>Adds 'View Source' menu.</em:description>
<em:creator>Gomita</em:creator>
<em:targetApplication>
<Description>
<em:id>{aa3c5121-dab2-40e2-81ca-7ea25febc110}</em:id>
<em:minVersion>14.0</em:minVersion>
<em:maxVersion>17.0a1</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>
function install(data, reason) {
// アドオンをインストール時に実行する処理
}
function uninstall(data, reason) {
// アドオンを削除時に実行する処理
}
function startup(data, reason) {
// アドオンを起動時(有効化時)に実行する処理
}
function shutdown(data, reason) {
// アドオンを終了時(無効化時)に実行する処理
}
とりあえずServices.jsmをインポート
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Firefoxウィンドウの監視①
function startup(data, reason) {
// アドオン起動時、すでに開いているウィンドウを取得
var winEnum = Services.wm.getEnumerator("navigator:browser");
while (winEnum.hasMoreElements()) {
var win = winEnum.getNext().QueryInterface(Ci.nsIDOMWindow);
if (win)
// ウィンドウに対する処理
loadIntoWindow(win);
}
// 今後開かれるウィンドウを監視
Services.wm.addListener(windowListener);
}
Firefoxウィンドウの監視②
var windowListener = {
onOpenWindow: function(aWindow) {
// 新しいウィンドウが開かれたら…
var win = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
// UIReadyイベントを監視
win.addEventListener("UIReady", function() {
win.removeEventListener("UIReady", arguments.callee, false);
if (win)
// UIReadyイベント発生後、ウィンドウに対する処理
loadIntoWindow(win);
}, false);
},
onCloseWindow: function(aWindow) {},
onWindowTitleChange: function(aWindow) {},
};
Firefoxウィンドウの監視を解除
function shutdown(data, reason) {
// Firefox自体の終了時は何もしなくていい
if (reason == APP_SHUTDOWN)
return;
// 今後開かれるウィンドウへの監視を終了
Services.wm.removeListener(windowListener);
// 現在開かれているウィンドウに対する処理
var winEnum = Services.wm.getEnumerator("navigator:browser");
while (winEnum.hasMoreElements()) {
var win = winEnum.getNext().QueryInterface(Ci.nsIDOMWindow);
if (win)
unloadFromWindow(win);
}
}
Firefoxウィンドウに対するUI生成処理
var gMenuId;
function loadIntoWindow(aWindow) {
// メニュー項目を追加
gMenuId = aWindow.NativeWindow.menu.add("View Source", null, function() {
viewSource(aWindow);
});
}
NativeWindow.menu.add … メニュー項目を追加するAPI
Firefoxウィンドウに対するUI削除処理
function unloadFromWindow(aWindow) {
// メニュー項目を削除
aWindow.NativeWindow.menu.remove(gMenuId);
}
NativeWindow.menu.remove … メニュー項目を削除するAPI
ソースを表示する処理
function viewSource(aWindow) {
// 現在のxul:browser要素を取得
var browser = aWindow.BrowserApp.selectedBrowser;
// 現在のURL
var url = browser.currentURI.spec;
// view-source:を付加したURLを新しいタブで開く
aWindow.BrowserApp.addTab("view-source:" + url);
}
BrowserApp.addTab … 新しいタブを開くAPI
デスクトップ版Firefox
モバイル版Firefox
<deck id="browsers" />
デスクトップ版Firefox
モバイル版Firefox - デスクトップ版よりも綺麗にモジュール化されている
アドオンからはタブブラウザ操作用APIとして利用
BrowserApp.tabs // Tabオブジェクトの配列
BrowserApp.selectedTab // 現在選択しているTabオブジェクト
BrowserApp.selectedBrowser // 現在選択しているxul:browser要素
BrowserApp.addTab() // タブを開く
BrowserApp.closeTab() // タブを閉じる
BrowserApp.selectTab() // タブを選択する
BrowserApp.deck // xul:deck要素
など
Native UIの機能を呼び出すAPI
NativeWindow.menu.add() // メニュー項目を追加
NativeWindow.contextmenus.add() // コンテキストメニュー項目を追加
NativeWindow.toast.show() // トースト型通知を表示
NativeWindow.doorhanger.show() // ドアハンガー型通知を表示
など
Javaで実装された機能を呼び出す、より低レベルなAPI
内部的にはnsIAndroidBridge::handleGeckoMessage
sendMessageToJava({
gecko: { type: "ToggleChrome:Show" }
})
sendMessageToJava({
gecko: { type: "Tab:Select", tabID: aTab.id }
})
など
chrome.manifest と locale フォルダを追加
localeパッケージを追加
locale viewsource en-US locale/en-US/ locale viewsource ja locale/ja/
・locale/en-US/main.properties
menu=View Source
・locale/ja/main.properties
menu=ソースを表示
main.properties のchrome:URL
chrome://viewsource/locale/main.properties
ローカライズされた文字列を取得する関数
var gStringBundle;
function getString(aName) {
if (!gStringBundle) {
var uri = "chrome://viewsource/locale/main.properties";
gStringBundle = Services.strings.createBundle(uri);
}
return gStringBundle.GetStringFromName(aName);
}
function loadIntoWindow(aWindow) {
gMenuId = aWindow.NativeWindow.menu.add("View Source", null, function() {
viewSource(aWindow);
});
}
▼
function loadIntoWindow(aWindow) {
gMenuId = aWindow.NativeWindow.menu.add(getString("menu"), null, function() {
viewSource(aWindow);
});
}
chrome://global/content/console.xul
function log(aMsg) {
Services.console.logStringMessage(aMsg);
}
function alert(aMsg) {
Services.prompt.alert(null, "My Add-on", aMsg);
}
ツールバーがNative UIなので不可
将来的に NativeWindow.toolbar.add のようなAPIが追加されるかも?
オーバーレイして独自ツールバーを追加するなど、一応可能
ただでさえ画面が狭いので、現実的でない
chrome.manifestでcontentパッケージを追加して実現可能
aboout:addons やabout:downloads のようにXHTMLによる構築が主流?
可能
nsILocalFile のインスタンスを作るか、FileUtils.jsm モジュールを利用
<em:bootstrap>true</em:bootstrap> を削除すれば可能
XULオーバーレイが実質なくなったので、再起動不要が主流