Back

WebアプリでのBattery Status APIの使用

WebアプリでのBattery Status APIの使用

ほとんどのWebアプリは、ユーザーが充電器を持たずに電車の中でバッテリー残量8%の状態にあるかどうかを知る術がありません。Battery Status APIはこの状況を変えます — 少なくとも一部のブラウザでは。このAPIを使用すると、JavaScriptでデバイスのバッテリーレベル、充電状態、および推定残り時間を読み取ることができ、それに応じてアプリの動作を適応させることができます。

この記事では、APIの仕組み、実際にできること、そしてどこでどのように使用するかについて注意が必要な理由を説明します。

重要なポイント

  • Battery Status APIは、navigator.getBattery()を通じてバッテリーレベル、充電状態、時間推定値を公開し、4つの読み取り可能なプロパティと4つの対応する変更イベントを持つBatteryManagerオブジェクトを返します。
  • APIは安全なコンテキスト(HTTPS)でのみ利用可能で、Chromiumベースのブラウザでのみ使用できるため、APIを呼び出す前に必ず機能検出とエラーハンドリングを使用してください。
  • Firefoxはフィンガープリンティングの懸念からAPIを削除し、Safariは実装していないため、バッテリー対応の動作は厳密にプログレッシブエンハンスメントとして扱い、コア機能として扱わないでください。
  • 実用的なアプリケーションには、バックグラウンド同期の一時停止、アニメーションの削減、バッテリー残量が少ないときにユーザーに作業の保存を促すことなどが含まれます。

Battery Status APIとは?

Battery Status APIは、navigator.getBattery()メソッドを通じてバッテリー情報を公開し、BatteryManagerオブジェクトに解決されるPromiseを返します。このオブジェクトは4つのプロパティを提供します:

  • level0から1の間の数値(例:0.72は72%を意味します)
  • charging — デバイスが充電中の場合はtrue、そうでない場合はfalse
  • chargingTime — 完全に充電されるまでの推定秒数
  • dischargingTime — バッテリーが空になるまでの推定秒数

両方の時間プロパティはInfinityを返すことがあります — デバイスがバッテリーのないデスクトップの場合、推定値がまだ準備できていない場合、またはブラウザがフィンガープリンティングリスクを制限するために意図的に精度を抑制している場合です。

APIを呼び出す前に、必ずサポートを確認してください。このAPIは安全なコンテキスト(HTTPS)でのみ利用可能で、それでもAPIを公開しているブラウザでのみ使用できます。

埋め込みコンテキストでは、battery Permissions Policyによってアクセスが制限されることもあります。

async function initBatteryMonitor() {
  // 機能検出 — APIの存在を前提としない
  if (!('getBattery' in navigator)) {
    console.warn('Battery Status API not supported in this browser.')
    return
  }

  let battery

  try {
    battery = await navigator.getBattery()
  } catch (err) {
    console.error('Failed to access battery information:', err)
    return
  }

  // 初期値を読み取る
  console.log(`Level: ${battery.level * 100}%`)
  console.log(`Charging: ${battery.charging}`)

  // 表示前にInfinityを適切に処理
  const formatTime = (seconds) =>
    seconds === Infinity ? 'Unknown' : `${Math.round(seconds / 60)} min`

  console.log(`Charging time: ${formatTime(battery.chargingTime)}`)
  console.log(`Discharging time: ${formatTime(battery.dischargingTime)}`)

  // 変更をリッスン
  battery.addEventListener('levelchange', () => {
    console.log(`Battery level updated: ${battery.level * 100}%`)
  })

  battery.addEventListener('chargingchange', () => {
    console.log(`Charging state changed: ${battery.charging}`)
  })
}

initBatteryMonitor()

リッスンできる4つのイベントは、levelchangechargingchangechargingtimechangedischargingtimechangeです。それぞれ対応する値が変更されたときに発火します。

実用的なユースケース

このAPIは、バッテリー残量が少ないユーザーのリソース消費を削減したい場合に最も有用です:

  • バックグラウンド同期やポーリングを一時停止battery.level0.2などの閾値を下回ったとき
  • アニメーションの複雑さを軽減または自動再生動画を無効化
  • ユーザーに作業の保存を促す — バッテリーが切れる前に
  • PWAの動作を調整 — 例えば、重要でないネットワークリクエストを延期する

これらはプログレッシブエンハンスメントです。アプリはこれらがなくても正常に動作する必要があります。

