JavaScript

ブラウザがバックグラウンド回ったことを検知する

Android,iOSでホームボタンなどが押されブラウザが後ろに回ったことを

検知したかった。


■対象

Android 4.0〜

iOS 7.1.2〜


■検証

・visibilitychange ... mdn Can I use

・blur

・onpagehide

・requestAnimationFrame ... mdn Can I use

visibilitychange が使える環境なら、それを優先して使う。

blur は使える環境が広いが、ブラウザメニューを開くなどの行動でも発火してしまうので、優先度は低め。


■検証結果

iOS

visibilitychange
blur
onpagehide

7.1.2
△※1
×

8.4.1


×

9.3.2


×

※1 ... 別タブ移動は検知できるが、アプリのバックグラウンド検知は×

Android(標準ブラウザ)

visibilitychange
blur
onpagehide
requestAnimationFrame

F-08(4.0.3)
×

×
×

DMO-14SH(4.0.4)
×

×
×

Nexus S(4.1.2)
×

×
×

F-07E(4.2.2)
×

×
×

SO-02F(4.4.2)
×

×
×

SO-01F(4.4.2)

?※3
?※3
?※3

SH-04F(5.0.2)

?※3
?※3
?※3

SC-04E(5.0.1)

?※3
?※3
?※3

SO-03F(5.0.2)
△※2
△※1
×
△※1

F-02G(5.0.2)
△※2
△※1
×
×

SO-05F(5.0.2)
△※2
△※1
×
△※1

SC-01H(6.0)
△※2
?※3
×

SO-03G(6.0)
△※2
?※3
×

F-03H(6.0.1)

?※3
?※3
?※3

SO-02G(6.0.1)
△※2
?※3
×

SO-04G(6.0.1)
△※2
?※3
×

※1 ... 別タブ移動は検知できるが、アプリのバックグラウンド検知は×

※2 ... Page Visibility API が使える分岐に入るが、ホーム遷移で発火しない

※3 ... 安定して検知できる方法があったので、未検証

標準ブラウザがなく、 ブラウザが chromeの場合は visibilitychange が動くので

上記の表から外しました。


■まとめ

iOS 7 → onpagehide

iOS 8〜 → visibilitychange

Android は

visibilitychange が使えれば使う、(requestAnimationFrameも保険として登録)

visibilitychange が使えなければ blur で対応

Android 5.0.2 はどうしてもバックグラウンド検知ができない場合がある

(setTimeoutでアプリがバックグラウンドに回った際の処理の差で検知する方法もあるけど、端末差があったのであまり信用できない。。)

/**

* visibilityChange判定
*/

var hidden, visibilityChange;
if (typeof document.hidden !== "undefined") {
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}

/**
* バックグランド遷移判定に何を使うか
*/

var available;
if(window.navigator.userAgent.toLowerCase().indexOf('iphone os 7_0') > -1){
// iOS7はonpagehide固定
available = 'onpagehide';
} else if(typeof document[hidden] === "undefined"){
if(window.requestAnimationFrame){
available = 'requestAnimationFrame';
} else {
available = 'blur';
}
} else {
available = 'visibilityChange';
}

// 再生中にアプリがバックグラウンドにまわったか監視する

if(available === 'onpagehide'){
window.onpagehide = function() {
stop();
};

} else if(available === 'blur'){
window.addEventListener('blur', stop, false);

} else {
observe();

if(available === 'visibilityChange'){
document.addEventListener(visibilityChange, stop, false);
}
}

/*

* requestAnimationFrameで監視
*/

var raf_id, raf_timer;
function observe(){
raf_id = window.requestAnimationFrame(observe);
if(raf_timer !== false){
clearTimeout(raf_timer);
}
raf_timer = setTimeout(function() {
stop();
}, 500);
};

// バックグランド監視の停止

if(available === 'onpagehide'){
window.onpagehide = null;
} else if(available === 'blur'){
window.removeEventListener('blur', stop, false);
} else {

// requestAnimationFrameの終了
window.cancelAnimationFrame(raf_id);

if(available === 'visibilityChange'){
document.removeEventListener('visibilitychange', stop, false);
}
}