Flutter 鸿蒙实战:用 battery_plus 三方库给应用加上电池状态监测与充电动效
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_plugins monorepo 里完成鸿蒙适配。本文介绍它在 OpenHarmony 上的引入方式、4 个接口的逐个调用与真实运行效果,并附 FAQ 与问题反馈流程。



一、环境搭建
本章不重复展开,直接引用官方文档:Flutter OH 开发环境搭建指导。

完成后用 flutter doctor -v 验证,Flutter 与 HarmonyOS toolchain 两项均为 [√] 即可。本文实际使用的版本:Flutter OH oh-3.44.9-dev(commit 77e0c8d13b)、DevEco Studio 26.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: flutter
battery_plus:
git:
url: https://atomgit.com/CPF-Flutter/flutter_plus_plugins.git
ref: 9571de239933ab2893dbd49037e128135b050a7c
path: 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():获取单例
final battery = Battery();
Battery 是单例工厂:第二次 Battery() 会复用同一实例。不要重复创建,否则事件流订阅会被覆盖。
4.2.2 batteryLevel:电量查询
功能说明:异步 getter,返回当前电量百分比(0-100 的整数)。
final level = await battery.batteryLevel;
print('当前电量:$level%');
运行效果:

demo 首屏:大字 100% 即 batteryLevel 返回值,电量充足时显示绿色。下方副标题标注了对应的 API 名。
4.2.3 batteryState:状态查询
功能说明:异步 getter,返回 BatteryState 枚举(charging / discharging / full / unknown)。
final state = await battery.batteryState;
switch (state) {
case BatteryState.charging: print('充电中');
case BatteryState.discharging: print('放电中');
case BatteryState.full: print('已充满');
default: print('未知');
}
运行效果:

通过 DevEco 模拟器命令 Emulator -instance "Pura X View" -battery 65 改变电量后刷新:大字变为 65%,事件流日志累积了多次调用记录。模拟器无真实电池硬件,batteryState 显示 unknown 属正常行为。
4.2.4 isInBatterySaveMode:省电模式查询
功能说明:异步 getter,返回设备是否处于省电模式。注意方法名是 isInBatterySaveMode(不是 isInPowerSaveMode,早期文档有此拼写错误)。
final powerSave = await battery.isInBatterySaveMode;
if (powerSave) {
// 降级:关闭高刷、减少上报频率
}
运行效果:

右侧卡片:isInBatterySaveMode() 返回 false(省电模式未开启)。鸿蒙适配版当前固定返回 false,见 5.1 Q5。
4.2.5 onBatteryStateChanged:状态变化事件流
功能说明:Stream<BatteryState>,订阅一次持续推送,免去手动轮询。必须在 dispose() 里 cancel 防止泄漏。
StreamSubscription<BatteryState>? _sub;
void initState() {
super.initState();
_sub = battery.onBatteryStateChanged.listen((s) {
print('电池状态变化:${s.name}');
});
}
void dispose() {
_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';
void main() => runApp(const BatteryApp());
class BatteryApp extends StatelessWidget {
const BatteryApp({super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'battery_plus · OpenHarmony',
theme: ThemeData(colorSchemeSeed: const Color(0xFF2EA043)),
home: const BatteryPage(),
);
}
}
class BatteryPage extends StatefulWidget {
const BatteryPage({super.key});
State<BatteryPage> createState() => _BatteryPageState();
}
class _BatteryPageState extends State<BatteryPage> {
final _battery = Battery();
int _level = -1;
BatteryState _state = BatteryState.unknown;
bool _powerSave = false;
final List<String> _events = [];
StreamSubscription<BatteryState>? _stateSub;
void initState() {
super.initState();
_refresh();
_stateSub = _battery.onBatteryStateChanged.listen((s) {
_log('onBatteryStateChanged → ${s.name}');
});
}
void dispose() {
_stateSub?.cancel();
super.dispose();
}
void _log(String msg) {
final now = 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 {
final level = await _battery.batteryLevel;
final state = 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}');
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('battery_plus · OpenHarmony')),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
Text('$_level%', style: const TextStyle(fontSize: 64)),
Text('状态:${_state.name} | 省电:$_powerSave'),
FilledButton(onPressed: _refresh, child: const Text('手动刷新')),
..._events.map(Text.new),
],
),
);
}
}
签名与构建(活动要求示例工程含 signingConfig: "default"):
flutter create --platforms ohos . # 生成 ohos 工程目录
# 在 ohos/build-profile.json5 填入签名材料(DevEco 自动生成于 ~/.ohos/config/)
flutter build hap --debug
hdc install build/ohos/hap/entry-default-signed.hap
无真机时,DevEco 模拟器可用命令脚本化触发电池状态,验证全部接口:
Emulator -instance "<模拟器名>" -battery 18 # 低电量(demo 变红)
Emulator -instance "<模拟器名>" -battery 65 # 中等电量(绿色)
Emulator -instance "<模拟器名>" -batteryStatus 1 # 触发 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 - 修改并提交:
git add packages/battery_plus/ git commit -m "fix(battery_plus): read isInBatterySaveMode from PowerManager on OHOS" git push -u origin fix/battery-save-mode - 发 PR:AtomGit 上 从
<你的账号>:fix/battery-save-mode→CPF-Flutter:master,描述中附鸿蒙设备验证截图(修改后isInBatterySaveMode正确返回 true 的效果)
六、其他内容
battery_plus 4.1.0 鸿蒙适配版开箱即用:一行 git 依赖 + 四个 API 即可覆盖电量查询、状态查询、省电模式、状态监听全部场景。配合 DevEco 模拟器的电池模拟命令,无需真机也能完整验证每个接口。已知限制是 isInBatterySaveMode 固定返回 false(可通过社区 Issue/PR 推动)。相比自己从零写 ArkTS 插件,直接复用 CPF-Flutter 适配成果是明显更优的选择。
更多推荐





所有评论(0)