利用状況把握拡張機能② - storageとContent Script、Service Workerの役割

　この記事は利用状況把握拡張機能①の続きですので、そちらにも目を通した方が理解しやすいと思います。
　ここでは、拡張機能の`storage API`、`Content Script`と`Service Worker`について述べている。

　前回のページ　→　<a href="
https://qiita.com/Hira_B/items/84fe189a38f43f574502">利用状況把握拡張機能①</a>

## chrome.storage
　manifestファイルの読み込みが完了したため、最初に拡張機能で使う予定のデータをchrome storageへと一通り入れておく。
  chrome.storageへとデータを入れるには、以下のように記述。
  ```
chrome.storage.local.set({ test_key : "value" });
  ```
  chrome.storageはオブジェクト型のデータなので、keyに関しては自動で生成するため問題はない。

データを取得する際は以下のように記述する
```
chrome.storage.local.get().then((result)=>{
    console.log(result.test_key); // "value"
});
```
 chrome storageのデータを確認したい場合は、拡張機能と関連したページのデベロッパーツールを開く必要がある（content scriptによる特定ページなどは不可能）。無難なのは、拡張機能の管理ページにある、ビューを検証をクリックして開く方法。
開いたらConsoleに
```
chrome.storage.local.get(null,function(data){console.info(data) });
```
と打ち込む。以下のようなデータが現在の拡張機能のstorageに入っているデータ一覧となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657037/fbc4a942-62c7-1042-3e18-600bcfec26b1.png)
　既にいくつかデータが入っているが、ここで少し解説をば。
- LockScreen は制限時間を超えたページに対して設ける使用禁止時間。30分間、利用できなくさせるデータといったところ
- PauseTimeとPauseTime_Hの二つは、前ページで言及した、特定時間帯の制限に関するデータ。配列の[0]が開始時間帯で、[1]が終了時間帯としている。
- Pause_Check はその特定時間帯の機能自体を有効にするかどうか。falseで無効、trueで有効。
- TimeReset は最後の方に記述するが、記録データの定期リセットに関するデータ。詳細はその時にて。

