电池状态 API

W3C 工作草案

关于本文档的更多详情
当前版本:
https://www.w3.org/TR/2024/WD-battery-status-20241024/
最新发布版本:
https://www.w3.org/TR/battery-status/
最新编辑草案:
https://w3c.github.io/battery/
历史记录:
https://www.w3.org/standards/history/battery-status/
提交历史
测试套件:
https://wpt.live/battery-status/
实现报告:
https://wpt.fyi/results/battery-status
编辑:
Anssi Kostiainen (英特尔公司)
前编辑:
Raphael Kubo da Costa (英特尔公司)
Mounir Lamouri (谷歌公司) (之前为 Mozilla)
反馈:
GitHub w3c/battery (拉取请求新问题开放问题)
public-device-apis@w3.org 主题行 [battery-status] … 消息主题 … (存档)

摘要

本规范定义了一个 API,用于提供托管设备的电池状态信息。

本文档状态

本节描述了本文档在发布时的状态。当前 W3C 发布的文档列表以及本技术报告的最新修订版可在 W3C 技术报告索引中找到:https://www.w3.org/TR/。

设备与传感器工作组将在请求水平审查之前对本规范进行编辑现代化、自我审查,并对 API 的安全和隐私方面进行修订。现有的 安全和隐私问题可供查看。

本文档由 设备与传感器工作组 作为工作草案发布,采用 推荐轨道

作为工作草案发布并不意味着 W3C 及其成员的认可。

本文档是草稿,可能会随时更新、替换或被其他文档废弃。将本文档作为除工作进展之外的其他用途引用是不适当的。

本文档由一个根据 W3C 专利政策 运行的工作组制作。 W3C 维护了一个 公开的专利披露列表,与工作组的交付物相关;该页面还包括披露专利的说明。任何个人如果实际知道某项专利,并认为该专利包含 必要声明,必须根据 W3C 专利政策第 6 节披露相关信息。

本文档受 2023 年 11 月 3 日 W3C 流程文档 管辖。

1. 介绍

本节为非规范性内容。

电池状态 API 规范为 Web 开发人员提供了一种编程方式,用于确定托管设备的电池状态。 如果不了解设备的电池状态,Web 开发人员必须假设设备有足够的电量来完成当前任务,从而设计 Web 应用。 这可能导致设备的电池耗尽速度快于预期,因为开发人员无法根据电池状态做出决策。 了解电池状态后,Web 开发人员可以设计节能的 Web 内容和应用,从而改善用户体验。 然而,作者应注意,API 的简单实现可能会对电池寿命产生负面影响。

电池状态 API 可用于在设备未充电或电池电量不足时推迟或减少工作量。 一个高级 Web 应用的典型例子是基于 Web 的电子邮件客户端:如果设备正在充电,它可以每隔几秒检查服务器是否有新邮件; 如果设备未充电或电池电量不足,则检查频率可以降低。 另一个例子是基于 Web 的文字处理器,它可以监控电池电量并在电池耗尽之前保存更改,以防止数据丢失。

2. 一致性

除了标记为非规范性的部分外,本规范中的所有作者指南、图表、示例和注释均为非规范性内容。除此之外,本规范的其他内容均为规范性。

本文档中的关键字 MAYMUSTSHOULD 应按照 BCP 14 [RFC2119] [RFC8174] 的描述进行解释,仅当它们以全大写形式出现时,如本文所示。

本规范定义了适用于单一产品的一致性标准:实现其包含的接口的 用户代理

3. 安全与隐私注意事项

本规范定义的 API 用于确定托管设备的电池状态。

用户代理 SHOULD 不应暴露高精度的电池状态信息读数,因为这可能引入新的指纹识别向量。

用户代理 MAY 请求用户访问电池状态信息,或者在其隐私浏览模式中强制执行用户权限要求。

用户代理 SHOULD 以不显眼的方式通知用户脚本正在使用 API,以帮助提高透明度并允许用户撤销 API 访问权限。

用户代理 MAY 混淆暴露的值,使作者无法直接知道托管设备是否没有电池、正在充电或暴露虚假值。

4. 概念

本规范中提到的 任务源电池状态任务源

5. 扩展 Navigator 接口

WebIDL[SecureContext]
    partial interface Navigator {
      Promise<BatteryManager> getBattery();
    };
注意

此方法在 PR #51 之前曾暴露于非安全上下文。

5.1 内部槽

内部槽 初始值 描述
[[BatteryPromise]] null 由调用 getBattery() 返回的 Promise
[[BatteryManager]] null 通过调用 getBattery() 创建的与给定 Navigator 关联的 BatteryManager 实例。

5.2 getBattery() 方法