ブラウザサポートとプライバシーの懸念

ここでBattery Status APIは複雑になります。

ブラウザサポート注記
Chromiumベースのブラウザ限定的な可用性でサポートHTTPSのみ; 値が削減、丸め、またはデフォルト値に置き換えられる場合があります
Firefoxなしプライバシーの懸念により削除
Safariなし実装されていません

現在のブラウザサポートは限定的です。Firefoxは、研究者がこのAPIがフィンガープリンティングベクターとして使用できることを実証したため、APIを削除しました — バッテリーレベルと時間値の組み合わせは、サイト間でユーザーを追跡するのに十分なほど特定的でした。これに対応して、Chromiumベースのブラウザは、そのリスクを制限するために精度を下げたり、デフォルト値を公開したりする場合があります。

つまり、Battery APIを主要機能として依存すべきではありません。あると便利な改善として扱い、何も返さない場合のフォールバック動作を常に記述してください。

開発環境でのBattery APIのテスト

Chrome DevToolsは現在、Sensorsの下に組み込みのバッテリーシミュレーターを提供していません。開発中にバッテリー関連の動作をテストするには、いくつかの実用的なオプションがあります:

  • 実際のモバイルデバイスを使用 — USBリモートデバッグ経由で接続し、実際のバッテリー状態の変化を観察します。
  • コード内でAPIをモックnavigator.getBatteryを、テストに必要なプロパティとイベントを持つ偽のBatteryManagerオブジェクトを返す関数に置き換えます。
  • ブラウザのオーバーライドまたはテストライブラリを使用 — SinonやJestなどを使用して、テストスイート内でnavigator.getBattery()をスタブ化します。

開発環境に組み込める最小限のモックは次のとおりです:

function mockBattery({ level = 0.15, charging = false } = {}) {
  const fake = {
    level,
    charging,
    chargingTime: charging ? 3600 : Infinity,
    dischargingTime: charging ? Infinity : 1800,
    addEventListener: () => {},
  }

  navigator.getBattery = () => Promise.resolve(fake)
}

// バッテリー残量が少なく、充電されていないデバイスをシミュレート
mockBattery({ level: 0.08, charging: false })

このアプローチにより、ブラウザ固有のツールに依存することなく、コードが受け取る値を完全に制御できます。

結論

Battery Status APIは、実際の制限があるニッチなツールです。ブラウザサポートは限定的で、値は意図的に不正確であり、プライバシーへの影響はその将来が不確実であることを意味します。しかし、管理された環境 — 内部ツール、既知のChromiumベースのブラウザをターゲットとするPWA、またはキオスクスタイルのアプリケーション — では、ユーザーエクスペリエンスを有意義に改善できます。

機能検出を使用し、Infinity値を明示的に処理し、不要になったときにイベントリスナーをクリーンアップし、その上に重要な機能を構築しないでください。

よくある質問

Chrome for AndroidなどのChromiumベースのモバイルブラウザでのみ使用でき、環境によって可用性が異なる場合があります。iOS上のSafariは実装しておらず、Firefoxはサポートを完全に削除しました。navigator.getBattery()を呼び出す前に必ず機能検出を使用して可用性を確認し、サポートされていないブラウザ向けのフォールバック動作を提供してください。

その可能性があります。研究者は、バッテリーレベルと放電時間値の組み合わせが、ウェブサイト間でユーザーをフィンガープリントするのに十分な精度があることを示しました。これによりFirefoxはAPIを完全に削除しました。Chromiumベースのブラウザは、そのリスクを制限するために精度を下げたり、デフォルト値を公開したりする場合がありますが、この懸念は一部のブラウザが実装を避ける理由のままです。

ハンドラー関数への参照を保存し、コンポーネントがアンマウントされるときなど、不要になったときにremoveEventListenerを呼び出します。BatteryManagerオブジェクトは永続化するため、リスナーを削除しないと、アプリがモニターを複数回再初期化する場合にメモリリークや予期しない動作が発生する可能性があります。

サポートされているChromiumベースのデスクトップブラウザでは動作しますが、値は意味がない場合があります。バッテリーのないデスクトップは、多くの場合、レベルが1、充電状態がtrueと報告され、両方の時間プロパティがInfinityに設定されます。このAPIは、バッテリー状態が実際に変動するラップトップやモバイルデバイスで最も有用です。

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay