Flutter 鸿蒙实战:用 battery_plus 三方库给应用加上电池状态监测与充电动效
Flutter 社区地址: https://atomgit.com/CPF-Flutter/flutter_flutter
github三方库地址:https://github.com/fluttercommunity/plus_plugins/tree/main/packages/battery_plus/battery_plus
pub地址:https://pub.dev/packages/battery_plus
鸿蒙适配版:https://atomgit.com/CPF-Flutter/flutter_plus_plugins
我的工程适配地址:https://atomgit.com/weixin_52908342/battery_demo
库版本:battery_plus 4.1.0(CPF-Flutter 鸿蒙适配版,commit
9571de2)|验证环境:Flutter 鸿蒙 SDK 3.44.9(oh-3.44.9-dev)|DevEco Studio 26.0.0.821 | 设备:DevEco 模拟器 Pura X View | HarmonyOS 7.0.0.106(API 26)
应用里的电池状态提示、电量告警、充电动效几乎是移动 App 标配。battery_plus是 Flutter 生态里用得最多的电池状态插件(pub.dev 月下载百万级),CPF-Flutter 社区已在flutter_plus_pluginsmonorepo 里完成鸿蒙适配。本文介绍它在 OpenHarmony 上的引入方式、4 个接口的逐个调用与真实运行效果,并附 FAQ 与问题反馈流程。
一、环境搭建
本章不重复展开,直接引用官方文档:Flutter OH 开发环境搭建指导。
完成后用flutter doctor -v验证,Flutter与HarmonyOS toolchain两项均为[√]即可。本文实际使用的版本:Flutter OHoh-3.44.9-dev(commit77e0c8d13b)、DevEco Studio26.0.0.821、HarmonyOS SDK API 26。
二、应用背景
2.1 当前的应用场景与痛点
- 儿童手表 / 老人手环类 App:需要根据电池余量动态降低刷新率、上传频率
- 导航 / 出行类:电量不足时提示用户充电,自动降级 UI 亮度
- 共享设备类:实时上报设备电量给云端
- 视频 / 游戏类:低电量时关闭高耗电特效
痛点在于:Flutter 官方battery_plus只覆盖 Android/iOS/Web/Windows/macOS/Linux,鸿蒙侧此前一片空白——应用迁到 OpenHarmony 后电池相关功能直接失效。
2.2 为什么需要这个库
自己写插件需要处理 ArkTS 通道、系统 API 差异、事件流生命周期,成本高;battery_plus的鸿蒙适配版由 CPF-Flutter 社区维护,一行 git 依赖即可获得跨端一致的 API。
2.3 解决什么问题
一句话总结:让 Flutter 应用在鸿蒙上以与 Android/iOS 完全相同的 API 读取电池状态。具体提供:
- 当前电量百分比(0-100)
- 电池状态(充电中 / 放电中 / 已充满 / 未知)
- 省电模式查询
- 电池状态变化事件流(免轮询、自动推送)
三、功能介绍
| 功能 | API | 说明 | 适用场景 |
|---|---|---|---|
| 电量查询 | batteryLevel | 返回Future<int>,0-100 | 电量展示、低电告警 |
| 状态查询 | batteryState | 返回Future<BatteryState>枚举 | 充电动效、充电提示音 |
| 省电模式 | isInBatterySaveMode | 返回Future<bool> | 省电模式下降低刷新率 |
| 状态变化流 | onBatteryStateChanged | Stream<BatteryState>,订阅后自动推送 | 实时监听插拔充电线 |
四、使用方法
4.1 在应用中引入三方库(AtomGit 链接方式)
dependencies:flutter:sdk:flutterbattery_plus:git:url:https://atomgit.com/CPF-Flutter/flutter_plus_plugins.gitref:9571de239933ab2893dbd49037e128135b050a7cpath:packages/battery_plus/battery_plus三个注意点:
path必须写到双层目录packages/battery_plus/battery_plus(monorepo 里插件在嵌套子目录),写成packages/battery_plus会 404ref建议写 commit hash(本文用9571de2),tag/分支名可能漂移- URL 用 AtomGit 而非 pub.dev——pub 上的
battery_plus没有 ohos 平台实现,必须走 CPF-Flutter 的适配仓库
执行flutter pub get后即可import 'package:battery_plus/battery_plus.dart';。
4.2 调用接口实现功能
4.2.1 Battery():获取单例
finalbattery=Battery();Battery是单例工厂:第二次Battery()会复用同一实例。不要重复创建,否则事件流订阅会被覆盖。
4.2.2 batteryLevel:电量查询
功能说明:异步 getter,返回当前电量百分比(0-100 的整数)。
finallevel=awaitbattery.batteryLevel;print('当前电量:$level%');运行效果:
demo 首屏:大字 100% 即batteryLevel返回值,电量充足时显示绿色。下方副标题标注了对应的 API 名。
4.2.3 batteryState:状态查询
功能说明:异步 getter,返回BatteryState枚举(charging/discharging/full/unknown)。
finalstate=awaitbattery.batteryState;switch(state){caseBatteryState.charging:print('充电中');caseBatteryState.discharging:print('放电中');caseBatteryState.full:print('已充满');default:print('未知');}运行效果:
通过 DevEco 模拟器命令Emulator -instance "Pura X View" -battery 65改变电量后刷新:大字变为 65%,事件流日志累积了多次调用记录。模拟器无真实电池硬件,batteryState显示unknown属正常行为。
4.2.4 isInBatterySaveMode:省电模式查询
功能说明:异步 getter,返回设备是否处于省电模式。注意方法名是isInBatterySaveMode(不是isInPowerSaveMode,早期文档有此拼写错误)。
finalpowerSave=awaitbattery.isInBatterySaveMode;if(powerSave){// 降级:关闭高刷、减少上报频率}运行效果:
右侧卡片:isInBatterySaveMode()返回false(省电模式未开启)。鸿蒙适配版当前固定返回 false,见 5.1 Q5。
4.2.5 onBatteryStateChanged:状态变化事件流
功能说明:Stream<BatteryState>,订阅一次持续推送,免去手动轮询。必须在dispose()里 cancel防止泄漏。
StreamSubscription<BatteryState>?_sub;@overridevoidinitState(){super.initState();_sub=battery.onBatteryStateChanged.listen((s){print('电池状态变化:${s.name}');});}@overridevoiddispose(){_sub?.cancel();super.dispose();}运行效果:
通过模拟器命令Emulator -batteryStatus 1(切换到充电态)触发真实事件:底部暗色事件流卡新增一行[00:54:45] onBatteryStateChanged → charging——无需任何手动刷新,事件自动推送到 Dart 层;顶部状态栏电池图标同步出现闪电符号。
补充:battery_plus 4.x没有
onBatteryLevelChanged(电量百分比变化流),如需细粒度电量监控请自行Timer.periodic轮询batteryLevel。
4.3 完整示例代码
可直接复制运行的main.dart(含 4 个接口的全调用 + 事件流日志 UI):
import'dart:async';import'package:battery_plus/battery_plus.dart';import'package:flutter/material.dart';voidmain()=>runApp(constBatteryApp());classBatteryAppextendsStatelessWidget{constBatteryApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'battery_plus · OpenHarmony',theme:ThemeData(colorSchemeSeed:constColor(0xFF2EA043)),home:constBatteryPage(),);}}classBatteryPageextendsStatefulWidget{constBatteryPage({super.key});@overrideState<BatteryPage>createState()=>_BatteryPageState();}class_BatteryPageStateextendsState<BatteryPage>{final_battery=Battery();int _level=-1;BatteryState_state=BatteryState.unknown;bool _powerSave=false;finalList<String>_events=[];StreamSubscription<BatteryState>?_stateSub;@overridevoidinitState(){super.initState();_refresh();_stateSub=_battery.onBatteryStateChanged.listen((s){_log('onBatteryStateChanged →${s.name}');});}@overridevoiddispose(){_stateSub?.cancel();super.dispose();}void_log(Stringmsg){finalnow=DateTime.now();setState((){_events.insert(0,'[${now.hour.toString().padLeft(2, '0')}:${now.minute.toString().padLeft(2, '0')}:${now.second.toString().padLeft(2, '0')}]$msg');if(_events.length>30)_events.removeLast();});}Future<void>_refresh()async{finallevel=await_battery.batteryLevel;finalstate=await_battery.batteryState;bool powerSave=false;try{powerSave=await_battery.isInBatterySaveMode;}catch(_){powerSave=false;}if(!mounted)return;setState((){_level=level;_state=state;_powerSave=powerSave;});_log('手动刷新:电量$level%,状态${state.name}');}@overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:AppBar(title:constText('battery_plus · OpenHarmony')),body:ListView(padding:constEdgeInsets.all(16),children:[Text('$_level%',style:constTextStyle(fontSize:64)),Text('状态:${_state.name}| 省电:$_powerSave'),FilledButton(onPressed:_refresh,child:constText('手动刷新')),..._events.map(Text.new),],),);}}签名与构建(活动要求示例工程含signingConfig: "default"):
flutter create--platformsohos.# 生成 ohos 工程目录# 在 ohos/build-profile.json5 填入签名材料(DevEco 自动生成于 ~/.ohos/config/)flutter build hap--debughdcinstallbuild/ohos/hap/entry-default-signed.hap无真机时,DevEco 模拟器可用命令脚本化触发电池状态,验证全部接口:
Emulator-instance"<模拟器名>"-battery18# 低电量(demo 变红)Emulator-instance"<模拟器名>"-battery65# 中等电量(绿色)Emulator-instance"<模拟器名>"-batteryStatus1# 触发 charging 事件流五、FAQ
5.1 常见问题
Q1:编译报The getter 'onBatteryLevelChanged' isn't defined
battery_plus 4.x 只有onBatteryStateChanged(状态流),没有电量百分比流。用Timer.periodic轮询batteryLevel替代。
Q2:编译报The getter 'isInPowerSaveMode' isn't defined
拼写错误:正确方法是isInBatterySaveMode。
Q3:batteryState在模拟器上一直返回unknown
正常现象——模拟器无真实电池硬件。用Emulator -batteryStatus 0|1强制切换状态可触发事件流;真机上会返回真实状态。
Q4:flutter pub get解析失败/找不到包
检查path: packages/battery_plus/battery_plus是否写完整(双层目录);镜像用export PUB_HOSTED_URL=https://pub.flutter-io.cn。
Q5:isInBatterySaveMode始终返回 false
鸿蒙适配版当前实现固定返回 false(省电模式真实监听尚未实现),属于已知限制。可关注上游仓库 issue 跟踪进度。
5.2 库本身存在问题:如何提交 Issue
仓库地址:https://atomgit.com/CPF-Flutter/flutter_plus_plugins
- 打开仓库 → Issues → 新建 Issue
- 标题:
[Bug] 现象简述(如[Bug] isInBatterySaveMode always returns false on OHOS) - 正文必备:复现步骤、期望行为、实际行为、设备与 SDK 版本(
flutter --version+hdc shell param get const.product.software.version)、最小复现代码 - 附上 demo 截图 / hilog 日志(
hdc shell hilog -t OHOSAbility -x)
5.3 能自己解决:如何提交 PR
- Fork仓库到自己账号:AtomGit 仓库页右上角 Fork
- 建分支:
git checkout -b fix/battery-save-mode - 修改并提交:
gitaddpackages/battery_plus/gitcommit-m"fix(battery_plus): read isInBatterySaveMode from PowerManager on OHOS"gitpush-uorigin fix/battery-save-mode - 发 PR:AtomGit 上 从
<你的账号>:fix/battery-save-mode→CPF-Flutter:master,描述中附鸿蒙设备验证截图(修改后isInBatterySaveMode正确返回 true 的效果)
六、其他内容
battery_plus4.1.0 鸿蒙适配版开箱即用:一行 git 依赖 + 四个 API 即可覆盖电量查询、状态查询、省电模式、状态监听全部场景。配合 DevEco 模拟器的电池模拟命令,无需真机也能完整验证每个接口。已知限制是isInBatterySaveMode固定返回 false(可通过社区 Issue/PR 推动)。相比自己从零写 ArkTS 插件,直接复用 CPF-Flutter 适配成果是明显更优的选择。