皆さん、Chrome拡張機能をご存知ですか? Chrome拡張機能は、Chromeブラウザをカスタマイズするための機能です。
私は、Chrome拡張機能を過去(数年前)に2つ作っていて、その当時は、Chrome拡張機能の仕様であるManifest V2に従っていました。 そして、今再び、Chrome拡張機能で作りたいものができたので、久々に作ろうと決意しました。 作ろうと思ったものの、どうやら今のChrome拡張機能の仕様はManifest V3を推奨しているようです。 そこで、今回、開発した際に知ったことをまとめようと思います。
ちなみに、実際に作ったものは次のものです。
※ Chrome拡張機能の概要について詳しく知りたい方は、What are extensions? - Chrome Developersをご覧ください。
Chrome Extensions Components
Chrome拡張機能は、主に次の4つのコンポーネントが存在します。
- Background Scripts
- サービスワーカー上で動作し、ブラウザ上のイベント駆動(ページ遷移やブックマーク差所など)で反応します。
- manifestの
background
フィールドで設定します。
- Content Scripts
- Webページのコンテキスト上で動作し、DOMへアクセスできます。
- manifestの
content_scripts
フィールドで設定します。
- UI Elements
- URLバーの右側にあるボタンを押した(Action)際に表示されるUIです。
- ブラウザ体験を損なわさない最低限の機能だけの提供を推奨されています。
- manifestの
action
フィールドで設定します。
- Options Page
私なりに、これらのコンポーネントの使い分けを考えると、次になります。
- DOMへアクセスする必要がある
- Content Scripts を使う
- ページに依存しない処理がある
- Background Scripts を使う
- 環境変数の設定が必要
- Option Page
UI Elementsは、基本的に必要ないのかなと思いました。
Debug
デバッグって、どうやるんでしょうか。
こちらにやり方が書いてありました。 私なりに解釈した結果、次の2つで使い分けるのかなと思います。
manifest.jsonファイルに記述で誤りがあるなどで、Chrome拡張機能がロードできない場面があります。 そういうときは、次の手順を実行します。
chrome://extensions
へアクセス- 次の図にあるようなERRORボタンをクリック
恐らく、何かしらエラーメッセージが出力されていると思います。 それを解決しましょう。
- ② ①以外の場合
Chrome拡張機能はロードできるが、期待通りに動作しない場面があると思います。 そういうときは、DevToolsを開きましょう。
- Background Scripts の場合
chrome://extensions
へアクセスし、inspect views
の右にあるリンクをクリック。(上図)- DevToolsが開きます。
- Content Scripts, UI Elements, Options Page の場合
- UI上で右クリックして
Inspect
をクリック- DevToolsが開きます。
- UI上で右クリックして
DevToolsには、consoleタブがあるはずです。そこのログメッセージを確認しましょう。
Message Passing
各コンポーネント間で、通信するのは、どうしたら良いのでしょうか。 例えば、Content ScriptsからBackground Scriptsへデータを渡したいときなどです。 次の資料が、参考になります。
資料を読むと、次のようなパターンの通信ができるようです。
- 各コンポーネント間の通信
- Background Scripts ⇔ Content Scripts など
- Chrome拡張機能間の通信
- Webページからの通信(Sending messages from web pages)
通信の具体的なコードは、chrome.runtime.sendMessage
メソッドを使います。
Background ScriptsからContent Scriptsへ通信する場合、どのChromeタブに送信するかchrome.tabs.query
で事前にidを見つけておく必要があります。
また、後で紹介しますが、Web Accessible Resources
でアクセス可能なJavascriptをWebページへInject(document.querySelector('body').append()
)した場合、そのJavascriptとContent Scriptsの通信は、window.postMessage
とwindow.addEventListener
を使いましょう。
chrome.runtime
が使えないので。
Web Accessible Resources
Content ScriptsからWebページのDOMへアクセスできますが、windowオブジェクトにある変数へアクセスすることができません。
windowオブジェクトへアクセスするには、Web Accessible Resourcesを使う方法があります。
具体的にコードで説明しましょう。
manifest.jsonで必要なフィールドの例は、次のとおりです。
{ "manifest_version": 3, "content_scripts": [ { "js": [ "content-script.js" ], "matches": [ "https://*/*" ] } ], "web_accessible_resources": [ { "resources": [ "web_accessible_resources.js" ], "matches": [ "https://*/*" ] } ] }
Content ScriptsとWeb Accessible ResourcesのJavascriptは次のとおりです。
// content-script.js const injectScript = (filePath, tag) => { var node = document.getElementsByTagName(tag)[0]; var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('src', filePath); node.appendChild(script); } injectScript(chrome.runtime.getURL('web_accessible_resources.js'), 'body');
// web_accessible_resources.js console.log(window['hoge']); // Content Scriptsへ通信する場合は、window.postMessageを使います。
このように、web_accessible_resources.jsをWebページのbodyタグへappendします。 そのweb_accessible_resources.jsでは、windowオブジェクトにアクセスすることができます。
chrome.webRequest API
Chromeブラウザでネットワークトラフィックを監視するChrome拡張機能のAPIがあります。
それが、chrome.webRequest
です。
これがあれば、Webページでどういうリクエストが発生しているか分かるようになります。
manifest.jsonのフィールドで、host_permissions
の設定が必要です。
サンプルで、Background Scriptsのコードを紹介します。 まず、manifest.jsonの必要なフィールドを書きます。
{ "manifest_version": 3, "host_permissions": [ "https://*/*" ], "background": { "service_worker": "background.js" } }
次に、Webページからリクエストが完了(onCompleted)したイベントを監視するコードを書きます。
// background.js chrome.webRequest.onCompleted.addListener( async (details) => { console.log(`request url is ${details.url}`); }, { urls: [ "https://*/*" ] }, ["responseHeaders"] // responseHeadersをdetailsオブジェクトに含めることができます。 );
このdetailsにはリクエストのURLが含まれています。さらに詳しく知りたい人は、こちらをご確認ください。
最後に
Chrome拡張機能、久々に開発してみると、進化しすぎていてキャッチアップに苦労しました。 私と同じような方の助けになれば、幸いです。