Chrome拡張でとっても役立つAPIのまとめ

[「BLOCK CLOCK」]((https://qiita.com/Yuta_Fujiwara/items/ce4de683255aeffffb5d))という、Chrome拡張のサービスを作りました。リリースの記事をQiitaにも投稿してサービスの紹介をさせていただいたのですが、技術的な内容が全くなかったので、開発に使用したChrome ExtensionのJavaScript APIsにも触れておきたいと思います。

Chrome拡張を作るためのGoogoleが提供している[Chrome ExtensionのJavaScript APIs](https://developer.chrome.com/apps/api_index)を呼び出しています。公式リファレンスは存在していますが全て英語で書かれており、APIの内容を調べるのに苦労しました。

Chrome拡張の開発で、同じように苦戦する方がいると思うので、少なくとも僕が使ったAPIだけは今回まとめておこうと思います。

[JavaScript APIs](https://developer.chrome.com/apps/api_index)

[BLOCK CLOCK - 仕事の時間をSNSから守るクローム拡張](
https://tech-portfolio.org/block_clock/)

## **マニフェストファイル**

chrome拡張を動かすためには設定ファイル```manifest.json```が必要です。ここに記述がないと呼び出せないAPIも存在しています。

詳しくは@mdstoy さんが、詳しくまとめてくれているので、僕は割愛します。
※参考にさせていただきました:bow:

[Chrome 拡張機能のマニフェストファイルの書き方](https://qiita.com/mdstoy/items/9866544e37987337dc79)

今回のサンプルは以下のようなファイルを設定しています。

```manifest.json

{
    "manifest_version": 2,
    "version": "1.0.0",
    "name": "Qiitaサンプル",
    "description": "description",
    "browser_action": {
        "default_icon": "/image/qiita_icon.png",
        "default_title": "Qiitaのサンプル用",
        "default_popup": "popup.html"
    },
    "icons": {
        "128": "/image/qiita_icon.png"
    },
    "background": {
        "scripts": [
            "/assets/js/background.js"
        ]
    },
    "permissions": [
        "background",
        "storage",
        "alarms",
        "tabs"
    ]
}

```

## **表示されるhtml**

上記のマニフェストファイルを設定すれば、アイコンをクリックしたときに、以下のpopup.htmlが読み込まれるようになります。


```popup.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Qiitaサンプル</title>
    <link rel="stylesheet" type="text/css" href="/static/dist/semantic.min.css">
    <script src="/assets/js/jquery-3.3.1.min.js"></script>
    <script src="/assets/js/push.min.js"></script>
    <link rel="stylesheet" type="text/css" href="/assets/css/dashboard.css">
</head>

<body>
<div class="ui inverted huge borderless fixed fluid menu blue column">
    <a class="header item" id='top'>Qiitaサンプル</a>
</div>

<div class="container">
    <div class="ui attached message">
        <div class="header">
            <a>Qiitaサンプル</a>
        </div>
    </div>

    <div class="ui attached fluid segment">
        <div class="ui stackable four column grid">
            <div class="five wide column">
                <div class="ui card">
                    <div class="extra content">
                        <a>
                            <container id='start_container'>
                                <button class="blue fluid ui button"  id='start_push'>START</button>
                            </container>
                            <container id='pomodoro_container' hidden>
                                <div class="ui orange fluid centered message" id="start_message_label">
                                    <div class="column center aligned">start</div>
                                </div>
                                <div class="ui blue fluid centered message" id="rest_message_label" hidden>
                                    <div class="column center aligned">
                                         end
                                    </div>
                                </div>
                            </container>
                        </a>
                    </div>
                    <div class="extra content" id='end_container'>
                        <a>
                            <container >
                                <button class="orange fluid ui button" id='end_push'>THE END</button>
                            </container>
                        </a>
                    </div>
                    <div class="extra content" id='confirm_container'>
                        <a>
                            <container>
                                <button class="green fluid ui button" id='confirm_push'>CONFIRM</button>
                            </container>
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="ui attached fluid segment" id='start_message_container'>
        <div class="ui negative orange message"  id="status_open">
            <div class="header">
                status：open
            </div>
        </div>
        <div class="ui negative blue message" id="status_start" hidden>
            <div class="header">
                status：start
            </div>
        </div>
        <div class="ui negative red message" id="status_end" hidden>
            <div class="header">
                status：end
            </div>
        </div>
    </div>
</div>
</body>
<script src="/assets/js/main.js"></script>
</html>

```

【popup.htmlイメージ】
<img width="392" alt="スクリーンショット 2018-04-27 15.52.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/147291/05bb3314-8541-9f62-6479-84f4706c1675.png">


## **仕組み**

Chrome Extensionの仕組みを図化しています。

![仕組み.jpg](https://qiita-image-store.s3.amazonaws.com/0/147291/bbd7cf48-9260-df29-cfc4-f151a6b3171d.jpeg)

## **API解説**

### **runtime**

background.jsとmain.jsでメッセージの送受信が可能になります。

```JavaScript:main.js

chrome.runtime.sendMessage({ text: "QiitaのSampleを送ります。" }, function (response) {
    console.log(response.text); // →　QiitaのSampleを返します。
});

```

```JavaScript:background.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    alert(request.text); // → QiitaのSampleを送ります。
    sendResponse({ text: "QiitaのSampleを返します。" });
});
```

簡単に解説すると、main.js → background.js → main.js(callback)というような流れになっています。alertの後に、ログが出力されているはずです。

 STARTボタンを押した時にメッセージを送信する書き方は以下のようになります。

```JavaScript:main.js
// 「START」ボタンを押した時にメッセージを送信する
$('#start_push').click(function () {
    chrome.runtime.sendMessage({ text: "QiitaのSampleを送ります。" }, function (response) {
        console.log(response.text);
    });
});

```


### **alarms**

経過した時間をセットして、イベント発生させるAPIも用意されています。

```JavaScript:background.js
// 1分毎実行
chrome.alarms.create("start_count_1", { "periodInMinutes": 1 });

// 5分後に実行
chrome.alarms.create("start_count_2", { "delayInMinutes": 5 });

// alarmsイベント取得
chrome.alarms.onAlarm.addListener(function (alarm) {
    if (alarm.name == "start_count_1") {
        alert("1分経過しました。");
    } else if (alarm.name == "start_count_2"){
        alert("5分経過しました。");
        chrome.alarms.clearAll(); //セットしたアラームをクリア
    }
});

```

### **storage**

アプリの状態を保持しておきたいときってありますよね。そんなときは```strage```を呼び出せば、メモリ上に保持することが可能です。

```JavaScript:main.js
$('#start_push').click(function () {
    chrome.runtime.sendMessage({ status: "start" }, function (response) {
        console.log(response.status); // → startをセットしました。
    });
});


$('#confirm_push').click(function () {
    chrome.storage.local.get(["status"], function (value) {
        console.log('status : '+value.status) // → status : start
    });
});

```

```JavaScript:backbground.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    if (request.status=='start'){
        chrome.storage.local.set({ 'status': request.status }, function () {});
        sendResponse({ status: "startをセットしました。" });
    }
});

```

### **tabs**

タブが切り替わった時、更新された時のイベントを取得できます。

```JavaScript:background.js
// タブが切り替わった時のイベント
chrome.tabs.onActivated.addListener(function (tabId) {
    chrome.tabs.query({"active": true}, function (tab) {
        console.log(tab[0].url); // 切り替わったタブのURL
        chrome.tabs.remove(tab[0].id); //切り替わったタブを削除
    });
});

// タブが更新された時のイベント
chrome.tabs.onUpdated.addListener(function (tabId, info, tab) {
    console.log(tab.url); // → 更新されたURL
    console.log(info.status); //→ loading,complete
    chrome.tabs.remove(tabId); // 更新されたタブのidを削除
});

//新規タブを開く
chrome.tabs.create({ "url": "index.html" });

```

### **setBadgeText, setBadgeBackgroundColor**

アイコンの下にメッセージを表示するAPIも用意されています。(そろそろ溜まっているメール見ないと...)

【Gmailのイメージ】
<img width="35" alt="スクリーンショット 2018-04-27 15.28.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/147291/5257d662-8c1e-2094-8e77-3aa0fd6001e9.png">



```JavaScript:main.js
$('#start_push').click(function () {
    chrome.browserAction.setBadgeText({ text: "start" });
    chrome.browserAction.setBadgeBackgroundColor({ color: [0, 0, 255, 100] });
});

$('#end_push').click(function () {
    chrome.browserAction.setBadgeText({ text: "end" });
    chrome.browserAction.setBadgeBackgroundColor({ color: [255, 140, 0, 100]});
});

chrome.browserAction.setBadgeText({ text: "" }); // 削除

```
【start】
<img width="65" alt="スクリーンショット 2018-04-27 15.33.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/147291/810fbe6e-14e5-389f-8b0a-e23c89fc3b2a.png">

【end】
<img width="66" alt="スクリーンショット 2018-04-27 15.35.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/147291/61ad6735-20c4-b010-d4df-4ebf520a8e14.png">


### **browserAction**

マニフェストファイルに設定している、デフォルトのアイコンを変更することができます。

```JavaScript:background.js
chrome.browserAction.setIcon({ path: "変更するパスを指定" });
```

## **まとめ**

少ないですが、今回作ったクローム拡張で使ったAPIを紹介しました。[Chrome ExtensionのJavaScript APIs](https://developer.chrome.com/apps/api_index)には他にも豊富なAPIがあるので、ぜひ試して使ってみてください！