- 開発技術
Chrome用に開発した拡張機能をfirefox対応させる際にハマったこと
- その他
目次
未審査の拡張機能をfirefoxにインストールする方法
【エンジニア募集中】フルリモート可◎、売上/従業員数9年連続UP、平均残業8時間、有給取得率90%、年休124日以上 etc. 詳細はこちらから>
chromeの場合はローカルでビルドしたファイル(Vue.jsなどのフレームワークを利用している場合)を拡張機能管理画面で追加してあげれば利用可能ですが、firefoxでは色々と手順が異なっており手間取りました。
firefoxでローカルビルドした拡張機能をインストールするためには以下の手順が必要となります。
・「firefox Developer Edition」のインストール
・ブラウザの設定変更
・ビルドしたファイルをzip化してインストール
「firefox Developer Edition」のインストール
まず、通常のfirefoxのアプリではなく「firefox Developer Edition」という開発者向けのアプリをインストールする必要があります。
ブラウザの設定変更
上記のインストールが完了したら、続いて「firefox Developer Edition」の設定を変更します。
①まずは、ブラウザのアドレスバーに「about:config」と入力します。
②設定画面の検索窓に「xpinstall.signatures.required」と入力して、設定を「false」に変更してください。
ビルドしたファイルをzip化してインストール
①拡張機能のソースファイルをzip化します。zipファイルを解凍後に「manifest.json」がルートにある必要があるため、ソースファイルのラッピングフォルダを圧縮するのではなく、中身を選択してzip化する必要があることに注意してください。
②ブラウザのアドレスバーに「about:addons」と入力しましょう。
③右上の歯車マークから、「ファイルからアドオンをインストール」を押下し、手順①で作成したzipファイルを選択することで、インストールが可能です。
外部サイトとのメッセージパッシング
chromeでは拡張機能と外部サイトでデータのやり取りをする際に、backgroundにてchrome.runtime.onMessageExtenal.addListener
で待受状態にすることで、外部とのやり取りが可能ですが、現状firefoxではmanifest.jsonのプロパティであるexternally_connectable
がサポートされておらず、外部サイトとの連携ができません。
chromeの場合
このため、外部サイトとのやり取りに一工夫必要となります。
やり方としては、ブラウザ上で実行されるcontent-scriptに対して、windowオブジェクトのpostMesasgeでメッセージを送信し、content-scriptとbackgroundでさらにメッセージのやり取りをするという方法でやり取りが可能となります。
イメージとしては以下のような形となります。
以下に、上記の図をスクリプト化しておきました。
一例ですので要件に応じて、スクリプトを変更してください。
front.js(外部サイトのスクリプト)
1 2 3 4 5 6 7 |
window.addEventListener("message", () => { if(event.data.from !== "content-script"){ return; } console.log("onMessage") }); window.postMessage({ from: "web-front", command: {method: "is-response"} }, "*"); |
content-script.js
1 2 3 4 5 6 7 8 9 |
window.addEventListener("message", async (event) => { const senderUrl = new URL(event.origin); if(event.data.from !== "web-front" || !(senderUrl.hostname.includes("外部サイトのホスト"))){ return; } browser.runtime.sendMessage(event.data.command, (response) => { window.postMessage({ from: "content-script", response: response}, "外部サイトのURL") }) }) |
background.js
1 2 3 4 5 6 7 8 9 |
browserApi.runtime.onMessage.addListener(function (request, sender, sendResponse) { switch (request.method) { case "is-response":{ sendResponse(true) break; } } }) |
WebExtensions API とchrome APIの違い
一部、説明のためにMozilla Docsを引用しています。
ネームスペースの違い
Chrome では、拡張機能は chrome
ネームスペースを使って特権 JavaScript API にアクセスします
1 |
chrome.browserAction.setIcon({path: "path/to/icon.png"}); |
WebExtensions は同等の API に browser
ネームスペースを使ってアクセスします
1 |
browser.browserAction.setIcon({path: "path/to/icon.png"}); |
コールバックとプロミス
多くの API は非同期です。 Chrome では、非同期 API はコールバックを使用して値を返し、runtime.lastError
がエラーを通知します:
1 2 3 4 5 6 7 8 9 10 11 12 |
function logCookie(c) { if (chrome.extension.lastError) { console.error(chrome.extension.lastError); } else { console.log(c); } } chrome.cookies.set( {url: "https://developer.mozilla.org/"}, logCookie ); |
同様の WebExtensions API では promises を利用します:
1 2 3 4 5 6 7 8 9 10 11 12 |
function logCookie(c) { console.log(c); } function logError(e) { console.error(e); } var setCookie = browser.cookies.set( {url: "https://developer.mozilla.org/"} ); setCookie.then(logCookie, logError); |
上記の違いがあるため本案件では、chrome APIを利用する場合は関数をラッピングし、Promiseを返すように変更しました。
1 2 3 4 5 6 7 8 9 |
const selectBrowserApi: any = window.chrome; const sendMessageFunc = selectBrowserApi.tabs.sendMessage; selectBrowserApi.tabs.sendMessage = (id: any, data: any) => { return new Promise((resolve) => { sendMessageFunc(id, data, (response: any) => { resolve(response) }); }) } |
【エンジニア募集中】フルリモートも◎(リモート率85.7%)、平均残業8時間、年休124日以上、有給取得率90% etc. 詳細はこちらから>