Firefox のWebExtensions のチュートリアルを試してみた
Firefox 44 から拡張機能は、 XUL からChrome, Operaも採用している WebExtensions が推奨されるようになりました。
Firefox でのWebExtensions の拡張機能の作り方 のチュートリアルを試してみたのでメモ。
環境
試した環境は以下です。
署名なしインストール
Firefoxの拡張機能(アドオン)は、 署名がないとインストールできないが、 Nightly やDeveloper Edition であれば、 設定してインストールすることができる。
Firefox のアドレスバーに about:config と入力して下さい。
(「細心の注意を払って使用する」をクリック)
「xpinstall.signatures.required」 を検索して下さい。
設定をダブルクリックするか、右クリックして "切り替え" を選択して、false にセットしてください。
デバッグ
拡張機能のコードに、 console.log();
しても コンソール(DOM Console)には表示されない。
「ブラウザツールボックス」のコンソールでデバッグすることができるので、 その設定をする。
Developer Toolsから「開発ツールのオプション」を開く。
「ブラウザとアドオンのデバッガを有効」と 「リモートデバッガを有効」 にチェックを入れる。
引用:https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Debugging
「Web開発ツール」から、 「ブラウザツールボックス」を開く。 このコンソールでデバッグできる。
WebExtensions の構成
Google Chrome のWebExtensions とほぼ同じ設定。
Doc: Anatomy of a WebExtension - Mozilla | MDN
manifest.json
ファイルに、 background
、 content_scripts
、 browser_action
のファイル、 web_accessible_resources
ファイルの設定をする。
background
バックグラウンドで動くjs, html を指定できる。
background のjs は、拡張機能を有効にするとに実行される。 以下の特徴がある。
-
WebExtension API をすべて使うことができる。
-
XHRを使ってCross-originのアクセスができる。
-
popup を設定してなくてもBrowser actionsを使うことができる。
また、 なので、WebExtension API を一部しか使えないcontent_scripts と連携して 使ったりする。
content_scripts
Webページを操作するJS とCSS を設定できる。 特徴は以下の3つ。
-
Cross-domainのXHRでアクセスできる。
-
WebExtension APIの一部を使うことができる。
-
background (scripts)とmessage を交換して、WebExtensionAPIを間接的に 全部使える。
browser_action
popup を設定することで、 toolbar にアイコンを配置できる。 popup用のメニューになるようなhtml, css, js を指定できる。 jsは、アイコンをクリックした時に有効になる。
web_accessible_resources
アクセスできるリソースを設定する。画像、HTML, CSS, JS など いろいろなファイルを設定できる。 jQuery等のファイルも指定できる。
チュートリアル
browser_action(popup)を使ったチュートリアル
「beastify」というbrowser_action を使ったチュートリアルを試してみたのでメモ。
toolbar に表示されるアイコンをクリック。 メニュー用HTMLにあるリスト(Frog, Turtol, Snake) をクリックすると、 現在のWebページ(DOM)にその画像を追加する拡張機能です。
Tutorial: Walkthrough - Mozilla | MDN
プロジェクト(ディレクトリ)の作成
適当な場所に、プロジェクト用のディレクトリを作成。
mkdir project_dir
cd project_dir
manifest.jsonファイルの作成
manifest.jsonファイルの作成する。
-
manifest_version
: manifest のバージョンを指定。 現時点() では「2」が最新のようです。 -
"name"
: 拡張機能の名前 -
"version"
: 拡張機能のバージョン -
"applications"
: 他の拡張機能と被らないようメールアドレス形式の id などを指定。 -
"permissions"
: パーミッションの設定。["http://*/*", "https://*/*"]
httpページ, httpsページのみ有効となる。 -
"browser_action"
:-
default_icon
: アイコン(ボタン)葉の画像を指定。 -
default_title
: optionでタイトルを指定。tooltipで表示される。 -
default_title
: popupするときのhtmlを指定。 アイコンをクリックすると、ここで指定したhtml が表示される。
-
-
web_accessible_resources
: リソースを指定。今回はDOMに追加する画像ファイル。
{
"manifest_version": 2,
"name": "Beastify",
"version": "1.0",
"applications": {
"gecko": {
"id": "beastify@sample"
}
},
"permissions": [
"http://*/*",
"https://*/*"
],
"browser_action": {
"default_icon": "button/beasts.png",
"default_title": "Beastify",
"default_popup": "popup/choose_beast.html"
},
"web_accessible_resources": [
"beasts/frog.jpg",
"beasts/turtle.jpg",
"beasts/snake.jpg"
]
}
popup用のファイルの作成
popup用htmlでも、DOCTYPE宣言などして 通常のHTMLと同じように書く。
-
choose_beast.html
:<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="choose_beast.css"/> </head> <body> <header> <h3>Hello World, Extensions</h3> </header> <main> <ul class="beasts"> <li class="beast">Frog</li> <li class="beast">Turtle</li> <li class="beast">Snake</li> </ul> </main> <script src="choose_beast.js"></script> </body> </html>
-
choose_beast.css
:html, body { width: 14rem; margin: 0; } main{ width: 100%; margin: 0; } .beasts { width: 100%; margin: 0; padding: 0; } .beast { display: block; width: 50%; margin: .5rem auto; padding: .3rem 0; border-radius: .3rem; text-align: center; font-size: 1.1rem; background-color: #E5F2F2; cursor: pointer; } .beast:hover { background-color: #CFF2F2; }
-
choose_beast.js
:chrome.tabs.executeScript(null, { file: "~~.js" });
で、acitive tab で指定のスクリプト(content_scripts)を実行させるchrome.tabs.query()
で、 active tabの取得。function(tabs) { chrome.tabs.sendMessage(tabs[0].id, {beast: chosenBeast}); }
: active tab にmessage を送る。document.addEventListener("click", function(e) { if (!e.target.classList.contains("beast")) { return; } console.log('addEventListener click'); var chosenBeast = e.target.textContent; /* chrome.tabs.executeScript: active tabで指定のscript を実行させる */ chrome.tabs.executeScript(null, { file: "content_scripts/beastify.js" }); /* get the active tab */ chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { //send a message to content scripts running in the active tab chrome.tabs.sendMessage(tabs[0].id, {beast: chosenBeast}); }); });
content_scriptsの作成
popup のjs からmessage を受け取り、 content_scripts がコールバックで動作し、 webページに画像を追加する。
// Assign beastify() as a listener for messages from the extension.
chrome.runtime.onMessage.addListener(beastify);
function beastify(request, sender, sendResponse) {
if (!request.beast){
return;
}
// DOMのbodyの中にある要素を全て削除
removeEverything();
// img要素を作りbody に挿入
insertBeast(beastNameToURL(request.beast));
chrome.runtime.onMessage.removeListener(beastify);
}
function removeEverything() {
while (document.body.firstChild) {
document.body.firstChild.remove();
}
}
function insertBeast(beastURL) {
var beastImage = document.createElement("img");
beastImage.setAttribute("src", beastURL);
beastImage.setAttribute("style", "width: 100vw");
beastImage.setAttribute("style", "height: 100vh");
document.body.appendChild(beastImage);
}
function beastNameToURL(beastName) {
switch (beastName) {
case "Frog":
return chrome.extension.getURL("beasts/frog.jpg");
case "Snake":
return chrome.extension.getURL("beasts/snake.jpg");
case "Turtle":
return chrome.extension.getURL("beasts/turtle.jpg");
}
}
ファイル構成
最終的なファイル構成
-
beastify/
xpiファイルの作成
最後に、zipコマンドでxpiファイルを作成する。
zip -r 拡張機能名.xpi *
動作確認
xpiファイルをFirefox にドラッグしてインストール。 アイコンをクリックでのpopup は以下のようになる。
background とnotificationを使ったサンプル
上記のチュートリアル ではbackground を使ってないが、このサンプルではbackground を使っている。 また、chrome API のnotification を使っている。
content_scripts とbackground がmessage で通信する。
-
permissions: notifications
でnotificationを使うことができる。content_scripts
で、 content_scriptsの設定をする。maches
で 有効にするWebページを指定。
manifest.json
:{ "manifest_version": 2, "name": "notify", "version": "1.0", "applications": { "gecko": { "id": "notify@my" } }, "permissions": [ "notifications" ], "web_accessible_resources": [ "link.jpg" ], "background": { "scripts": ["background/background-script.js"] }, "content_scripts": [ { "matches": ["http://*/", "https://*/"], "js": ["content-scripts/notify.js"] } ] }
-
chrome.runtime.sendMessage({"url": e.target.href});
で、background にhref属性をmeassage として送る。content_scripts/notify.js
:window.addEventListener("click", notifyExtension); function notifyExtension(e) { //console.log('event: ', e); if (!e.target) { return; } var target = e.target; //console.log('target: ', target); if (target.href){ console.log("content script sending message"); chrome.runtime.sendMessage({"url": target.href}); } else { if (!target.hasChildNodes()) { return; } var childNodes = target.childNodes; for(var i = 0; i < childNodes.length; i++){ var childNode = childNodes[i]; if(childNode.href){ console.log("content script sending message: chilednode"); chrome.runtime.sendMessage({"url": childNode.href}); return; } } } }
-
chrome.runtime.onMessage.addListener(notify);
で、 content_scriptsからmessage を受け取る。chrome.notifications.create({ "type": , "iconUrl": , "title": , "message": });
で、notification を生成する。background
:chrome.runtime.onMessage.addListener(notify); function notify(message) { if(!message.url){ return; } console.log("background script received message"); chrome.notifications.create({ "type": "basic", "iconUrl": chrome.extension.getURL("link.jpg"), "title": "You clicked a link!", "message": message.url }); }
リンクをクリックして click event が発火するWebページでは、以下のように、 notification(通知) が生成される。 (Googleの検索結果では、 リンクを左クリックしても発火しないようです。右クリックと 新しいタブで開くだと発火するようです。)