Chromeブラウザの拡張機能を作ってみたい初心者向けに開発方法を紹介！【サンプルあり】

先日、初めて[アドベントカレンダー(クソアプリ2)](https://qiita.com/advent-calendar/2018/kuso-app2)に参加しました。

そこでたっくさんの面白いサービスと巡り会ったのですが、拡張機能を作っていらっしゃる方が多い！！！ブラウザをハックしている感あって、めっちゃ面白そう！

ってことで、自分も拡張機能に初トライしたのですが、概念や作り方に慣れるまで四苦八苦…。

そこで今回、拡張機能を作りたいけど一歩踏み出すのに苦労している方に向けて、自分の経験も踏まえながら、作り方をまとめてみました。サンプルソースも添えてあります。

少しでも参考になれば幸いです！

※もし間違えやご指摘などございましたら、コメント頂けると嬉しいですm(_ _)m

※githubに簡単なサンプルをupしたので、こっちもチェックしてみてください！
→[gurutaka/extensions_hundsOn](https://github.com/gurutaka/extensions_hundsOn)

## 使用する言語
- html
- css
- JavaScript

## 設定ファイルが必要！
拡張機能を作るにあたって、manifest.jsonが必要になります。ソースはこんな感じ！

```manifest.json
{
	"manifest_version": 2,
	"name": "",
	"description": "",
	"version": "1.0",
	"icons": {
		"32": "icon_32.png",
		"48": "icon_48.png",
		"128": "icon_128.png"
	},
	"content_scripts": [{
		"matches": ["http://*/*", "https://*/*" ],
		"js": ["content_scripts.js"],
		"css": ["content_scripts.css"]
	}],
	"background": {
		"scripts": ["background.js"]
	},
	"browser_action": {
		"default_icon": "icon_32.png",
		"default_title": "",
         "default_popup": "popup.html"
	},
	"permissions": [
		"tabs",
		"background",
		"http://*/*",
		"https://*/*"
	]
}

```
参考：[【結構簡単】ブラウザアクションボタン発火の自作Chrome拡張機能の作り方＆サンプル
](http://degitekunote.com/blog/2016/11/02/chrome-extension/)

色々な設定がありそうで複雑にみえますが、ご安心ください。開発にあたって、特に重要なのは、この3つです！

- default_popup
- background
- content_scripts

上記３つが拡張機能の処理に大きく関係してきます。こちらについて、説明していきます。

※manifest.jsonの設定や用語を網羅した超わかりやすい解説を知りたい方は、こちらをチェックしてみて下さい！
参考：[Chrome 拡張機能のマニフェストファイルの書き方](https://qiita.com/mdstoy/items/9866544e37987337dc79)

※`browser_action`は`page_action`に変更することも可能です。もしくは書かない選択肢もあります！

## 処理の流れやイメージ
まず、噛み砕いてみた用語の説明から！

- default_popup：拡張機能のポップアップ(まんま)
- content_scripts：開いているwebページに影響するscript
- background：content_scriptやdefault_popupとの連携(イベント)

`default_popup`の一例が下図です！拡張機能をクリックして表示されるポップアップを意味しています。ここのscriptは、popup内の世界で動いています。
<img width="673" alt="スクリーンショット_2018-12-30_15_48_12.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/c3cd8eb3-28a3-c89c-8ad4-eec7554127aa.png">


一方で、`content_scripts`は開いているブラウザで動くscriptです。

例えば, `content_scripts`の`css`でバックグラウンドを黒、`js`でDOMを差し込むと、開いているブラウザの背景が黒くなります！

<img width="1112" alt="スクリーンショット_2018-12-30_16_31_10.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/4d96acbe-f6e1-5073-0d8b-b172d499a5c0.png">

```manifest.json
{
  "name": "BaclkgroundColor",
  "manifest_version": 2,
  "version": "1.0",
  "browser_action": {
    "default_title": "BaclkgroundColor"
  },

  "content_scripts": [
    {
      "matches": ["http://*/*", "https://*/*"],
      "css": ["content_scripts.css"],
      "js": ["jquery.min.js", "content_scripts.js"]
    }
  ]
}

```

```content_scripts.js
$("body").prepend('<div class="txt">Hello World!</div>');
```


```content_scripts.css
body {
  background-color: black;
}

.txt {
  color: white;
  font-size: 50px;
}

```


ここで１つの問題が…。

**どうやって、連携するの？？？**

例えば、ポップアップ内のボタンをクリックして、ブラウザの背景を黒くする処理をやろうとしても、上記の処理だけではできません。

そんな時に使うのが、chrome.* APIです！APIを使うことでscript間の連携ができます。処理のイメージ図がこちら！

<img width="906" alt="スクリーンショット 2018-12-30 21.52.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/09cf9839-b3e1-96fd-c116-f24d39b313fa.png">


`background`は`content_scripts`などで制約されているAPIを使う時などに重宝します！


## chrome.* APIでメッセージのやり取りをする！
chrome.*には色んなモノがありますが、最も基本的なのはsendとlistenを使ったメッセージのやり取りです！

以下が簡単なテンプレと意味合いになります。またイメージできるようなgif動画も紹介しています。

```send.js

//変数sendをメッセージで送る
chrome.runtime.sendMessage(send, function(response) {
   console.log(response);//メッセージの受け手がレスを返したときキャッチできる
});
```

```listen.js
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
  console.log(msg);//送られたメッセージをキャッチ
  sendResponse(response);//sendResponseでmsgを送ったスクリプト側にレスを返せる
});
```

![api_res_check.gif](https://qiita-image-store.s3.amazonaws.com/0/314351/f9580c69-7eb8-f56c-a17f-bce7f0b8b0ca.gif)


このgifはポップアップのボタンを押すことで、メッセージが送られます。そして、バックグラウンドでメッセージをリッスン。その後、送り手にレスを返すプログラムになります。

このようにchrome.* APIを使えば、スクリプト間でやり取りができます！
(ディベロッパーツール＠左：バックグラウンド, 右：ポップアップ)

```manifest.json

{
  "name": "API_SAMPLE",
  "manifest_version": 2,
  "version": "1.0",
  "browser_action": {
    "default_title": "API_SAMPLE",
    "default_popup": "popup.html"
  },

  "background": {
    "scripts": ["background.js"]
  }

}
```

```popup.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <script src="jquery.min.js"></script>
    <style>
      body {
        width: 100px;
      }
    </style>
  </head>
  <body>
    <button id="btn">helloと伝える!</button>
    <script src="popup.js"></script>
  </body>
</html>

```

```popup.js
  $("#btn").on("click", () => {
    chrome.runtime.sendMessage({ greeting: "hello" }, function(response) {
      console.log(response);
    });
  });
```

### 【注意】ファイルによって使えないコマンドあり
厄介なことに、スクリプトによってchrome.* APIの一部コマンドが使えない場合があります。これは随時、ググりながら確認するしかありません。

例えば、上記の`chrome.runtime.sendMessage`でポップアップからmsgを送っても、`content_scripts`には届きません。この時は、`chrome.tabs.query`と`chrome.tabs.sendMessage`を使って、msgを送ります。

ポップアップ内のボタンを押して、ブラウザのバックグラウンドを黒にしたい場合は、こんなソースになります！
![color.gif](https://qiita-image-store.s3.amazonaws.com/0/314351/a07b9346-7242-4f19-e8b8-856c62c32fa9.gif)

```manifest.json
{
  "name": "SAMPLE_2",
  "manifest_version": 2,
  "version": "1.0",
  "browser_action": {
    "default_title": "SAMPLE_2",
    "default_popup": "popup.html"
  },

  "content_scripts": [
    {
      "js": ["jquery.min.js", "content_script.js"],
      "matches": ["http://*/*", "https://*/*"]
    }
  ]

}
```

```popup.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <script src="jquery.min.js"></script>
    <style>
      body {
        width: 100px;
      }
    </style>
  </head>
  <body>
    <button id="black">背景を黒にする!</button>
    <button id="red">背景を赤にする!</button>
    <script src="popup.js"></script>
  </body>
</html>

```

```popup.js
$("#black").on("click", () => {
  chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
    chrome.tabs.sendMessage(tabs[0].id, {
      color: "black"
    });
  });
});

$("#red").on("click", () => {
  //送れない！！
  // chrome.runtime.sendMessage({ color: "red" });

  chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
    chrome.tabs.sendMessage(tabs[0].id, {
      color: "red"
    });
  });
});

```

```content_script.js
chrome.runtime.onMessage.addListener(function(msg) {
  $("body").css("background-color", msg.color);
});
```


何か動かないな…と思ったら、指定したscriptでは動かないかも…？と怪しんでみてください。
(私はこの事実に気づかず、半日くらい消耗しました爆)


## デバッグの方法
意外に曲者なのがデバッグです！図で解説していきます。

まず`chrome://extensions/`をブラウザで開いて、拡張機能のファイルを読み込みましょう！
<img width="1424" alt="スクリーンショット_2018-12-30_17_12_52.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/dc06f676-e71c-bfe4-2f49-cacdfa1df5b3.png">

### ポップアップのデバック
<img width="371" alt="スクリーンショット_2018-12-30_17_16_25.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/6b0b936a-e7cc-f833-38cc-86143f29bf4a.png">
<img width="605" alt="スクリーンショット_2018-12-30_17_16_33.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/0fcaaf07-7389-8a2d-371d-d7bc7be457c1.png">


### content_scriptsのデバック
ブラウザのディベロッパーツールでチェック！
<img width="472" alt="スクリーンショット_2018-12-30_17_20_44.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/bbdee72c-65f6-6093-3a25-87550356d8da.png">

### バックグラウンドのデバック
<img width="424" alt="スクリーンショット_2019-01-03_20_14_09.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/dd996052-7878-6874-418c-79bf5282dac2.png">



<img width="513" alt="スクリーンショット_2018-12-30_17_25_08.png" src="https://qiita-image-store.s3.amazonaws.com/0/314351/b218b245-9b15-b692-b639-6ab203478b12.png">


### キャッシュ残るので注意！

デバッグする際はキャッシュを無視してリロード(スーパーリロード)しましょう(`cmd + R + shift`)

キャッシュが残っていると、更新が反映されない場合があるのでお気をつけください。

## 最後に
初めてグーグル拡張機能の開発したい方向けに、作り方をまとめました。開発の参考になれば幸いです！

## 神すぎる参考URL
- [Chrome拡張の開発方法まとめ　その1：概念編](https://qiita.com/k7a/items/26d7a22233ecdf48fed8)
- [Chrome拡張　備忘録　１から１０まで](https://qiita.com/Tachibana446/items/696bb93bd4a23525cbb0)
- [Chromeのオリジナル拡張機能を開発しよう（ソースコードあり）](https://liginc.co.jp/web/tool/browser/163575)
- [Chrome Extensionの実装方法　初心者向け](http://luckriver.tech/tool/optimal-width/)
- [公式：Chrome APIs（extensions）](https://developer.chrome.com/extensions/api_index)
- [Chrome 拡張機能のマニフェストファイルの書き方](https://qiita.com/mdstoy/items/9866544e37987337dc79)

## おまけ：初めて作った記念すべき拡張機能
四季を代表するアイコン(桜、葉、紅葉、雪)がブラウザ上を舞い落ちる拡張機能を作りました！(自己満 オブ 自己満)

リリースもしましたので、ぜひ遊んでみて下さい！
[Chrome 拡張機能：四季](https://chrome.google.com/webstore/detail/%E5%9B%9B%E5%AD%A3/kcjmjgjjobicdbmcjonecojccpobanla/related?hl=ja)
![kakucyou.gif](https://qiita-image-store.s3.amazonaws.com/0/314351/bad0a97a-c995-a6cd-2a1e-eb0a4e698f8f.gif)