引言

电池是移动设备的"心脏"。无论是开发系统工具类应用、性能监控面板,还是做电量敏感的功耗优化,都需要精准掌握设备的电池状态。HarmonyOS NEXT 提供了 @ohos.batteryInfo 模块,它以同步常量的形式暴露设备的电池信息——电量、充电状态、健康度、温度、电压、电流等十余项关键指标。

相比 @ohos.wifiManager@ohos.window 这些需要处理 Promise 的模块,batteryInfo 的使用方式更加直观:所有属性都是可直接读取的常量,无需 await,无需 .then(),一行代码即可获取数据。

本文将以"电池健康实验室"Demo 为线索,逐一拆解 @ohos.batteryInfo 的全部属性,并探讨如何将这些数据组织为一个实用、美观的电池诊断面板。

@ohos.batteryInfo 模块概述

@ohos.batteryInfo 是 HarmonyOS NEXT 提供的电池信息查询模块,位于 @kit.BasicServicesKit 工具包。它的设计哲学非常简洁:将设备的电池状态封装为一组同步可读的常量,开发者无需任何异步操作即可获取完整信息。

导入方式

import batteryInfo from '@ohos.batteryInfo';

wifiManager 一致,采用 default import。

API 全貌

属性 类型 单位 说明
batterySOC number % (0-100) 当前电量百分比
chargingStatus BatteryChargeState 枚举 充电状态
healthStatus BatteryHealthState 枚举 电池健康状态
pluggedType BatteryPluggedType 枚举 充电器类型
batteryTemperature number 0.1°C 电池温度
voltage number µV 电池电压
nowCurrent number mA 瞬时电流(API 12+)
batteryCapacityLevel BatteryCapacityLevel 枚举 电量等级
technology string 电池技术(如 Li-poly)
isBatteryPresent boolean 电池是否存在

全部同步可用——这是 batteryInfo 最显著的特征。你可以在组件初始化、事件回调、定时器中的任意位置直接读取这些值。

核心属性详解

1. batterySOC — 电量百分比

const batterySOC: number;

这是最常用的电池指标,返回一个 0 到 100 的整数,表示当前剩余电量百分比。它是 UI 中"电池电量"显示的直接数据源。

const level: number = batteryInfo.batterySOC;
console.log('当前电量: ' + level + '%');

注意batterySOC 的值可能受系统电量显示策略影响——部分厂商会在 UI 层做"平滑处理",导致 API 返回的百分比与状态栏显示的百分比存在微小偏差。

2. chargingStatus — 充电状态

const chargingStatus: BatteryChargeState;

BatteryChargeState 是一个枚举,包含四种充电状态:

枚举值 数值 含义 UI 表现建议
NONE 0 未知状态 灰色问号
ENABLE 1 充电中 绿色闪电图标
DISABLE 2 未充电(放电中) 橙色电池图标
FULL 3 已充满 绿色对勾图标

Demo 中的判断逻辑:

private chargeLabel(s: batteryInfo.BatteryChargeState): string {
  if (s === batteryInfo.BatteryChargeState.NONE) return '未知';
  if (s === batteryInfo.BatteryChargeState.ENABLE) return '充电中';
  if (s === batteryInfo.BatteryChargeState.DISABLE) return '未充电';
  if (s === batteryInfo.BatteryChargeState.FULL) return '已充满';
  return '—';
}

实战技巧:不要使用 === 1 这样的魔法数字。始终使用枚举值(如 BatteryChargeState.ENABLE)进行比较,这既增强可读性,又避免因枚举值变更导致的 bug。

3. healthStatus — 电池健康状态

const healthStatus: BatteryHealthState;

这是判断电池是否需要更换的关键指标。BatteryHealthState 包含六种状态:

枚举值 含义 严重程度
UNKNOWN 未知
GOOD 良好 绿 — 正常
OVERHEAT 过热 红 — 需要降温
OVERVOLTAGE 电压过高 红 — 充电异常
COLD 温度过低 橙 — 影响续航
DEAD 电池损坏 红 — 需要更换

