📖

Chrome拡張機能 ManifestV3移行のために、V2について確認してみた

2021/12/15に公開

はじめに

V3にアップデートするにあたって、公式のガイドを元に変更点を整理し始めました。
しかし、そもそもV2が分かっていないゆえに「?」となっていた点がありました。
そこで、「?」をピックアップして、まずはV2がどうなっていたのかについて整理することにしました。

V2がそもそも理解があやふやだけどV3移行にチャレンジしたいという、同じような方の参考になればと思い記事化します。

やってみたこと

公式ドキュメントの確認

まず何が分かっていないか確認するために、公式のV3へのマイグレーションガイドを見てみましょう。
これで分かるなら別にやることはないのだ。

ガイドから要点と「何がわからないのか」をピックアップして整理してみました。
(注)筆者の意訳です。

  • Service workersがバックグラウンドページに取って代わられる
    • バックグラウンドページって何?
  • NWリクエストの変更は declarativeNetRequest API に取って代わられる
    • そもそもNWリクエストの変更って、何をどうやって行っていたの?
  • リモートでホストされたコードは変更できない。拡張機能のパッケージ内に含まれるJavaScriptのみが実行できる
    • リモートでホストされたコードの実行って、何をどうやって行っていたの?
  • Browser Action APIとPage Action APIはAction APIに統合される
    • Browser Action APIとPage Action APIって何?
  • WEBアクセス許可は、事前に明記されたサイトだけ使用可能
  • 拡張機能は任意の文字列を実行できなくなり、スクリプトファイルと関数のみを実行できるようになりました。このメソッドは、TabsAPIから新しいScriptingAPIにも移行しています。
    • evalダメってこと?
    • Tabs APIって何?
    • Scripting APIって何?

V3にアップデートする前に、そもそもChromeの拡張機能開発で分かっていないことが多すぎました。そのため、一旦V2までのChromeの拡張機能開発について勉強することにしました。

ぶっちゃけ移行マイグレーションチェックリストという公式ガイドを見れば漫然とできちゃうと思うのですが、とはいえもうちょい理解しておきたいな、という温度感です。

V2までのChrome拡張機能について

最初に次の記事を見ながら、ざっと概要を掴みました。

  • 初めてでも理解できるようになる「Google Chrome機能拡張の開発」 | OXY NOTES https://oxynotes.com/?p=8836
    • 図が豊富で、説明もシンプルでとっかかりとして非常にわかりやすかったです
  • サービスワーカー API - Web API | MDN https://developer.mozilla.org/ja/docs/Web/API/Service_Worker_API
    • Service Workersとは何か?について必要十分に、例も交えて説明してくれるので分かりやすいです

その上で、公式の「About Manifest V2」を確認し、裏付けを取りました。

概要

V2までの仕様をまとめてみました。
(注)筆者の意訳です。

  • Chromeでは次の機能を拡張できる
    • ブラウザアクション(ツールバーのアイコンクリックで起動するやつ)
    • ページアクション(ページ読み込み時に起動するやつ)
    • コンテンツスクリプト(ページ読み込み時に起動やつ。ただし特定のURLでのみ)
    • コンテキストメニュー(右クリックメニューの項目クリックで起動するやつ)
  • 「Chrome拡張機能」は、それらの一部か全部に対して作用するものである
  • 拡張機能に必須なファイルは以下である
    • manifestファイル
    • HTMLファイル
    • JavaScriptファイル
    • その他(CSSやアイコンなどのアセット)
  • manifestファイルに必須な項目は次の3つである: manifest-version, name, version
    • 具体的にはこんな感じになる
    manifest.json
    "name": "Getting Started Example",
    "version": "1.0",
    "description": "Build an Extension!",
    "manifest_version": 2
    
  • 具体的に作ってみるなら、Getting Startedの項をみれば簡単にできる

バックグラウンドページとイベントページ

  • 拡張機能であるからには、呼び出された時に実行される.jsファイルと、その指定がその指定が必要になる。
  • 呼び出されるたびに実行されるJavaScriptファイルを「バックグラウンドページ」という
  • 指定は、具体的にはmanifest.jsonでこのように行う
manifest.json
{
  "name": "Getting Started Example",
  "version": "1.0",
  "description": "Build an Extension!",
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "manifest_version": 2
}

じゃぁ、そのバックグラウンドページって何なんでしょうか?

