やりたいこと
webページが非表示になったことを検知して、処理を行いたい
検証
検証環境
- iOS : iPhone6 (9.3.1)
- Android : Xperia501SO (5.1.1)
- Proxy : BurpSuite (1.6.32)
検証内容(その1)
beforeunload / pagehide / unloadイベントを仕込んでやってみた
検証結果(その1)
[iOS]
動作 | 発生イベント |
---|---|
ページリロード | pagehide unload |
リンクタップ | pagehide unload |
リンクタップ(target blunk) | - |
ブラウザバック | pagehide unload |
電源ボタンタップ | - |
ホームボタン | - |
ホームボタン(ダブルタップ) | - |
[Android]
動作 | 発生イベント |
---|---|
ページリロード | beforeunload pagehide unload |
リンクタップ | beforeunload pagehide unload |
リンクタップ(target blunk) | - |
ブラウザバック | beforeunload pagehide unload |
電源ボタンタップ | - |
ホームボタン | - |
アプリ履歴ボタンタップ | - |
考察(その1)
結果からわかる通り、デバイスに備わっているボタンをタップした時のイベントが拾えていない
iOSは、beforeunloadが呼ばれないみたい
検証内容(その2)
次に、Page Visibility APIを仕込んでやってみた
検証結果(その2)
[iOS]
動作 | 発生イベント |
---|---|
ページリロード | - |
リンクタップ | - |
リンクタップ(target blunk) | - |
ブラウザバック | - |
電源ボタンタップ | visibilityChange |
ホームボタン | visibilityChange |
ホームボタン(ダブルタップ) | - |
ホームボタン(ダブルタップ)→電源ボタン | visibilityChange |
[Android]
動作 | 発生イベント |
---|---|
ページリロード | - |
リンクタップ | - |
リンクタップ(target blunk) | visibilityChange |
ブラウザバック | - |
電源ボタンタップ | visibilityChange |
ホームボタン | visibilityChange |
アプリ履歴ボタンタップ | visibilityChange |
考察(その2)
各種デバイスのボタンイベント後に、visibilityChangeイベントが呼ばれページが非表示になったことは検知できた
ただし、どの動作が行われたかは、検知できないみたい
iOSの場合、ホームボタンのダブルタップでは、visibilityChangeイベントが呼ばれず、その後、電源ボタンを押してみたところ、visibilityChangeイベントが呼ばれた
結果まとめ
以上の検証結果からbeforeunload / pagehide / unloadイベントとPage Visibility APIを組み合わせるとページが非表示になる動作を大体捉えられることがわかった
ページ遷移系のイベントは、とりあえず、pagehide
かunload
を読んでおけば大丈夫
iOS8とかAndroid 4/6系でどう動くかは、確認していないので、そのうち確認する予定
サンプルコード
// デバイスのボタンイベントを検知するためのリスナー
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();