chrome拡張でユーザーごとの何かを保存する

## 目的
Chorme拡張を自作するにあたって、ユーザーごとにデータを保存できないのではできることが限られてしまうのでその方法をまとめます。
結論としてはLocalStrageを使うだけ。

## 作るもの
[前回の記事](https://qiita.com/ririli/items/b1469cb96c2b43e6202f)でtwitterを開いたら5分後にアラートを出してくれるChrome拡張を作りました。
今回はこれを改修してTwitterを開いていた時間を集計して見れるようにしてみます。

## 本編
### 手順1 ローカルストレージへのアクセス
とりあえずmanifest.jsonとcontent.jsを用意します。

```manifest.json
{
  "name": "Sample",
  "version": "1.0.0",
  "manifest_version": 2,
  "description": "Sample Chrome Extension",
  "content_scripts": [{
    "matches": ["https://twitter.com/*"],
    "js": [
      "content.js"
    ]
  }],
  "permissions": [
    "storage"
  }
}
```

```content.js
this.intervalId = setInterval(() => {
    window.alert('そろそろTwitter閉じて作業しましょう');
    
    //保存
    localStorage.setItem("testKey", "testVal");

    clearInterval(this.intervalId)

    //読み込み
    console.log(localStorage.getItem("testKey"));
}, 10000)

```

前回からの変更点は以下ですね。

```javascript

    //保存
    localStorage.setItem("testKey", "testVal");
```

```javascript

    //読み込み
    console.log(localStorage.getItem("testKey"));
```

これはChrome拡張とは関係なく、JavaScriptの機能の一つで、LocalStrageというブラウザが値を保持しておけるKey-Valueストアへのインタフェースです。
また、manifest.jsにpermissionsという項目が増えています。
これはChrome拡張がブラウザに対してどのような操作を許すかということを指定します。
今回はローカルストレージにアクセスするのでstorageを指定します。

何も考えず10秒後にアラートがでるとともに"testKey"というキーに対して"testValue"という値をローカルストレージに保存し、その後過ぎにローカルストレージから"testKey"で登録されている値を読み込んでconsoleに出力しています。
consoleには"testValue"と表示されているはず。

#### 補足
ここまで確認できたら開発者ツールからローカルストレージをクリアしておきましょう。
Applicationタブ > Storage > Local Storage を開き,twitterのurlをクリック。
禁止マークがクリアボタンです。
今後も何度か消します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177043/58e99f77-50d9-f1c1-f431-1e7657633ed6.png)


### 手順2 実行方式の変更
現在の値をconsoleなどではなくChrome拡張として出力できるようにChrome拡張の実行方式を変更します。
これまでcontent_scriptsを利用していましたが、ここからはbrowser_actionを利用します。
manifest.jsonを変更してください。

```manifest.json
{
  "name": "Sample",
  "version": "1.0.0",
  "manifest_version": 2,
  "description": "Sample Chrome Extension",
  "browser_action": {
    "default_popup": "popup.html"
  }
}
```

content_scriptではurlが指定のものとマッチしたら実行されるようになっていましたが、browser_actionではブラウザがアクティブな間は常にじっこうされるようになります。

また、Chrome拡張のアイコンをクリックした際に表示するポップアップのhtmlを指定します。
今回は以下のようなhtmlを用意しました。

```popup.html

<!DOCTYPE html>
  <html>
    <head>
      <style>
        body {
          height: 100px;
          width: 200px;
          outline: none;
        }
      </style>
    </head>
    <body>
      <p>Sum Rec Time</p>
      <p id="sumRecTime"></p>
      <script src="popup.js"></script>
    </body>
</html>
```

また,ポップアップが開かれた時に実行されるJavaScriptファイルにpopup.jsを用意。

```popup.js

let sumRecTimePTag = document.getElementById('sumRecTime');
sumRecTime = localStorage.getItem("sumRecTime");
sumRecTimePTag.innerText = sumRecTime + "sec";


this.intervalId = setInterval(() => {
    sumRecTime = localStorage.getItem("sumRecTime");
    sumRecTimePTag.innerText = sumRecTime + "sec";
}, 1000)

```

残念ながらまだ動きません。
popup.jsではローカルストレージに保存した"sumRecTime"というキーに対応する値を取得してhtmlに表示するということをやっています。
ということは"sumRecTime"に保存する処理が必要なはず。

popup.jsに書けばいいじゃんと思うかもしれませんが、popup.jsはChrome拡張のアイコンがクリックされた時しか実行されません。
これではTwitterを開いてる間カウントするという仕様を満たせません。

そこで,manifest.jsonを以下のように変えてみます。

```manifest.json
{
  "name": "Sample",
  "version": "1.0.0",
  "manifest_version": 2,
  "description": "Sample Chrome Extension",
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "browser_action": {
    "default_popup": "popup.html"
  },
  "permissions": [
    "storage",
    "tabs"
  ]
}
```

backgroundという項目とpermissionsにtabsという項目が追加されています。
backgroundに指定したscriptsのファイルはChrome拡張がアクティブであれば常に実行されます。

Twitterを開いてる間カウントするという機能はこのbackgroundで実行させることにします。

```background.js
//読み込み
sumRecTime = localStorage.getItem("sumRecTime");
if(sumRecTime === null) {
    sumRecTime = 0;
}
else {
    sumRecTime = parseInt(sumRecTime);
}

this.intervalId = setInterval(() => {
    
    chrome.tabs.query({active: true, lastFocusedWindow:true}, tabs => {
        var url = tabs[0].url;
        if(url.match(/https:\/\/twitter\.com\/.*/) != null) {
            //保存
            sumRecTime = sumRecTime + 1;
            localStorage.setItem("sumRecTime", sumRecTime);
        }
    });
}, 1000)
```

現在値(初期値)の読み込みと,1秒毎の更新処理を用意しました。
また、以下の部分で現在開いているタブのurlを取得し、

```
chrome.tabs.query({active: true, lastFocusedWindow:true}
```

```
if(url.match(/https:\/\/twitter\.com\/.*/) != null) {
```

urlがtwitterであればsumRecTimeを+1します。
ここでブラウザのタブにアクセスするためにpermissionsでtabsを指定する必要がありました。

### 手順3 動作確認

一通り実装できたので動作確認します。
Chrome拡張管理画面から再読み込みを行い、Twitterを開いた状態で今回開発したChrome拡張のアイコンをクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/177043/597bd274-f5ad-fce7-bf3b-395c13a61671.png)

このような表示が出て1秒毎に値が更新されていれば成功です。

Twitter以外のタブを開いて同じように確認し、値が更新されないことも確認しておきましょう。


## まとめ

Chrome拡張が値を保持する方法はさして難しくありません。
どっちかというとurlを取得する方が難しかったですね...

さて、今のままだとこれまでの集計結果を削除する機能がありません。（localstorage消せばいいけど）
興味があればボタンを追加して実装してみてください。