バックグラウンドページについて

  • バックグラウンドページは拡張機能が実行時に呼び出されるJavaScriptファイルである。
  • 拡張機能の裏で常にメモリ上に展開されている
  • 拡張機能を読み込んだ時に1度だけ実行する処理や、イベントリスナの登録が必要な場合に有用である
  • 例えば、「クリックした時にダイアログを表示する」など。

ところで、拡張機能から呼び出される.jsファイルにはもう1つの種類があります。「イベントページ」です。何が違うんでしょうか?

イベントページについて

  • バックグラウンドページは「常にメモリ上に展開され続ける」ことのデメリットがある
    • 具体例を一つ上げると、単純に動作が重くなってしまうというのが挙げられる。
  • イベントページは、一定の時間が経過すると無効になり、メモリを開放する
  • よって、同じことをするならイベントページで行うのがよい。それができない場合のみバックグラウンドページを使うべきである
  • イベントページを利用するためには次のように記述する
      "background": { "scripts": ["background.js"], "persistent": false },  
  • メッセージパッシングやチャンネルを利用して、バックグラウンドページ側とメッセージのやりとりができる
  • 同様に、ストレージを利用してやり取りすることもできる
    • ストレージを使うなら次のようにpermissionの指定が必要
    manifest.json
    {
      "name": "Getting Started Example",
      "version": "1.0",
      "description": "Build an Extension!",
      "permissions": ["storage"],
      "background": {
        "scripts": ["background.js"],
        "persistent": false
      },
      "manifest_version": 2
    }
    
  • イベントページは10数秒で無効になってしまうので、chrome.alerms APIを利用して延長するとよい

ところで、裏で動作するんじゃなくて、現在ユーザが表示中のページを構成しているDOM要素を読み込んだり変更を加えたりするにはどうするのでしょうか?そこでは「コンテンツスクリプト」が必要になります。

コンテンツスクリプトについて

  • 実行させたいjsと、実行するための条件を指定します。
  • 具体的には実行させたいURLと実行するjsを次のように指定します。
     "content_scripts": [
          {
               "matches": ["https://www.google.co.jp/*"],
               "js": ["jquery-2.1.3.min.js", "myscript.js"]
          }
     ]

https://oxynotes.com/?p=8960 から引用させていただきました

これで、googleにアクセスした時にGoogleの背景を変更したりすることができます

ポップアップUI

ツールバーのアイコンをクリックした時にUIが表示される拡張機能を見たことがあると思います。
それはどうやっているのかというと、表示用のUIを構成する.htmlと、ツールバーアイコンと、その指定が行われています。こんな感じです。

popup.html
<!DOCTYPE html>
<html>
  <head>
    <style>
      button {
        height: 30px;
        width: 30px;
        outline: none;
      }
    </style>
  </head>
  <body>
    <button id="changeColor"></button>
  </body>
manifest.json
{
  "name": "Getting Started Example",
  "version": "1.0",
  "description": "Build an Extension!",
  "permissions": ["storage"],
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "page_action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "images/get_started16.png",
      "32": "images/get_started32.png",
      "48": "images/get_started48.png",
      "128": "images/get_started128.png"
    }
  },
  "manifest_version": 2
}

CSPについて

拡張機能を作成するに当たり、重要な制約が存在します。なぜなら、それ無しにはセキュリティが担保できないためです。

  • V2からコンテンツセキュリティポリシー(CSP)というものが導入された
  • CSPの目的はXSSや成りすましを防ぐことだと思われる
  • CSPで対応すべきことは次の3点
    • リソースの読み込み元をマニフェストファイルに明示する
    • 外部から渡されたコードを実行するような記述をしない
    • インラインでJavaScriptを記述しない
  • Ajax等で外部リソースと通信をする場合、 マニフェストファイルでリソース元を明示する必要がある
    • 例えば、デフォルトだとこうなっている
    "content_security_policy": "script-src 'self'; object-src 'self'",
    
    • それぞれの意味は次の通り
    script-src ‘self’	外部オリジンの全てのスクリプトを拒否
    object-src ‘self’	外部オリジンの全てのオブジェクト(画像など)を拒否
    
    • 例えば、Google Analyticsと通信するなど外部のリソースを読み込むには次のような記載が必要になる
    "content_security_policy": "script-src 'self' https://ssl.google-analytics.com; object-src 'self'"
    

さいごに

ざっくりとV2について理解しました。次は実際にV3移行に着手していこうと思います。

<追記>移行しました https://zenn.dev/katoaki/articles/4e7548b533d7b3

Discussion