Chrome Extension の作り方 (その3: Browser Action / Page Action)

[Chrome Extension の作り方 \(その1: 3つの世界\) \- Qiita](https://qiita.com/sakaimo/items/416f36db1aa982d8d00c)
[Chrome Extension の作り方 \(その2: Contents Script\) \- Qiita](https://qiita.com/sakaimo/items/6b7b464de4bdcad18802)

の続き。

Browser Action (Page Action) について説明します。

全てのページに対してアクションを起こしたい → [公式 Browser Action](https://developer.chrome.com/extensions/browserAction)
特定のページに対してアクションを起こしたい → [公式 Page Action](https://developer.chrome.com/extensions/pageAction)

というように使い分けるようです。


# できること

アイコンをクリックしたときに何かの処理をさせることができます。
ここでいうアイコンとは、ブラウザの右上に出るこれらのこと(下記の赤枠)

![ex07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/508ae64d-3ec9-b36d-d55c-97621149ec91.png)



# Browser Actionの例 

アイコンをクリックすると、現在開いているタブの数を表示する君を作ってみます。


## フォルダ構成

```
現在開いているタブの数を表示する君
  └icon16.png
  └jquery-3.4.0.min.js
  └manifest.json
  └popup.html
  └popup.js
```

## manifest_json

まずは `manifest_json` です。

```json:manifest.json
{
  "manifest_version":2,
  "name":"アイコンクリックしたらポップアップが出る",
  "version":"1.0",
  "permissions":["tabs"],
  "browser_action":{
    "default_icon": {
      "16": "icon16.png"
    },
    "default_title":"開いてるタブの数を表示する",
    "default_popup":"popup.html"
  }
}
```

今回の流れとして、

1. ある画面にアクセスする
2. アイコンがクリックされる
3. `default_popup` に定義されている `popup.html` を表示させる
4. その中のJavascriptを実行する

をやってみようと思います。


今回はExtensionから「Tabの情報」にアクセスしたいので、

```json:manifest.json
  "permissions":[
    "tabs"
  ],
```

が入ってます。


↓ここがBrowser Actionの設定箇所です。

```json:manifest.json
  "browser_action":{
    "default_icon": {
      "16": "icon16.png"
    },
    "default_title":"開いてるタブの数を表示する",
    "default_popup":"popup.html"
  }
```

アイコンには↓これを使いました。
![icon16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/9e309643-16f4-02d2-a627-6ba5c806b3de.png)


ここまでで `manifest.json` の中に

- アイコンには `icon16.png` を使用する
- アイコンをクリックすると `popup.html` を開く

という指定ができました。

## popup.html

次に `popup.html` ですが、ここは普通にHTMLを書けます。

```html:popup.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>popup</title>
  <style>
    body{
      width: 250px;
      height: 50px;
    }
  </style>
</head>
<body>
  <p id="tabnum"></p>
  
  <script src="jquery-3.4.0.min.js"></script>
  <script src="popup.js"></script>
</body>
</html>
```

アイコンがクリックされたら↑このポップアップが開きます。その中で `jquery-3.4.0.min.js` と `popup.js` が読み込まれます。

**注意！**
`Browser Action` を使うときには `popup.html`, `popup.js` が必要 **というわけではありません。**

今回は

- 「アイコンを押したら、ポップアップとしてHTMLを表示させたい」ので、そのHTMLのファイル名を `popup.html` と名付けた。
-  `popup.html` の中で呼び出すjavascriptファイル名を `popup.js` と名付けた、だけです。


## popup.js

```js:popup.js
chrome.tabs.query({},function(tabs){
  $('#tabnum').text('現在開いているタブの数は['+tabs.length+']個です')
});
```

`chrome.tabs.query` については [公式 chrome\.tabs](https://developer.chrome.com/extensions/tabs#method-query)

これで必要なファイルが揃いました。

## BrowserActionを実行する


`chrome://extensions/` を開いて、`現在開いているタブの数を表示する君`フォルダをドラッグ&ドロップしてインストール。

↓こんな感じで動作します。現在起動しているChromeの中にあるタブ数を表示してくれます。(別ウィンドウで開いていても合算されます)

![ex10.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/b8abfccc-e0d4-b8fc-91ef-57d338b1f771.gif)

- カーソル乗せると `default_title` に設定した値が表示される
- クリックすると `default_popup` に設定したhtmlが開く



もっとリッチな機能にするには、タブ数だけじゃなくて開いているサイトのタイトルとURLの一覧を表にして表示させる、とかできそうですね。。。


...


せっかくなのでやってみました。

`manifest.json` は上のやつそのまま使う。
`popup.html` と `popup.js` を下記のように変更。

```html:popup.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>popup</title>
  <style>
    body{
      width: 1000px;
      height: 800px;
    }
  </style>
</head>
<body>
  <p id="tabnum"></p>

  <table border="1">
    <thead></thead>
    <tbody></tbody>
  </table>

  <script src="jquery-3.4.0.min.js"></script>
  <script src="popup.js"></script>
</body>
</html>
```

```js:popup.js
chrome.tabs.query({},function(tabs){
  $('#tabnum').text('現在開いているタブの数は['+tabs.length+']個です');

  for(var i in tabs){
    $('tbody').after('<tr><td>'+tabs[i].title + '</td><td>' +  tabs[i].url + '</td></tr>');
  }
});
```

↓ 実行する(デザインセンスは無いけれど)

![ex17.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/42cceb24-c706-d393-e918-dc74c79496af.gif)



## Browser Action のデバッグ

例えば`popup.js` のデバッグをしたいと思います。
`console.log` を入れて実行したとします。


```js:popup.js
console.log("popup.jsが呼ばれた");

chrome.tabs.query({},function(tabs){
  $('#tabnum').text('現在開いているタブの数は['+tabs.length+']個です');
});
```

でも `content scripts` の時([その2:ContentScripts](https://qiita.com/sakaimo/items/6b7b464de4bdcad18802)参照)のようにデベロッパーツールを開いてもログは出力されていません。。。

これは、

- `content scripts` とは「いま表示されているサイト自体にscriptを挿入する」ものなので、そのサイト自体のconsoleに表示される。
  - → 普通にデベロッパーツールを表示すれば見える
- `browser action` (の中で使っている `popup.js`) は `popup.html` から呼ばれているので、 `popup.html` のconsoleに表示される。
  - → `popup.html` のデベロッパーツールってどこよ？

になります。

これは **アイコン右クリック → ポップアップを検証** で確認できます。

![ex11.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/bcc60860-26a9-aa2b-7436-5ba500dd3071.gif)


------

# Page Actionの例 

**「特定のページ」にのみ有効な Browser Action** のようです。

`page action` の処理の流れは下記のようになります。

1. ある画面にアクセスする
2. `background.js` にあるRuleに合えば(今回は「特定のURLならば」) `page_action`を有効にする(アイコンが有効になる)
3. アイコンがクリックされる
4. `default_popup` のHTMLを表示させる
5. その中にJavascriptがあればそれを実行する


**2の部分がBrowser Actionでは存在しなかったところです。**

例として、Browser Action のところで作ったExtensionを、「`qiita.com` ドメインに一致するURLにアクセスしたときにだけ」実行できるように変更してみます。


## フォルダ構成

```
page_action
  └background.js
  └icon16.png
  └jquery-3.4.0.min.js
  └manifest.json
  └popup.html
  └popup.js
```


## manifest.json

```json:manifest.json
{
  "manifest_version":2,
  "name":"qiitaでアイコンクリックしたらタイトルとURLをポップアップに表示させる君",
  "version":"1.0",
  "permissions":["tabs", "declarativeContent"],
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "page_action":{
    "default_icon": {
      "16": "icon16.png"
    },
    "default_title":"開いてるタブの数を表示する",
    "default_popup":"popup.html"
  }
}
```

- `permissions` に `declarativeContent` を追加
- `background` に `background.js` を追加(ファイル名は任意です)

## background.js

```js:background.js
// 現時点でのruleをクリア(removeRules)して
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
  // 新たなruleを追加する
  chrome.declarativeContent.onPageChanged.addRules([{
    conditions: [
      // アクションを実行する条件
      new chrome.declarativeContent.PageStateMatcher({
        pageUrl: {hostEquals: 'qiita.com'},
      })
    ],
    // 実行するアクション
    actions: [
      new chrome.declarativeContent.ShowPageAction()
    ]
  }]);
});
```

`chrome.declarativeContent.PageStateMatcher` でどんな条件を指定ができるのか、については [公式 chrome\.declarativeContent](https://developer.chrome.com/extensions/declarativeContent#type-PageStateMatcher) にサンプルも載ってます。

## popup.html, popup.js

この2つのファイルは、Browser Action のときと同じ中身です。

## PageActionを実行する

インストールして
![ex12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/71fe976d-4195-9c96-d65f-d6a3df186ecc.png)


`https://qiita.com/*` にアクセスすると

↓ アイコンが有効(押せる)な状態で、押せば動きます。

![ex13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/5d971d7d-9f53-d3e7-8cdf-88ee0578deeb.png)


`https://qiita.com/*` **以外**にアクセスすると

↓ Pアイコンが押せません。
![ex14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/8612/f94d0154-8389-71c3-2671-59f2ea9ba4df.png)

きちんと `PageStateMatcher` が効いているようです。


## Page Action のデバッグ

Browser Actionと同じです。


次回は Event Page (Background Page) についてです。


# 連載リンク

[Chrome Extension の作り方 \(その1: 3つの世界\) \- Qiita](https://qiita.com/sakaimo/items/416f36db1aa982d8d00c)
[Chrome Extension の作り方 \(その2: Contents Script\) \- Qiita](https://qiita.com/sakaimo/items/6b7b464de4bdcad18802)
[Chrome Extension の作り方 \(その3: Browser Action / Page Action\) \- Qiita](https://qiita.com/sakaimo/items/129a785146e5873c42a6)
[Chrome Extension の作り方 \(その4: Event Page / Background Page\) \- Qiita](https://qiita.com/sakaimo/items/edd910a770b3d5ba83e3)
[Chrome Extension の作り方 \(最終話: メッセージパッシング\) \- Qiita](https://qiita.com/sakaimo/items/5e41d6b2ad8d7ee04b12)