[iOS/Android]ブラウザでページが非表示になったことを検知する方法

## やりたいこと
webページが非表示になったことを検知して、処理を行いたい

## 検証
### 検証環境
* iOS : iPhone6 (9.3.1)
* Android : Xperia501SO (5.1.1)
* Proxy : BurpSuite (1.6.32)


### 検証内容（その1）
[beforeunload](https://developer.mozilla.org/ja/docs/Web/Reference/Events/beforeunload) / [pagehide](https://developer.mozilla.org/ja/docs/Web/Events/pagehide) / [unload](https://developer.mozilla.org/ja/docs/Web/Events/unload)イベントを仕込んでやってみた

### 検証結果（その1）

[iOS]

| 動作 | 発生イベント |
|:------|:------|
| ページリロード            | pagehide <br> unload |
| リンクタップ              | pagehide <br> unload |
| リンクタップ(target blunk) | - |
| ブラウザバック            | pagehide <br> unload |
| 電源ボタンタップ          | - |
| ホームボタン              | - |
| ホームボタン（ダブルタップ） | - |

[Android]

| 動作 | 発生イベント |
|:------|:------|
| ページリロード            | beforeunload <br> pagehide <br> unload |
| リンクタップ              | beforeunload <br> pagehide <br> unload |
| リンクタップ(target blunk) | - |
| ブラウザバック            | beforeunload <br> pagehide <br> unload |
| 電源ボタンタップ          | - |
| ホームボタン              | - |
| アプリ履歴ボタンタップ     | - |

### 考察（その1）
結果からわかる通り、デバイスに備わっているボタンをタップした時のイベントが拾えていない
iOSは、beforeunloadが呼ばれないみたい

### 検証内容（その2）
次に、[Page Visibility API](https://developer.mozilla.org/ja/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API)を仕込んでやってみた

### 検証結果（その2）

[iOS]

| 動作 | 発生イベント |
|:------|:------|
| ページリロード            | - |
| リンクタップ              | - |
| リンクタップ(target blunk) | - |
| ブラウザバック            | - |
| 電源ボタンタップ          | visibilityChange |
| ホームボタン              | visibilityChange |
| ホームボタン（ダブルタップ） | - |
| ホームボタン（ダブルタップ）→電源ボタン | visibilityChange |

[Android]

| 動作 | 発生イベント |
|:------|:------|
| ページリロード            | - |
| リンクタップ              | - |
| リンクタップ(target blunk) | visibilityChange |
| ブラウザバック            | - |
| 電源ボタンタップ          | visibilityChange |
| ホームボタン              | visibilityChange |
| アプリ履歴ボタンタップ     | visibilityChange |

### 考察（その2）
各種デバイスのボタンイベント後に、visibilityChangeイベントが呼ばれページが非表示になったことは検知できた
ただし、どの動作が行われたかは、検知できないみたい
iOSの場合、ホームボタンのダブルタップでは、visibilityChangeイベントが呼ばれず、その後、電源ボタンを押してみたところ、visibilityChangeイベントが呼ばれた

## 結果まとめ
以上の検証結果から[beforeunload](https://developer.mozilla.org/ja/docs/Web/Reference/Events/beforeunload) / [pagehide](https://developer.mozilla.org/ja/docs/Web/Events/pagehide) / [unload](https://developer.mozilla.org/ja/docs/Web/Events/unload)イベントと[Page Visibility API](https://developer.mozilla.org/ja/docs/Web/Guide/User_experience/Using_the_Page_Visibility_API)を組み合わせるとページが非表示になる動作を大体捉えられることがわかった

ページ遷移系のイベントは、とりあえず、`pagehide`か`unload`を読んでおけば大丈夫
iOS8とかAndroid 4/6系でどう動くかは、確認していないので、そのうち確認する予定

## サンプルコード

```sample.js
// デバイスのボタンイベントを検知するためのリスナー
function setVisibilityEvent(){
  var hidden, visibilityChange;
  if (typeof document.hidden !== "undefined") {
    hidden = "hidden";
    visibilityChange = "visibilitychange";
  } else if (typeof document.mozHidden !== "undefined") {
    hidden = "mozHidden";
    visibilityChange = "mozvisibilitychange";
  } else if (typeof document.msHidden !== "undefined") {
    hidden = "msHidden";
    visibilityChange = "msvisibilitychange";
  } else if (typeof document.webkitHidden !== "undefined") {
    hidden = "webkitHidden";
    visibilityChange = "webkitvisibilitychange";
  }
  document.addEventListener(visibilityChange, function(){
    // ページ非表示と表示時に呼ばれるため、表示から非表示になった時だけ呼ばれるように
    // document.hidden条件を追加
    if(document.hidden){
      request("visibilitychange");
    }
  }, false);
}

// ページ遷移イベントを検知するためのリスナー
function setPageTransitionListener(){
  window.addEventListener("pagehide", function(){
    request("pagehide");
  }, false);
}

// 非表示時の処理
// 以下の場合、サーバに通知する処理
function request(event){
  var id = 'test_'+window.btoa(event);
  var img = document.createElement('img');
  var endPoint = 'http://...';
  img.src = endPoint + query;
  img.id = id;
  body.appendChild(img);
  img.parentNode.removeChild(img);
}

function main(){
  setVisibilityEvent();
  setPageTransitionListener();
}

main();
```