📱

Screen Wake Lock API で画面を常時表示させる

に公開

先日、料理のレシピサイトを閲覧していたところ、画面表示を維持することができるトグルスイッチが設置されている事に気付きました。料理中は手が汚れスマホを極力触りたくないので、とても助かりました。
併せて、Web でも画面表示を維持することができると知り驚きました。

これは Screen Wake Lock API によって実現できる機能で、Chrome 84 以降、Safari 16.4 以降で対応しています。

今回は、この API の挙動を Android と iOS の実機で検証しました。
この機能が活かせるユースケースについて紹介し、実際に利用する際の注意点について記載します。

検証

検証環境

  • Android Chrome 140
    • Xperia 1 V (XQ-DQ44)
    • Android 15
  • iOS Safari 18.6
    • iPhone 15 Pro
    • iOS 18.6.2

PC でも利用できる機能ではありますが、ここではスマートフォンに絞って検証を行っています。

検証用サイト

Gemini CLI で2つのページを作成しました。

検証結果

Android Chrome iOS Safari
検証項目 Android Chrome iOS Safari
トグルスイッチの操作で API 呼び出し ◯ ◯
ページを開いたタイミングで即時に API 呼び出し ◯ ✗
別タブから戻った際の API 再呼び出し ◯ ◯
別アプリから戻った際の API 再呼び出し ◯ ◯
ロック画面から戻った際の API 再呼び出し ◯ ◯
ページ再読み込み後の API 再呼び出し ◯ ✗

※ API 呼び出しは navigator.wakeLock.request の呼び出しを指します。

Android Chrome ではユーザー操作で明示的に呼び出す場合も、ユーザーの操作無しに即時で呼び出す場合も、問題なく機能しました。

iOS Safari の場合は特殊で、ユーザーの操作無しに呼び出すことはできません。
Screen Wake Lock API を呼び出す権限がなくエラーになってしまいます。

共通して、一度ページから離れるとロックが開放されますが、再取得が可能です。
ただし、ページをリロードしてしまうと iOS Safari の場合は再度ユーザーの操作が必要です。

iOS Safari の制約と、ユーザビリティを考慮するとトグルスイッチ等で明示的にロックを取得するのが現実的な実装になると思います。

ユースケース

Screen Wake Lock API が有効に活用できるユースケースについて、いくつか紹介します。

タイマー、ストップウォッチ、時計

画面が消えてしまうと現在の状態 (残り時間、経過時間、現在時刻) が見えなくなってしまい不便になるアプリケーションの代表例です。

ダッシュボード

エンジニアがシステムのメトリクスを確認するためのダッシュボードでも良いですし、スマートホームの各種センサーの状態を表示するダッシュボードのようなものを想像してもらっても構いません。
Kiosk モードのような形で専用の端末を独占して利用できる場合は、端末の設定でスリープ機能を切ると良いですが、Web アプリ側から制御できるアプローチがあると端末側で制御する以外の選択肢が増えて便利でしょう。

デジタルチケット、クーポンサイト

読み取り機で QR コードを読み取る場合や、スタッフに目視でチケットを確認してもらう場合、どちらにしても画面が消えてしまうとオペレーションに無駄な時間と手間を要するため、画面が消えないようにするという対応は、現場のスタッフと顧客のどちらにとっても嬉しい改善となるでしょう。

ノベルゲーム

オートモード使用中は基本的に画面操作をせずにストーリーが進むため、画面が消えてしまうことがあります。
画面が消えないよう定期的にマウスカーソルを動かす、スマホの場合はタップするといった操作をせずに済むので、有用でしょう。

他にも以下のような ユースケースが紹介 されていました。

  • 電子書籍
  • 地図、ナビゲーション
  • レシピ
  • プレゼンテーション
  • タッチ以外 (ジェスチャー、音声) で操作する UI を持った Web アプリ

実装時の注意点

文書が非アクティブになった際には開放される

例えば、次のような操作を行うと文書が非アクティブになり取得したロックは自動的に開放されます。

  • 別のタブに切り替える
  • 別のアプリに切り替える
  • 電源ボタンを押すなどして画面を消す

開放された事は WakeLockSentinel の release イベント で検知できます。

文書がアクティブになった事を Document の visibilitychange イベント で検知して、再度ロックを取得することが可能です。

iOS Safari で暗黙的にロックを取得する

前述の通り iOS Safari ではユーザーの操作無しにロックを取得することはできません。

User Activation API を用いることで、ユーザーがページを操作した事を確認できます。
技術的には、次のように1秒間隔で navigator.userActivation.hasBeenActive を参照し、true であればロックを取得するという実装が可能です。

let wakeLockSentinel = null;
const intervalId = setInterval(async () => {
    if (!navigator.userActivation.hasBeenActive) return;
    clearInterval(intervalId);
    wakeLockSentinel = await navigator.wakeLock.request('screen');
    console.log('WakeLock acquired');
}, 1000);

同様の実装を https://apcat.github.io/wakelock/immediately/ の方で行っているので、実際の挙動はその目でご確認ください。

しかし、iOS Safari では画面のスクロールやタップではページの操作とは見做されず、ボタンをタップする等の明確な UI 操作が必要です。

SPA で直前のページから遷移してくるタイミングでロックを獲得することはできるかもしれませんが、画面を再読み込みしてしまうと取得したロックは失われ、再度ユーザーの操作が必要となる問題は残ります。

ですので、現実的にはトグルスイッチ等の UI を設置し、ユーザーが明示的に操作する形がユーザビリティの観点から見ても良いでしょう。更に、明示的にロックを取得する場合は iOS と Android で同様の挙動となるため、OS 差異を減らせることで品質保証の観点からも好ましいと思います。

iOS Safari 18.4 未満は PWA で不具合がある

PWA、つまりホーム画面に追加された状態で起動すると動作しない不具合があったようです。

https://bugs.webkit.org/show_bug.cgi?id=254545

PWA を想定する場合は iOS Safari 18.4 以降で利用する必要があるため注意が必要です。

不要になったら開放すること

ユースケースに合わせて必要な時だけロックを取得し、不要になったら開放するように実装します。
これは、特にモバイルデバイスに於いて端末のバッテリーを浪費しない観点や、画面を消し忘れて放置してしまい第三者に操作されるといったセキュリティリスクの観点からも重要な配慮です。

ロックの解放はとても容易で、WakeLockSentinel の release メソッド を呼び出すだけです。

await wakeLockSentinel.release();

まとめ

  • Screen Wake Lock API により、Web アプリでも画面表示を維持することができる
  • iOS Safari では Screen Wake Lock API の呼び出しにユーザーの操作が必要となる

少し地味な機能ではありますが、うまく活用することで Web アプリの UX を改善できます。もっと普及して欲しいと思いこの記事を書きました。
Web アプリ開発者の方のお役に立てれば幸いです。

参考

https://www.w3.org/TR/screen-wake-lock/

https://developer.mozilla.org/ja/docs/Web/API/Screen_Wake_Lock_API

https://web.dev/blog/screen-wake-lock-supported-in-all-browsers?hl=ja

余談

Screen Wake Lock API が提供されるまでは、ブラウザで動画再生中に画面が消えない挙動を利用してバックグラウンドで動画を再生することで画面が消えないよう制御するライブラリがあったようです。

https://github.com/richtr/NoSleep.js

Discussion