温度与健康的关系OVERHEATCOLD 两种状态与 batteryTemperature 联动。当温度超出安全范围时,系统会自动将健康状态标记为异常。锂电池的最佳工作温度在 20°C ~ 35°C,极端温度会加速电池老化。

Demo 中的颜色映射:

private healthColor(): string {
  if (this.healthEnum === batteryInfo.BatteryHealthState.GOOD) return '#10B981';   // 绿
  if (this.healthEnum === batteryInfo.BatteryHealthState.UNKNOWN) return '#94A3B8'; // 灰
  return '#EF4444';  // 红 — 所有异常状态
}

4. pluggedType — 充电器类型

const pluggedType: BatteryPluggedType;

这个属性告诉你设备是如何充电的,对于功耗分析和充电策略优化很重要。

枚举值 含义 典型场景
NONE 未连接充电器 电池供电
AC 交流电源 充电器直插
USB USB 充电 电脑/移动电源
WIRELESS 无线充电 Qi 充电板

充电功率提示:AC 充电通常意味着更高的充电功率(快充),USB 充电受限于接口功率(通常 5V/500mA 或 5V/1A),无线充电效率较低但更方便。你可以在应用中根据充电器类型向用户展示预估充满时间。

5. batteryTemperature — 电池温度

const batteryTemperature: number;  // 单位:0.1°C

这是最容易被用错的属性。 batteryTemperature 的单位是 0.1°C,不是 °C。必须除以 10 才能得到摄氏度值:

// 错误写法!
const temp: number = batteryInfo.batteryTemperature;
console.log('电池温度: ' + temp + '°C');  // 显示 350°C??

// 正确写法
const tempC: number = batteryInfo.batteryTemperature / 10;
console.log('电池温度: ' + tempC.toFixed(1) + '°C');  // 35.0°C

为什么使用 0.1°C 为单位? 这是嵌入式系统的常见做法——用整数代替浮点数,避免浮点运算开销,同时保留一位小数精度。类似的设计在 Android 的 BatteryManager.EXTRA_TEMPERATURE 中也能看到。

6. voltage — 电池电压

const voltage: number;  // 单位:µV(微伏)

与温度类似,voltage 使用了一个"非直觉"的单位——微伏(µV)。标准锂电池电压约 3.7V(即 3,700,000 µV)。转换为可读格式:

const voltageV: number = batteryInfo.voltage / 1000000;
console.log('电池电压: ' + voltageV.toFixed(3) + ' V');  // 3.702 V

电压与电量的关系:锂电池的电压并非恒定不变——满电时约 4.2V,放电至 3.0V 左右自动关机。电压是判断电池剩余容量的物理依据,但系统已经将其封装为更直观的 batterySOC 百分比。

7. nowCurrent — 瞬时电流

const nowCurrent: number;  // 单位:mA(毫安)

nowCurrent 是 API 12 新增的属性,表示电池当前的瞬时电流。正值表示充电电流,负值表示放电电流。这个数据对于电池健康监控应用至关重要——它可以用来:

  • 计算实时功耗(结合电压):power_mW = |nowCurrent| * voltage / 1000
  • 检测快充是否激活(电流 > 2000mA 通常意味着快充)
  • 异常电流告警(电流突增可能意味着应用异常耗电)
const current: number = batteryInfo.nowCurrent;
if (current > 2000) {
  console.log('快充已激活 (电流: ' + current + ' mA)');
} else if (current > 0) {
  console.log('普通充电中 (电流: ' + current + ' mA)');
} else if (current < 0) {
  console.log('放电中 (电流: ' + Math.abs(current) + ' mA)');
}

8. batteryCapacityLevel — 电量等级

const batteryCapacityLevel: BatteryCapacityLevel;

除了精确的百分比,系统还提供了一个语义化的电量等级,适合用于通知和 UI 决策:

枚举值 含义 建议动作
LEVEL_FULL 满电 可断开充电器
LEVEL_HIGH 高电量 (≥60%) 正常使用
LEVEL_NORMAL 正常 (20%-60%) 正常使用
LEVEL_LOW 低电量 (10%-20%) 建议开启省电模式
LEVEL_WARNING 电量警告 (5%-10%) 提示用户充电
LEVEL_CRITICAL 严重低电 (3%-5%) 强制省电
LEVEL_SHUTDOWN 即将关机 (❤️%) 保存数据,即将关机