getBattery() 方法的步骤如下:

  1. 如果 this.[[BatteryPromise]]null,则将其设置为 一个新的 Promise, 位于 this 的相关领域
  2. 如果 this相关全局对象关联的 Document 不允许使用 "battery" 策略控制功能,则 拒绝 this.[[BatteryPromise]],并抛出 "NotAllowedError" DOMException
  3. 否则:
    1. 如果 this.[[BatteryManager]]null, 则将其设置为在 this 的相关领域 中创建的一个新的 BatteryManager
    2. 解析 this.[[BatteryPromise]],并返回 this.[[BatteryManager]]
  4. 返回 this.[[BatteryPromise]]

6. BatteryManager 接口

WebIDL[SecureContext, Exposed=Window]
interface BatteryManager : EventTarget {
    readonly        attribute boolean             charging;
    readonly        attribute unrestricted double chargingTime;
    readonly        attribute unrestricted double dischargingTime;
    readonly        attribute double              level;
                    attribute EventHandler        onchargingchange;
                    attribute EventHandler        onchargingtimechange;
                    attribute EventHandler        ondischargingtimechange;
                    attribute EventHandler        onlevelchange;
};

BatteryManager 接口表示托管设备的当前电池状态信息。

如果用户代理无法报告任何属性的值,例如由于用户或系统偏好、设置或限制,则称用户代理 无法报告电池状态信息

注意

6.1 内部槽

BatteryManager 实例创建时包含以下 内部槽

内部槽 初始值
[[Charging]] true
[[ChargingTime]] 0
[[DischargingTime]] 正无穷大
[[Level]] 1.0

6.1.1 [[Charging]] 内部槽

[[Charging]] 内部槽表示系统电池的充电状态。如果电池正在放电,则其值 必须 设置为 false;如果电池正在充电、无法报告状态、系统没有电池或其他情况,则其值设置为 true

当系统电池的充电状态发生变化时,用户代理必须运行 更新电池状态并通知 算法, 使用 [[Charging]]truefalse, 具体取决于电池是充电还是放电,以及 "chargingchange"。

6.1.2 [[ChargingTime]] 内部槽

[[ChargingTime]] 内部槽表示系统电池完全充电所需的剩余时间(以秒为单位)。 如果电池已充满或系统没有电池,则其值 必须 设置为 0;如果电池正在放电、无法报告剩余充电时间或其他情况,则其值设置为正无穷大。

当电池充电时间更新时,用户代理必须运行 更新电池状态并通知 算法, 使用 [[ChargingTime]]、新的充电时间(以秒为单位),以及 "chargingtimechange"。

6.1.3 [[DischargingTime]] 内部槽

[[DischargingTime]] 属性表示系统电池完全放电并即将挂起所需的剩余时间(以秒为单位)。 如果电池正在充电、无法报告剩余放电时间、系统没有电池或其他情况,则其值 必须 设置为正无穷大。

当电池放电时间更新时,用户代理必须运行 更新电池状态并通知 算法, 使用 [[DischargingTime]]、新的放电时间(以秒为单位),以及 "dischargingtimechange"。

6.1.4 [[Level]] 内部槽

[[Level]] 内部槽表示系统电池的电量水平。如果系统电池耗尽并即将挂起,则其值 必须 设置为 0;如果电池已充满、无法报告电量水平或系统没有电池,则其值设置为 1.0。

当电池电量水平更新时,用户代理必须运行 更新电池状态并通知 算法, 使用 [[Level]]、新的电池电量水平,以及 "levelchange"。

注意

关于 "chargingtimechange"、"dischargingtimechange" 和 "levelchange" 事件触发频率的定义由实现决定。

6.2 charging 属性

charging 的 getter 步骤是返回 this.[[Charging]]

6.3 chargingTime 属性

chargingTime 的 getter 步骤是返回 this.[[ChargingTime]]

6.4 dischargingTime 属性

dischargingTime 的 getter 步骤是返回 this.[[DischargingTime]]

6.5 level 属性

level 的 getter 步骤是返回 this.[[Level]]

6.6 事件处理程序

以下是 事件处理程序(及其对应的 事件处理程序事件类型),它们 必须 作为 BatteryManager 对象的属性支持:

事件处理程序 事件处理程序事件类型
onchargingchange chargingchange
onchargingtimechange chargingtimechange
ondischargingtimechange dischargingtimechange
onlevelchange levelchange

6.7 算法

更新电池状态并通知 给定一个内部槽 slot、一个 value 和一个 eventName,运行以下步骤:

  1. global当前全局对象
  2. 如果 global 不是 Window,则中止这些步骤。
  3. navigatorglobal 的关联 Navigator
  4. batteryManagernavigator 的值。 [[BatteryManager]]
  5. 如果 batteryManagernull,则中止这些步骤。
  6. 在全局任务队列中排队一个任务,使用 电池状态任务源 给定 global 运行以下步骤:
    1. batteryManager.slot 设置为 value
    2. 触发一个事件,事件名称为 eventName,目标为 batteryManager

