[Firefox OS][WebAPI]Page Visibility APIの使い方 – onResumeの代わりにできること


 藪下@2課のガジェオタです。

 Firefox Developers Conference 2014 in Kyotoの準備とかその間に滞った作業のリカバリでバタバタしていたのでご無沙汰していました。今週から平常運転に戻します。

 FxOSコードリーディングの運営をお手伝いいただいているひらとりさんとノマドワーキングしてたら面白い質問をもらったので調べてみました。

Q&A

Q.Firefox OSのアプリにはAndroidのライフサイクルでいうところのonResumeがないけどアプリから離れて戻ってきた時に動作したい場合どうしたらいいの?

A.Page Visibility APIを使いましょう。

What is Page Visibility API?

 Page Visibility APIはSafari発祥みたいですね。Page Visibility APIではページが見えているかいないかを知ることができます。
 onblurとかonfocus見たいなハックは見たことありますよね。これらはフォーカスが外れたとき、フォーカスを得たときを検知してくれますがページの可視状態と必ずしも一致しません。Page Visibility APIだとちゃんと見えなくなったり見えるようになったときにvisibilitychangeイベントを呼んでくれるので正しい解決だといえます。
 gaiaだとブラウザやSMS、時計、カメラなどいろいろなところで使っています。

How to

 使い方を見ていきます。

visibilitychangeイベント

 visibilitychangeイベントはDOMイベントです。なのでいつものaddEventListenerでイベントハンドラを登録します。

document.addEventListener("visibilitychange", handler);

function handler() {
    // なんかなんか
}

document.hiddenメソッド

 hiddenメソッドはページが見えていない場合trueを、そうでない場合falseを返します。

if (document.hidden) {
    // 不可視状態
} else {
    // 可視状態
}

document.visibilityStateメソッド

 visibilityStateメソッドは可視性の状態を表す文字列を返します。

  • visible
    • ページは見えています。Page Visibility APIでの「見えている」というのは別のタブを表示していない、最小化されていないということなので、デスクトップなどでは別のウィンドウが上に乗っていてもvisibleになることがあります。
  • hidden
    • ページは見えていません。前述の通りタブの状態や最小化の状態のことを言っているのでhiddenであるということは別のタブを表示しているか最小化されているということです。
  • prerender
    • ページは見えていません。ページはまだプリレンダリングされただけでユーザに見えるように表示されていません。
    • 他の状態からprerenderになることはありません。
if (document.visibilityState == "visible") {
    // 可視状態
} else if (document.visibilityState == "hidden") {
    // 不可視状態
} else if (document.visibilityState == "prerender") {
    // プリレンダリング状態
}

Try on Firefox OS

 Firefox OS上でも試してみます。例のごとくサンプルコードは以下のURLです。

  • https://github.com/aoitan/gcg_labo/tree/master/api_reading/20140430_using_Page_visibility_API

 How toのところで示した使い方で画面に何かしら表示するようにしただけです。
 マニフェストは何も特別なことをしていないので省略します。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Using Page Visibility API Sample</title>
    <script src="index.js"></script>
  </head>
  <body>
    <ul id="output"></ul>
  </body>
</html>
init();

function init() {
  document.addEventListener("visibilitychange", handler);
  var output = document.getElementById('output');
  output.appendChild(outputVisibilityState());
}

function handler() {
  var output = document.getElementById('output');
  output.appendChild(outputVisibilityChange());

  var childUl = document.createElement('ul');
  childUl.appendChild(outputHidden());
  childUl.appendChild(outputVisibilityState());

  output.appendChild(childUl);
}

function outputVisibilityChange() {
  var li = document.createElement('li');
  li.innerHTML = 'event: visibilitychange';
  return li;
}

function outputHidden() {
  var li = li = document.createElement('li');
  if (document.hidden) {
    // 不可視状態
    li.innerHTML = 'document.hidden = hidden';
  } else {
    // 可視状態
    li.innerHTML = 'document.hidden = visible';
  }
  return li;
}

function outputVisibilityState() {
  var li = document.createElement('li');
  if (document.visibilityState == "visible") {
    // 可視状態
    li.innerHTML = 'document.visibilityState = visible';
  } else if (document.visibilityState == "hidden") {
    // 不可視状態
    li.innerHTML = 'document.visibilityState = hidden';
  } else if (document.visibilityState == "prerender") {
    // プリレンダリング状態
    li.innerHTML = 'document.visibilityState = prerender';
  }
  return li;
}

 ホーム押したりホーム長押しから戻ったりしてみました。

using_page_visibility_api

 なんだか検知できてますね!

さいごに

 これでAndroidのライフサイクルイベントをすべて賄えるわけではないんですが、既存のAndroidアプリを移植する上で引っかかる部分の一部は解決できるのではないでしょうか。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <img localsrc="" alt="">