这个等级比百分比更适合用于用户通知——"电量低"比"电量 12%"更具可操作性。

9. technology 与 isBatteryPresent

const technology: string;        // 如 "Li-poly"(锂聚合物)、"Li-ion"(锂离子)
const isBatteryPresent: boolean; // 电池是否存在
  • technology 标识电池的化学类型。目前主流移动设备使用锂聚合物(Li-poly)或锂离子(Li-ion)电池
  • isBatteryPresent 在普通手机/平板上始终为 true,但在某些可拆卸电池设备或开发板上可能为 false

实战:电池健康实验室

页面结构设计

整个页面分为六个区域:

┌─────────────────────────────────┐
│  < 电池健康实验室  @ohos.batteryInfo │  ← 标题栏(#10B981 翠绿)
├─────────────────────────────────┤
│  电池电量                        │
│  ┌─────────────────────────┐   │
│  │   ┌──┐                  │   │  ← 圆形电量仪表 + 充电信息
│  │   │85│%  充电状态 充电中  │   │     左侧:大数字电量百分比
│  │   └──┘   充电器  交流电源 │   │     右侧:充电状态/充电器/电流
│  │           当前电流 1580mA │   │
│  └─────────────────────────┘   │
├─────────────────────────────────┤
│  电池详情                        │
│  ┌─────────────────────────┐   │
│  │ 健康状态  良好    温度  35.2°C│  ← 四宫格详情
│  │ 电压      3.702V  电池技术 Li-poly│
│  │ 电池存在  是      容量等级 高电量│
│  └─────────────────────────┘   │
├─────────────────────────────────┤
│  充电与健康可视化                │
│  ┌─────────────────────────┐   │
│  │ ● 充电中           ● 良好 │  ← 双栏状态 + 建议文案
│  │ 设备正在充电...    电池状态良好│
│  └─────────────────────────┘   │
├─────────────────────────────────┤
│  [ 刷新电池数据 ]               │  ← 操作按钮
├─────────────────────────────────┤
│  操作日志                        │  ← 时间戳日志列表
└─────────────────────────────────┘

状态管理

@State batterySOC: number = 0;
@State chargingStatus: string = '—';
@State chargingEnum: number = -1;   // 保存枚举值用于颜色判断
@State healthStatus: string = '—';
@State healthEnum: number = -1;     // 保存枚举值用于颜色判断
@State pluggedType: string = '—';
@State voltageText: string = '—';
@State temperatureText: string = '—';
@State technology: string = '—';
@State isBatteryPresent: boolean = false;
@State capacityLevel: string = '—';
@State nowCurrent: string = '—';
@State eventLogs: EventLog[] = [];
@State loading: boolean = true;

设计要点:除了中文标签(chargingStatus),还保留了原始的枚举值(chargingEnum)。这是因为后续的颜色逻辑需要根据枚举值判断——例如 BatteryChargeState.ENABLE 显示绿色,BatteryChargeState.DISABLE 显示橙色。如果仅保留中文字符串,就无法进行枚举比较。

数据读取:一读全读

由于所有属性都是同步常量,数据读取极其简洁——一个方法完成全部:

private loadBattery(): void {
  this.addLog('开始读取电池信息...');
  try {
    this.batterySOC = batteryInfo.batterySOC;
    this.chargingEnum = batteryInfo.chargingStatus;
    this.chargingStatus = this.chargeLabel(batteryInfo.chargingStatus);
    this.healthEnum = batteryInfo.healthStatus;
    this.healthStatus = this.healthLabel(batteryInfo.healthStatus);
    this.pluggedEnum = batteryInfo.pluggedType;
    this.pluggedType = this.pluggedLabel(batteryInfo.pluggedType);

    const voltageV: number = batteryInfo.voltage / 1000000;
    this.voltageText = voltageV.toFixed(3) + ' V';

    const tempC: number = batteryInfo.batteryTemperature / 10;
    this.temperatureText = tempC.toFixed(1) + ' °C';

    this.technology = batteryInfo.technology !== '' ? batteryInfo.technology : '未知';
    this.isBatteryPresent = batteryInfo.isBatteryPresent;
    this.capacityLevel = this.capacityLabel(batteryInfo.batteryCapacityLevel);

    const current: number = batteryInfo.nowCurrent;
    this.nowCurrent = current !== 0 ? current + ' mA' : '—';

    this.loading = false;
  } catch (e) {
    this.loading = false;
    this.addLog('读取电池信息失败');
  }
}

与 WiFi 实验室的对比:WiFi 管理器需要使用 .then().then().catch() 的 Promise 链式调用处理异步数据,而电池信息是纯同步的——一个方法内即可完成全部读取和格式化。这体现了 HarmonyOS API 设计中的"恰如其分的复杂度":对于 I/O 密集型操作(网络/WiFi)使用异步,对于系统状态查询(电池)使用同步。

圆形电量仪表

使用 Stack 叠加实现中心大字 + 百分号的效果:

Stack({ alignContent: Alignment.Center }) {
  Circle({ width: 100, height: 100 })
    .fill('#F1F5F9')
  Text(this.batterySOC.toString())
    .fontSize(36).fontColor(this.socColor())
    .fontWeight(FontWeight.Bold)
  Text('%')
    .fontSize(14).fontColor(this.socColor())
    .fontWeight(FontWeight.Bold)
    .margin({ top: 24 })
}

电量颜色动态变化:绿色(≥50%)、橙色(20-49%)、红色(<20%)。

充电与健康可视化面板

Demo 中的双栏可视化面板是用户友好的设计亮点。它不只是展示数据,还根据状态给出人性化的建议

Text(this.chargingEnum === batteryInfo.BatteryChargeState.ENABLE ?
  '设备正在充电,请注意散热' :
  this.chargingEnum === batteryInfo.BatteryChargeState.FULL ?
  '电池已充满,可断开充电器' :
  this.chargingEnum === batteryInfo.BatteryChargeState.DISABLE ?
  '电池正在放电中' : '充电状态未知')

这个模式可以扩展到更多的上下文感知场景——例如当温度 > 40°C 且正在充电时,提示"充电中温度较高,建议暂停使用"。
在这里插入图片描述
在这里插入图片描述

枚举值比较 vs 魔法数字

在 Demo 中,所有的枚举比较都使用了完整的枚举路径:

// 推荐
if (h === batteryInfo.BatteryHealthState.GOOD) { ... }

// 不推荐
if (h === 1) { ... }

前者的优势:

  1. 语义明确——一眼就知道在比较什么
  2. IDE 支持自动补全和跳转定义
  3. 如果 SDK 更新改变了枚举值,编译器会报错而不是静默产生逻辑 bug
  4. 代码审查友好

完整代码

import { router } from '@kit.ArkUI';
import batteryInfo from '@ohos.batteryInfo';
import { FontSize, Spacing } from '../common/Constants';

interface EventLog {
  time: string;
  msg: string;
}

@Entry
@Component
struct BatteryLabPage {
  @State batterySOC: number = 0;
  @State chargingStatus: string = '—';
  @State chargingEnum: number = -1;
  @State healthStatus: string = '—';
  @State healthEnum: number = -1;
  @State pluggedType: string = '—';
  @State pluggedEnum: number = -1;
  @State voltageText: string = '—';
  @State temperatureText: string = '—';
  @State technology: string = '—';
  @State isBatteryPresent: boolean = false;
  @State capacityLevel: string = '—';
  @State nowCurrent: string = '—';
  @State eventLogs: EventLog[] = [];
  @State loading: boolean = true;

  aboutToAppear(): void {
    this.loadBattery();
  }

  private loadBattery(): void {
    this.addLog('开始读取电池信息...');
    try {
      this.batterySOC = batteryInfo.batterySOC;
      this.chargingEnum = batteryInfo.chargingStatus;
      this.chargingStatus = this.chargeLabel(batteryInfo.chargingStatus);
      this.healthEnum = batteryInfo.healthStatus;
      this.healthStatus = this.healthLabel(batteryInfo.healthStatus);
      this.pluggedEnum = batteryInfo.pluggedType;
      this.pluggedType = this.pluggedLabel(batteryInfo.pluggedType);

      const voltageV: number = batteryInfo.voltage / 1000000;
      this.voltageText = voltageV.toFixed(3) + ' V';

      const tempC: number = batteryInfo.batteryTemperature / 10;
      this.temperatureText = tempC.toFixed(1) + ' °C';

      this.technology = batteryInfo.technology !== '' ?
        batteryInfo.technology : '未知';
      this.isBatteryPresent = batteryInfo.isBatteryPresent;
      this.capacityLevel = this.capacityLabel(
        batteryInfo.batteryCapacityLevel);

      const current: number = batteryInfo.nowCurrent;
      this.nowCurrent = current !== 0 ? current + ' mA' : '—';

      this.addLog('电池电量: ' + this.batterySOC + '%');
      this.addLog('充电状态: ' + this.chargingStatus);
      this.addLog('健康状态: ' + this.healthStatus);
      this.loading = false;
    } catch (e) {
      this.loading = false;
      this.addLog('读取电池信息失败');
    }
  }

  private chargeLabel(s: batteryInfo.BatteryChargeState): string {
    if (s === batteryInfo.BatteryChargeState.NONE) return '未知';
    if (s === batteryInfo.BatteryChargeState.ENABLE) return '充电中';
    if (s === batteryInfo.BatteryChargeState.DISABLE) return '未充电';
    if (s === batteryInfo.BatteryChargeState.FULL) return '已充满';
    return '—';
  }

  private healthLabel(h: batteryInfo.BatteryHealthState): string {
    if (h === batteryInfo.BatteryHealthState.UNKNOWN) return '未知';
    if (h === batteryInfo.BatteryHealthState.GOOD) return '良好';
    if (h === batteryInfo.BatteryHealthState.OVERHEAT) return '过热';
    if (h === batteryInfo.BatteryHealthState.OVERVOLTAGE) return '过压';
    if (h === batteryInfo.BatteryHealthState.COLD) return '过冷';
    if (h === batteryInfo.BatteryHealthState.DEAD) return '损坏';
    return '—';
  }

  private pluggedLabel(p: batteryInfo.BatteryPluggedType): string {
    if (p === batteryInfo.BatteryPluggedType.NONE) return '未充电';
    if (p === batteryInfo.BatteryPluggedType.AC) return '交流电源';
    if (p === batteryInfo.BatteryPluggedType.USB) return 'USB';
    if (p === batteryInfo.BatteryPluggedType.WIRELESS) return '无线充电';
    return '—';
  }

  private capacityLabel(l: batteryInfo.BatteryCapacityLevel): string {
    if (l === batteryInfo.BatteryCapacityLevel.LEVEL_FULL) return '满电';
    if (l === batteryInfo.BatteryCapacityLevel.LEVEL_HIGH) return '高电量';
    if (l === batteryInfo.BatteryCapacityLevel.LEVEL_NORMAL) return '正常';
    if (l === batteryInfo.BatteryCapacityLevel.LEVEL_LOW) return '低电量';
    if (l === batteryInfo.BatteryCapacityLevel.LEVEL_WARNING) return '电量警告';
    if (l === batteryInfo.BatteryCapacityLevel.LEVEL_CRITICAL) return '严重低电';
    if (l === batteryInfo.BatteryCapacityLevel.LEVEL_SHUTDOWN) return '即将关机';
    return '—';
  }

  private healthColor(): string {
    if (this.healthEnum === batteryInfo.BatteryHealthState.GOOD)
      return '#10B981';
    if (this.healthEnum === batteryInfo.BatteryHealthState.UNKNOWN)
      return '#94A3B8';
    return '#EF4444';
  }

  private chargeColor(): string {
    if (this.chargingEnum === batteryInfo.BatteryChargeState.ENABLE ||
        this.chargingEnum === batteryInfo.BatteryChargeState.FULL)
      return '#10B981';
    if (this.chargingEnum === batteryInfo.BatteryChargeState.DISABLE)
      return '#F59E0B';
    return '#94A3B8';
  }

  private socColor(): string {
    if (this.batterySOC >= 50) return '#10B981';
    if (this.batterySOC >= 20) return '#F59E0B';
    return '#EF4444';
  }

  // ... build() 方法省略,参见项目源码
}

权限与系统能力

@ohos.batteryInfo 的所有属性均无需额外权限即可读取。它属于 SystemCapability.PowerManager.BatteryManager.Core 系统能力,这是所有鸿蒙设备的基础能力。

无需在 module.json5 中声明任何 requestPermissions

与其它平台对比

平台 获取电池信息的方式 同步/异步
HarmonyOS NEXT batteryInfo.batterySOC 等同步常量 同步
Android IntentFilter + BroadcastReceiver 监听 BATTERY_CHANGED 异步(广播)
iOS UIDevice.current.isBatteryMonitoringEnabled + batteryLevel 同步(需开启监控)
Web navigator.getBattery() 异步(Promise)

HarmonyOS 的设计在简洁性上最接近 iOS——同步读取,无需注册监听器。区别在于 iOS 需要先设置 isBatteryMonitoringEnabled = true 才能读取,而 HarmonyOS 随时可读。

扩展实践:定时刷新

虽然 batteryInfo 的属性是同步的,但电池状态会实时变化。要提高数据的新鲜度,可以使用 setInterval 定时刷新:

private timerId: number = -1;

aboutToAppear(): void {
  this.loadBattery();
  this.timerId = setInterval(() => {
    this.loadBattery();
  }, 5000);  // 每 5 秒刷新
}

aboutToDisappear(): void {
  if (this.timerId !== -1) {
    clearInterval(this.timerId);
  }
}

注意:过于频繁的轮询(如 1 秒以下)会增加不必要的 CPU 开销。5~10 秒的间隔对于电池数据来说已经足够。如果需要实时响应电池状态变化,更好的做法是订阅系统广播 COMMON_EVENT_BATTERY_CHANGED,这需要使用 @ohos.commonEventManager,超出本文范围。

常见问题

1. 模拟器上所有电池数据都为 0 或默认值

原因:模拟器没有真实电池硬件,系统返回默认值。

解决:在真机上测试可获得真实数据。模拟器仅用于验证 UI 渲染和编译。

2. batteryTemperature 显示温度异常高(如 350°C)

原因:忘记除以 10。batteryTemperature 单位为 0.1°C。

解决:始终使用 batteryInfo.batteryTemperature / 10 获取摄氏度。

3. nowCurrent 始终为 0

原因nowCurrent 是 API 12 新增的属性,旧版本设备可能返回 0。

解决:做好兜底处理——current !== 0 ? current + ' mA' : '—'

总结

本文系统讲解了 HarmonyOS NEXT 中 @ohos.batteryInfo 模块的全部 10 个属性,并通过"电池健康实验室"Demo 展示了实战应用。核心要点:

  1. 全同步 API:所有属性均为常量,无需异步操作——这是 batteryInfo 最大的便利之处。

  2. 单位陷阱:温度是 0.1°C(需除 10),电压是 µV(需除 10^6),使用前务必完成单位转换。

  3. 枚举优于数字:始终使用 BatteryHealthState.GOOD 而非 1 进行比较——这是工程质量的底线。

  4. 数据 + 建议 = 好 UX:仅仅展示数字是不够的。Demo 中的"充电与健康可视化"面板将枚举值转化为人性化的建议——这才是面向用户的应用应有的设计水准。

  5. 电量等级 ≠ 电量百分比batteryCapacityLevel 提供的是语义化等级,更适合用于通知和 UI 决策。

掌握 @ohos.batteryInfo,你就能开发出电池诊断、功耗监控、充电优化等一系列实用工具。作为 BasicServicesKit 的核心模块之一,它与 @ohos.wifiManager(网络)、@ohos.deviceInfo(设备)、@ohos.power(电源管理)共同构成了鸿蒙设备信息的基础能力矩阵。


Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