Chrome拡張機能開発の公式チュートリアルを解説+補足 後編

#はじめに
この記事は

- [Chrome拡張機能開発の公式チュートリアルを解説+補足 前編](https://qiita.com/T-Kawashima/items/15af26bdb2b797534fad)

の続きです。
前編を読んでから、こちらを読むことをおすすめします。
前編では、チュートリアルの

1. マニフェストを作成
2. アップロード
3. Backgroundファイルを作成

の部分を解説しました。

後編では、

 ４. Popupファイルの作成
 ５. Contents Scriptへの反映
 ６. オプションの設定

を行います。

#チュートリアル
前回の記事までのチュートリアルはうまくいったでしょうか？
今回はユーザからの見た目の部分を中心にやっていきます。

##4. Popupファイルの作成
ポップアップとは、Chromeの右上あたりに追加されるChrome拡張のアイコンを押すことで表れるUIのことです。
下の画像では、「[YouTube™のための自分好み](https://chrome.google.com/webstore/detail/adblock-for-youtube/cmedhionkhpnakcndndgjdbohmhepckk?hl=ja)」という、YouTubeの広告をブロックしてくれる拡張機能のポップアップの例です。
<img width="1440" alt="ポップアップ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/9563485e-51f0-d782-16c4-c94543195e5f.png">
ここにラジオボタンとかを追加して、ユーザに拡張機能を使いやすくさせるわけです。

###4-1. popup.html
見た目はHTMLとCSSで制御しています。
早速`Popup.html`を書いてみましょう。
ここもファイル名は何でも良いですが、公式に乗っ取って「popup.html」にしておきましょう。

```popup.html
<!DOCTYPE html>
  <html>
    <head>
      <style>
        button {
          height: 30px;
          width: 30px;
          outline: none;
        }
      </style>
    </head>
    <body>
      <button id="changeColor"></button>
    </body>
  </html>
```

書けたら保存して、フォルダに保存してください。
この`popup.html`を使うということを、マニフェストファイルに教えてあげましょう。

```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"
    },

    "manifest_version": 2
}
```

書けたら保存しましょう。

###4-2. アイコンの設定
加えて、右上に表示されるアイコンも設定しましょう。
公式が準備してくれてるデータを使います。
↓ここからダウンロードしてください

- [アイコン by Chrome公式](https://developer.chrome.com/extensions/examples/tutorials/get_started/images.zip)

フォルダを解凍したら、`images`フォルダの中に4つの画像が入っているかと思います。
その`images`フォルダをそのままいつものフォルダにぶちこんじゃってください。
現在、フォルダの中はこうなっているはずです。
<img width="768" alt="Popupファイル&アイコン画像保存" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/2ebca253-878a-5ff1-ef7a-3bdacde9be9f.png">
マニフェストファイルに、アイコンとして保存した画像を使うということ教えましょう。
また、次に使う`declarativeContent`のAPIを許可するために、`permissions`に書き込んでおきます。

```manifest.json
{
    "name": "Test Chrome-Extension",
    "version": "1.0",
    "description": "これはChrome拡張機能のテストです。",

    "permissions": ["declarativeContent", "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"
      }

    },

    "icons": {
      "16": "images/get_started16.png",
      "32": "images/get_started32.png",
      "48": "images/get_started48.png",
      "128": "images/get_started128.png"
    },

    "manifest_version": 2
}
```

カンマとか付け忘れないように注意してください！（コピペすれば大丈夫だと思いますが。）
なぜ二つアイコンの設定が書かれているのかというと、

- `page_action`の中の`default_icon` → ポップアップのアイコン
- `icons` → ファビコンや拡張機能の管理画面でのアイコン

の2種類を設定したためです。

###4-3. declarativeContent
さて、先ほど`declarativeContent`のAPIを使うといいましたが、これは一体なんなのかというと、Contents Scriptの構成を取得できて、指定した要素の有無に応じてポップアップを表示させるか否かを指定できるようにするものです。

`background.js`に下記のコード追加して保存してみましょう。

```background.js
  chrome.runtime.onInstalled.addListener(function() {
    chrome.storage.sync.set({color: '#3aa757'}, function() {
      console.log('The color is green.');
    });

    chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
      chrome.declarativeContent.onPageChanged.addRules([{
        conditions: [new chrome.declarativeContent.PageStateMatcher({
          pageUrl: {hostEquals: 'developer.chrome.com'},
        })
        ],
            actions: [new chrome.declarativeContent.ShowPageAction()]
      }]);
    });

  });
```

上の公式の例で言うと、

- `conditions`の`pageUrl`ところで、URLに`developer.chrome.com`が含まれているかを見ています。
- 含まれていると判断されたとき、`actions`で`ShowPageAction()`（ポップアップを表示させるように）しています。

###4-4. popup.jsを作成
最後に、宣言したAPIを用いて、PopupからContents Scriptを動かすコードを書きます。
`popup.js`というファイルを作って、下記のコードを書いて保存してください。

```popup.js
  let changeColor = document.getElementById('changeColor');

  chrome.storage.sync.get('color', function(data) {
    changeColor.style.backgroundColor = data.color;
    changeColor.setAttribute('value', data.color);
  });
```

ここでは、単純にボタンの背景色をJSから変更することを書いています。
そして、今度はこのファイルを使うということを、`popup.html`の`</body>`の直前に書き込んできださい。
ここはいつものHTMLとJSを繋げるのと同じですね。

```popup.html
<!DOCTYPE html>
<html>
...
  <body>
    <button id="changeColor"></button>

    <script src="popup.js"></script>

  </body>
</html>
```

できたら保存して、拡張機能の管理画面で更新してみましょう！
<img width="770" alt="ここまでのファイル構成" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/64d5ce3f-4648-93e5-a5af-6875192d5046.png">

左が`developer.chrome.com`がURLに含まれているサイトでも表示で、右が含まれていないサイトでの表示です。
<img width="607" alt="ポップアップ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/3402d5fd-2c86-11cc-d488-4c6cdadb3c28.png">
`declarativeContent`で指定したように、`developer.chrome.com`がURLに含まれていないサイトでは、アイコンが白黒になりポップアップが表示されないようになっています。

ここまでうまくできたら、最後の章へ進みましょう。

##5. Contents Scriptへの反映
ポップアップでボタンを押したら、ウェブサイトの背景の色を変更するような機能を作っていきます。
そのためには、PopupとContents Scriptの世界どうしで通信を行う必要があります。
それを可能にするために、まずはマニフェストファイルの`permission`に`activeTab`を追加しましょう。
これは、`tabs.executeScript`という、別の世界からウェブサイトのスクリプトを操作できるコードを使えるようにできるAPIです。

```manifest.json
  {
    "name": "Getting Started Example",
    ...
    "permissions": ["activeTab", "declarativeContent", "storage"],
    ...
  }
```

書いて保存したら、`popup.js`に下記のコードを書きましょう。

```popup.js
  let changeColor = document.getElementById('changeColor');
  ...

  changeColor.onclick = function(element) {
    let color = element.target.value;
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
      chrome.tabs.executeScript(
          tabs[0].id,
          {code: 'document.body.style.backgroundColor = "' + color + '";'});
    });
  };
```

- `chrome.tabs.query ...` → 操作するウェブサイトのタブのIDを取得
    - `chrome.tavs.executeScript ...` → 取得したIDのタブのスクリプトを操作
        - `code: ...` → 実行するスクリプト、この場合背景の色を変更している

補足ですが、PopupからContents Scriptへ通信をするには`chrome.tabs.query`で行けますが、他の世界どうしではこの方法でできるとは限りません。

- [Chrome Extension の作り方 (最終話: メッセージパッシング) - Qiita](https://qiita.com/sakaimo/items/5e41d6b2ad8d7ee04b12)

この方の記事に世界どうしの通信方法が分かりやすく書いてありますので、見てみてください。

これでポップアップのボタンを押すと、そのサイトの背景色が変わるようになりました。
今の所、URLに`developer.chrome.com`が含まれているサイトじゃないと実行できないので注意です。
![変更.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/bedc2a99-dec8-78a6-8c8f-08b3513105b0.gif)

##6. Optionsの設定
Optionsとは、ユーザが拡張機能のより詳細な設定をさせたいときに追加する世界です。
Popupとはまた別のページを作ります。
[拡張機能詳細ページ](chrome://extensions/) から開けます。
<img width="412" alt="スクリーンショット 2019-12-26 17.52.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/1418a407-279c-70ed-1e27-30f296117b3d.png">
<img width="1440" alt="スクリーンショット 2019-12-26 17.52.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/a2dee98d-80f7-8a9c-0dca-f58ab7a8975b.png">
まだOptionsを設定してないので、②は表示されていないと思うので、これから設定していきましょう。

まず、`options.html`と`options.js`を作ります。
チュートリアルでは、オプションページで背景色を変更できるようなオプションを追加します。

```options.html
 <!DOCTYPE html>
  <html>
    <head>
      <style>
        button {
          height: 30px;
          width: 30px;
          outline: none;
          margin: 10px;
        }
      </style>
    </head>
    <body>
      <div id="buttonDiv">
      </div>
      <div>
        <p>Choose a different background color!</p>
      </div>
    </body>
    <script src="options.js"></script>
  </html>
```

```options.js
let page = document.getElementById('buttonDiv');
  const kButtonColors = ['#3aa757', '#e8453c', '#f9bb2d', '#4688f1'];
  function constructOptions(kButtonColors) {
    for (let item of kButtonColors) {
      let button = document.createElement('button');
      button.style.backgroundColor = item;
      button.addEventListener('click', function() {
        chrome.storage.sync.set({color: item}, function() {
          console.log('color is ' + item);
        })
      });
      page.appendChild(button);
    }
  }
  constructOptions(kButtonColors);
```

ボタンを4つ作り、ボタンによって`storage`の`color`を変更します。

オプションページを使うということをマニフェストファイルに教えてあげましょう。

```manifest.json
  {
    "name": "Getting Started Example",
    ...
    "options_page": "options.html",
    ...
    "manifest_version": 2
  }
```

ここまでできたら、拡張機能を更新して、先ほどの②の「拡張機能のオプション」ページを開いてみましょう。
<img width="1440" alt="スクリーンショット 2019-12-26 18.09.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/3a9418d0-ce2b-2fb2-3ae7-69207ab58284.png">
オプションページで赤のボタンを押すと、ポップアップで背景色を赤に変更することができました！
<img width="1440" alt="スクリーンショット 2019-12-26 18.09.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298379/7ca92014-ed34-24fd-3419-9261826e8160.png">

#おわりに
うまくチュートリアルを実行することができたでしょうか。
意外と簡単にChrome拡張機能が開発できますね。

不足あったらコメントください。

前編はこちら

- [Chrome拡張機能開発の公式チュートリアルを解説+補足 前編 - Qiita](https://qiita.com/T-Kawashima/items/15af26bdb2b797534fad)

公式のチュートリアルページはこちら

- [Getting Started Tutorial - chrome](https://developer.chrome.com/extensions/getstarted)