6.8 多电池

如果托管设备包含多个电池, BatteryManager 应该 暴露电池的统一视图。

[[Charging]] 内部槽 必须 设置为 true, 如果至少有一个电池的充电状态如上所述为 true。否则,它 必须 设置为 false。

[[ChargingTime]] 内部槽可以设置为 如果并行充电,则为单个电池的最大充电时间;如果串行充电,则为单个充电时间的总和。

[[DischargingTime]] 内部槽可以设置为 如果并行放电,则为单个电池的最大放电时间;如果串行放电,则为单个放电时间的总和。

[[Level]] 内部槽可以设置为 相同容量电池的电量平均值,或者不同容量电池的加权平均电量。

7. 权限策略集成

电池状态 API 是一个由字符串 "battery" 标识的 策略控制功能。其 默认允许列表'self'

8. 示例

本节为非规范性内容。

以下简单示例在每次电池电量变化时将电池电量写入控制台:

// 当 promise 解析时获取初始值...
navigator.getBattery().then(function(battery) {
    console.log(battery.level);
    // ...以及任何后续更新。
    battery.onlevelchange = function() {
    console.log(this.level);
    };
});

或者,使用 addEventListener() 方法实现相同功能:

navigator.getBattery().then(function(battery) {
    console.log(battery.level);
    battery.addEventListener('levelchange', function() {
    console.log(this.level);
    });
});

以下示例更新指示器以显示充电状态、电量和剩余时间(以分钟为单位):

<!DOCTYPE html>
<html>
<head>
    <title>Battery Status API 示例</title>
    <script>
    window.onload = function () {
        function updateBatteryStatus(battery) {
        document.querySelector('#charging').textContent = battery.charging ? 'charging' : 'not charging';
        document.querySelector('#level').textContent = battery.level;
        document.querySelector('#dischargingTime').textContent = battery.dischargingTime / 60;
        }

        navigator.getBattery().then(function(battery) {
        // 初始更新电池状态...
        updateBatteryStatus(battery);

        // ...以及任何后续更新。
        battery.onchargingchange = function () {
            updateBatteryStatus(battery);
        };

        battery.onlevelchange = function () {
            updateBatteryStatus(battery);
        };

        battery.ondischargingtimechange = function () {
            updateBatteryStatus(battery);
        };
        });
    };
    </script>
</head>
<body>
    <div id="charging">(充电状态未知)</div>
    <div id="level">(电池电量未知)</div>
    <div id="dischargingTime">(放电时间未知)</div>
</body>
</html>

A. 索引

A.1 本规范定义的术语

A.2 引用定义的术语

B. IDL 索引

WebIDL[SecureContext]
partial interface Navigator {
  Promise<BatteryManager> getBattery();
};

[SecureContext, Exposed=Window]
interface BatteryManager : EventTarget {
    readonly        attribute boolean             charging;
    readonly        attribute unrestricted double chargingTime;
    readonly        attribute unrestricted double dischargingTime;
    readonly        attribute double              level;
                    attribute EventHandler        onchargingchange;
                    attribute EventHandler        onchargingtimechange;
                    attribute EventHandler        ondischargingtimechange;
                    attribute EventHandler        onlevelchange;
};

C. 致谢

本组深深感谢 Mounir Lamouri、Jonas Sicking 和 Mozilla WebAPI 团队的宝贵反馈,这些反馈基于原型实现。特别感谢 System Information API 和 Device Orientation Event 规范的开发者们提供了最初的灵感。同时感谢 Page Visibility 规范的开发者们,他们激励了本规范的编辑撰写介绍章节,讨论了一些同样适用于本规范的现实世界高价值用例。特别感谢 Device APIs 工作组的所有参与者以及其他提供了大量反馈和意见的人们, 他们通过这样做使 Web 对所有人来说变得更好。最后,感谢 Lukasz Olejnik、Gunes Acar、Claude Castelluccia 和 Claudia Diaz 对本 API 的隐私分析。

D. 参考文献

D.1 规范性参考文献

[dom]
DOM 标准. Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
[ECMASCRIPT]
ECMAScript 语言规范. Ecma International. URL: https://tc39.es/ecma262/multipage/
[html]
HTML 标准. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[permissions-policy]
权限策略. Ian Clelland. W3C. 2024年9月25日. W3C 工作草案. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
RFC 中用于指示需求级别的关键词. S. Bradner. IETF. 1997年3月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
RFC 2119 关键词中大小写的歧义. B. Leiba. IETF. 2017年5月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc8174
[WEBIDL]
Web IDL 标准. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/