## 利用時間の記録（content_script・service_worker）
　データも入れ終わったため、ブラウザの各ページの利用時間を計る利用時間の記録機能を作成する。Content Script側から現在のページのURLを取得し、Service Workerへと情報を送り利用時間の計測を開始する。
　最初にページが読み込まれContent Scriptが実行される。まずは訪れたサイトに対しそのページのURLを取得して、拡張機能が有効な間に初めて訪れたサイトなら、そのURLと0を初期値としたそのページの利用時間データ二つをstorageへと同時に入れる。そうして、[“HTTPS://○○/〇” ]←→[0(利用時間)]と一致するようにする。
　保存後、URLや識別番号といった情報をService Worker側へと送信する。
```javascript:content_scripts.js
chrome.storage.local.get().then((result)=>{
    for( i = 0; i < result.All_URL.length; i++){
        if( result.All_URL[i].includes(location.host) ){
            allFlag = true;
        }
    }
    let newList = result.All_URL;
    let newListT = result.All_Time;
    let i = result.All_URL.length;
    newList.push(location.host);
    newListT.push(0);
    chrome.storage.local.set({ All_URL : newList });
    chrome.storage.local.set({ All_Time : newListT });
    chrome.runtime.sendMessage({name : 'All_URL', url : currentURL,num : m });
});
```
　storageは仕様上、上書き処理なので一度複製し追加してからもう一度storageへとデータを保存している。`chrome.runtime.sendMessage`でService Workerへとメッセージを送信している。一緒にurlと添え字を向こうへと送る。送信する情報は、メッセージ名とURLとURLの識別番号。Service Worker側では、メッセージを受け取りsetIntervalで利用時間のカウントを開始する。
```javascript:service_worker.js
chrome.runtime.onMessage.addListener((msg,sender)=>{
    if( msg.name === 'All_URL'){
        chrome.tabs.query({active:true,currentWindow:true},async function(activeTab){
            chrome.storage.local.get().then((result) =>{
                let counttime = 0;
                clearInterval(All_interval)
                All_interval = setInterval(function(){
                    counttime = counttime + 1;
                    measureViewTimeAll(msg.num,counttime,result.All_URL,result.All_Time,result.WeekdataArchiveAll );
                },1000);
            });
        });
    }
});
```
　`chrome.runtime.onMessage.addListner`は、拡張機能内から送信されたメッセージを受信した際に発生するイベント。このイベントはどんなメッセージでも発生する。Service worker.jsにはもう一つ同じイベントがあり、そちらと処理が混ざらないようにメッセージに名前を付け、if文で区別させている。
 `chrome.tabs.query`は、現在のタブ情報を配列で取得する。`active:true,currentWindow:true`とパラメータに追加すると、現在のページ情報を取得することが出来る。
 　こちらでsetIntervalを一秒間隔で実行してカウントを開始している。中ではインクリメントと、storageへと利用時間を更新させる、measureViewTimeAll関数がある。
  
```javascript:service_worker.js
functionmeasureViewTimeAll(i,counttime,All_URL,All_Time,WeekdataArchiveAll{
    let newlist = All_Time;
    let Week = getWeek();
    newlist[i] = newlist[i] + 1;
    	
    chrome.storage.local.set({ All_Time : newlist });
    let Obj = {};
    for(let i = 0; i < All_URL.length; i++){
        let URL = All_URL[i];
        if( All_Time[i] === undefined)
            Obj[URL] = 0;
        else
            Obj[URL] = All_Time[i];
    }
    WeekdataArchiveAll[Week] = Obj;
    chrome.storage.local.set({ WeekdataArchiveAll : WeekdataArchiveAll });
}
```
　時間の更新処理。動きとしては+1した利用時間データをstorageへと保存をしているだけなため、URLをリストに追加する最初のContent Scriptとそこまで変わらない。
　WeekdataArchiveAllは、利用時間を一週間分保存させるためのもの。配列オブジェクトであり、曜日の数の配列の中に、キーをドメイン、バリューを利用時間として保存している。このデータは、後で追加する週の累計利用時間のためにある。

```javascript:service_worker.js
chrome.tabs.onActivated.addListener(function(activeInfo){
    clearInterval(All_interval);
    chrome.storage.local.get().then((result) =>{
        chrome.tabs.get(activeInfo.tabId,function(activeTab){
            //処理が同じため省略
        });
    });
});
```
　`chrome.tabs.onActivated.addListener`は、タブ・ウィンドウを移動した際に発生するイベント。こちらもonMessageと同じく、利用時間の計測の処理をしている。
　Content Scriptはページを読み込んだ際に実行されるため、タブの移動などには対応できない。そのためService Workerの方からタブ・ウィンドウ移動時にカウントができる処理を記述する。なお、setInterval関数の複数実行を防ぐためにどちらかのイベントが発生した時、最初にclearInterval関数を実行させている。
 
　実装後、利用時間が記録されているかをConsoleで確認。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657037/a6b71725-8940-1c90-fdae-5c9696c59fb6.png)
きちんとページごとの利用時間を記録し、一つのページのみを計測している。

　ここまでを実装してから、一度ブラウザを通常通りに使用し、storageへとデータが保存されているかを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657037/a56a1631-be77-bb42-59b5-369063b87813.png)
　ちゃんとデータが入っていることを確認できた。上記ではQiitaのページの利用時間が5114秒、軽く1時間25分ほど経っている。
 利用時間の記録は、これにて完成。

 ## 関連する記事
 - <a href="https://qiita.com/Hira_B/items/84fe189a38f43f574502">利用状況把握拡張機能① - 拡張機能の概要とmanifestの読み込み</a>　
 - <a href="https://qiita.com/Hira_B/items/3978218f8d92c7a92c6c">利用状況把握拡張機能② - storageとContent Script、Service Workerの役割</a> ←現在の記事
 - <a href="https://qiita.com/Hira_B/items/7f1160cb274bce2b4292">利用状況把握拡張機能③ - メッセージ送信と制限処理</a>
 - <a href="https://qiita.com/Hira_B/items/8a30109f47d1cef6a61e">利用状況把握拡張機能④ - 拡張機能のdefault_popup</a>
 - <a href="https://qiita.com/Hira_B/items/6acd07e5f76150cda476">利用状況把握拡張機能⑤ - オプションページとグラフ①</a>
 - <a href="https://qiita.com/Hira_B/items/7fc516607a499298678c">利用状況把握拡張機能⑥ - オプションページとグラフ②</a>
 - <a href="https://qiita.com/Hira_B/items/141a0d506c14bbe7a6e5">利用状況把握拡張機能⑦ - ソースコード</a>