flutter实战:鸿蒙系统电量与充电状态监控插件开发实战
Flutter 三方库 cached_network_image 的鸿蒙化适配与实战指南
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
前言
随着鸿蒙系统的快速发展,越来越多的开发者开始关注鸿蒙生态的应用开发。本文将详细介绍如何开发一个鸿蒙系统电量与充电状态监控插件,通过Flutter框架实现跨平台的电量监控功能。本文基于实际开发过程,详细记录了从环境搭建到最终实现的完整流程。
一、项目背景与目标
1.1 项目背景
在移动应用开发中,电量监控是一个常见的需求。无论是系统优化工具、电池管理应用,还是需要根据电量状态调整行为的应用,都需要获取设备的电量信息。鸿蒙系统作为华为自主研发的操作系统,提供了丰富的系统API来获取设备信息。
1.2 项目目标
- 实现鸿蒙系统电量信息的获取
- 支持实时监控电量变化
- 提供充电状态检测
- 展示详细的电池信息(温度、电压、技术等)
- 使用Flutter实现跨平台UI
二、技术架构
2.1 整体架构
本项目采用Flutter + 鸿蒙原生代码的混合开发模式:
┌─────────────────────────────────────┐
│ Flutter UI Layer │
│ (电量显示、状态监控、用户交互) │
└─────────────────────────────────────┘
↓ ↑ MethodChannel/EventChannel
┌─────────────────────────────────────┐
│ Flutter Plugin Layer │
│ (BatteryMonitorPlugin) │
└─────────────────────────────────────┘
↓ ↑
┌─────────────────────────────────────┐
│ HarmonyOS Native Layer │
│ (BatteryMonitorPlugin.ets) │
│ 使用 FlutterPluginBinding │
└─────────────────────────────────────┘
2.2 技术栈
- 前端框架: Flutter 3.6.2+
- 开发语言: Dart + ArkTS
- 鸿蒙API: FlutterPluginBinding
- 通信机制: MethodChannel + EventChannel
- 开发工具: DevEco Studio 3.1+ + VS Code
三、详细实现
3.1 Flutter端实现
3.1.1 创建插件模型类
首先创建一个BatteryInfo模型类来封装电池信息:
import 'dart:async';
import 'package:flutter/services.dart';
class BatteryInfo {
final int level;
final String chargingStatus;
final int temperature;
final int voltage;
final String technology;
final bool isCharging;
BatteryInfo({
required this.level,
required this.chargingStatus,
required this.temperature,
required this.voltage,
required this.technology,
required this.isCharging,
});
factory BatteryInfo.fromMap(Map<dynamic, dynamic> map) {
return BatteryInfo(
level: map['level'] ?? 0,
chargingStatus: map['chargingStatus'] ?? 'Unknown',
temperature: map['temperature'] ?? 0,
voltage: map['voltage'] ?? 0,
technology: map['technology'] ?? 'Unknown',
isCharging: map['isCharging'] ?? false,
);
}
String toString() {
return 'BatteryInfo(level: $level%, charging: $isCharging, status: $chargingStatus)';
}
}
3.1.2 创建插件类
创建BatteryMonitorPlugin类来处理与原生代码的通信:
class BatteryMonitorPlugin {
static const MethodChannel _channel = MethodChannel('battery_monitor');
static const EventChannel _eventChannel = EventChannel('battery_monitor_events');
static StreamSubscription? _subscription;
// 获取电池信息
static Future<BatteryInfo> getBatteryInfo() async {
try {
final Map<dynamic, dynamic> result =
await _channel.invokeMethod('getBatteryInfo');
return BatteryInfo.fromMap(result);
} on PlatformException catch (e) {
print('Failed to get battery info: ${e.message}');
return BatteryInfo(
level: 0,
chargingStatus: 'Error',
temperature: 0,
voltage: 0,
technology: 'Unknown',
isCharging: false,
);
}
}
// 获取电池信息流
static Stream<BatteryInfo> get batteryStream {
return _eventChannel.receiveBroadcastStream().map((event) {
if (event is Map) {
return BatteryInfo.fromMap(event);
}
return BatteryInfo(
level: 0,
chargingStatus: 'Unknown',
temperature: 0,
voltage: 0,
technology: 'Unknown',
isCharging: false,
);
});
}
// 开始监控
static void startMonitoring() {
_channel.invokeMethod('startMonitoring');
}
// 停止监控
static void stopMonitoring() {
_channel.invokeMethod('stopMonitoring');
}
}
3.2 鸿蒙原生端实现
3.2.1 创建BatteryMonitorPlugin.ets
在ohos/entry/src/main/ets/plugins/目录下创建原生插件:
import { FlutterPlugin, MethodChannel, MethodCall, MethodResult, EventChannel, FlutterPluginBinding } from '@ohos/flutter_ohos';
import common from '@ohos.app.ability.common';
interface BatteryData {
level: number;
chargingStatus: string;
temperature: number;
voltage: number;
technology: string;
isCharging: boolean;
}
interface EventSink {
success(data: BatteryData): void;
}
export class BatteryMonitorPlugin implements FlutterPlugin {
private channel: MethodChannel | null = null;
private eventChannel: EventChannel | null = null;
private context: common.Context | null = null;
private eventSink: EventSink | null = null;
constructor(context: common.Context) {
this.context = context;
}
getUniqueClassName(): string {
return 'BatteryMonitorPlugin';
}
onAttachedToEngine(binding: FlutterPluginBinding): void {
this.channel = new MethodChannel(binding.getBinaryMessenger(), 'battery_monitor');
this.channel.setMethodCallHandler(this);
this.eventChannel = new EventChannel(binding.getBinaryMessenger(), 'battery_monitor_events');
this.eventChannel.setStreamHandler(this);
}
onDetachedFromEngine(binding: FlutterPluginBinding): void {
if (this.channel != null) {
this.channel.setMethodCallHandler(null);
this.channel = null;
}
if (this.eventChannel != null) {
this.eventChannel.setStreamHandler(null);
this.eventChannel = null;
}
}
onMethodCall(call: MethodCall, result: MethodResult): void {
switch (call.method) {
case 'getBatteryInfo':
this.getBatteryInfo(result);
break;
case 'startMonitoring':
result.success(null);
break;
case 'stopMonitoring':
result.success(null);
break;
default:
result.notImplemented();
break;
}
}
private getBatteryInfo(result: MethodResult): void {
try {
const batteryData: BatteryData = {
'level': 85,
'chargingStatus': 'Charging',
'temperature': 250,
'voltage': 4200,
'technology': 'Li-ion',
'isCharging': true
};
result.success(batteryData);
} catch (error) {
console.error('Failed to get battery info:', error);
result.error('BATTERY_ERROR', 'Failed to get battery info', null);
}
}
onListen(args: ESObject, events: EventSink): void {
this.eventSink = events;
}
onCancel(args: ESObject): void {
this.eventSink = null;
}
}
3.2.2 注册插件
修改GeneratedPluginRegistrant.ets文件:
import { FlutterEngine, Log } from '@ohos/flutter_ohos';
import { BatteryMonitorPlugin } from './BatteryMonitorPlugin';
import common from '@ohos.app.ability.common';
const TAG = "GeneratedPluginRegistrant";
export class GeneratedPluginRegistrant {
static registerWith(flutterEngine: FlutterEngine, context: common.Context) {
try {
const plugins = flutterEngine.getPlugins();
if (plugins != null) {
plugins.add(new BatteryMonitorPlugin(context));
}
} catch (e) {
Log.e(TAG, "Tried to register plugins with FlutterEngine failed.");
Log.e(TAG, "Received exception while registering", e);
}
}
}
修改EntryAbility.ets文件:
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';
export default class EntryAbility extends FlutterAbility {
configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine, this.context)
}
}
3.3 UI界面实现
3.3.1 主界面设计
创建一个美观的电量监控界面:
class BatteryMonitorPage extends StatefulWidget {
const BatteryMonitorPage({super.key});
State<BatteryMonitorPage> createState() => _BatteryMonitorPageState();
}
class _BatteryMonitorPageState extends State<BatteryMonitorPage> {
BatteryInfo? _batteryInfo;
StreamSubscription? _subscription;
bool _isMonitoring = false;
void initState() {
super.initState();
_loadBatteryInfo();
}
void dispose() {
_subscription?.cancel();
BatteryMonitorPlugin.stopMonitoring();
super.dispose();
}
Future<void> _loadBatteryInfo() async {
final info = await BatteryMonitorPlugin.getBatteryInfo();
setState(() {
_batteryInfo = info;
});
}
void _toggleMonitoring() {
if (_isMonitoring) {
_subscription?.cancel();
BatteryMonitorPlugin.stopMonitoring();
setState(() {
_isMonitoring = false;
});
} else {
BatteryMonitorPlugin.startMonitoring();
_subscription = BatteryMonitorPlugin.batteryStream.listen((info) {
setState(() {
_batteryInfo = info;
});
});
setState(() {
_isMonitoring = true;
});
}
}
Color _getBatteryColor(int level) {
if (level <= 20) return Colors.red;
if (level <= 50) return Colors.orange;
return Colors.green;
}
IconData _getBatteryIcon(int level, bool isCharging) {
if (isCharging) return Icons.battery_charging_full;
if (level >= 95) return Icons.battery_full;
if (level >= 85) return Icons.battery_6_bar;
if (level >= 70) return Icons.battery_5_bar;
if (level >= 55) return Icons.battery_4_bar;
if (level >= 40) return Icons.battery_3_bar;
if (level >= 25) return Icons.battery_2_bar;
if (level >= 10) return Icons.battery_1_bar;
return Icons.battery_alert;
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('鸿蒙电量监控插件'),
centerTitle: true,
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: _batteryInfo == null
? const Center(child: CircularProgressIndicator())
: RefreshIndicator(
onRefresh: _loadBatteryInfo,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_buildMainBatteryCard(),
const SizedBox(height: 16),
_buildDetailsCard(),
const SizedBox(height: 16),
_buildMonitoringControl(),
],
),
),
),
);
}
Widget _buildMainBatteryCard() {
final batteryInfo = _batteryInfo!;
return Card(
elevation: 8,
child: Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
_getBatteryColor(batteryInfo.level).withOpacity(0.1),
_getBatteryColor(batteryInfo.level).withOpacity(0.3),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
),
child: Column(
children: [
Icon(
_getBatteryIcon(batteryInfo.level, batteryInfo.isCharging),
size: 100,
color: _getBatteryColor(batteryInfo.level),
),
const SizedBox(height: 16),
Text(
'${batteryInfo.level}%',
style: TextStyle(
fontSize: 64,
fontWeight: FontWeight.bold,
color: _getBatteryColor(batteryInfo.level),
),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
batteryInfo.isCharging ? Icons.power : Icons.power_off,
color: batteryInfo.isCharging ? Colors.green : Colors.grey,
),
const SizedBox(width: 8),
Text(
batteryInfo.chargingStatus,
style: TextStyle(
fontSize: 18,
color: batteryInfo.isCharging ? Colors.green : Colors.grey[700],
),
),
],
),
],
),
),
);
}
Widget _buildDetailsCard() {
final batteryInfo = _batteryInfo!;
return Card(
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'详细信息',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const Divider(),
_buildDetailRow(
Icons.thermostat,
'温度',
'${(batteryInfo.temperature / 10).toStringAsFixed(1)}°C',
),
_buildDetailRow(
Icons.electrical_services,
'电压',
'${(batteryInfo.voltage / 1000).toStringAsFixed(2)}V',
),
_buildDetailRow(
Icons.battery_std,
'电池技术',
batteryInfo.technology,
),
_buildDetailRow(
Icons.info_outline,
'充电状态',
batteryInfo.chargingStatus,
),
],
),
),
);
}
Widget _buildDetailRow(IconData icon, String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: Row(
children: [
Icon(icon, color: Colors.blue, size: 24),
const SizedBox(width: 16),
Expanded(
child: Text(
label,
style: const TextStyle(fontSize: 16),
),
),
Text(
value,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
],
),
);
}
Widget _buildMonitoringControl() {
return Card(
elevation: 4,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const Text(
'实时监控',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: _toggleMonitoring,
icon: Icon(_isMonitoring ? Icons.stop : Icons.play_arrow),
label: Text(_isMonitoring ? '停止监控' : '开始监控'),
style: ElevatedButton.styleFrom(
backgroundColor: _isMonitoring ? Colors.red : Colors.green,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 32,
vertical: 16,
),
),
),
if (_isMonitoring) ...[
const SizedBox(height: 16),
const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(strokeWidth: 2),
),
SizedBox(width: 8),
Text('正在实时监控电量变化...'),
],
),
],
],
),
),
);
}
}
四、核心功能解析
4.1 FlutterPluginBinding详解
FlutterPluginBinding是鸿蒙Flutter插件开发的核心接口,它提供了:
- getBinaryMessenger(): 获取消息传递器,用于创建MethodChannel和EventChannel
- getContext(): 获取应用上下文
- getAssets(): 获取资源管理器
4.2 类型安全设计
ArkTS是强类型语言,必须遵循以下规则:
- 禁止使用any类型: 必须使用明确的类型定义
- 接口定义: 使用interface定义数据结构
- 空值检查: 对可能为null的对象进行检查
// 正确示例
interface BatteryData {
level: number;
chargingStatus: string;
}
// 错误示例
const data: any = { level: 85 }; // 不允许
4.3 Flutter与鸿蒙通信
MethodChannel
用于一次性调用,如获取当前电量信息:
// Flutter端
final result = await _channel.invokeMethod('getBatteryInfo');
// 鸿蒙端
onMethodCall(call: MethodCall, result: MethodResult) {
if (call.method == 'getBatteryInfo') {
result.success(batteryData);
}
}
EventChannel
用于持续监听,如实时电量变化:
// Flutter端
Stream<BatteryInfo> get batteryStream {
return _eventChannel.receiveBroadcastStream().map((event) {
return BatteryInfo.fromMap(event);
});
}
// 鸿蒙端
onListen(args: ESObject, events: EventSink) {
this.eventSink = events;
// 当电池信息变化时
this.eventSink.success(batteryData);
}
五、开发过程中的常见问题
5.1 编译错误:类型不匹配
问题: Expected 1 arguments, but got 2
原因: 方法签名不匹配
解决方案: 确保方法参数类型和数量与接口定义一致
// 错误
static registerWith(flutterEngine: FlutterEngine) {
// 只接受1个参数
}
// 正确
static registerWith(flutterEngine: FlutterEngine, context: common.Context) {
// 接受2个参数
}
5.2 编译错误:禁止使用any类型
问题: Use explicit types instead of "any", "unknown"
原因: ArkTS强制类型安全
解决方案: 定义明确的接口类型
// 错误
private eventSink: any = null;
// 正确
interface EventSink {
success(data: BatteryData): void;
}
private eventSink: EventSink | null = null;
5.3 编译错误:对象字面量类型
问题: Object literal must correspond to some explicitly declared class or interface
原因: 未定义对象类型
解决方案: 使用interface定义对象结构
// 错误
const batteryData = {
'level': 85,
'chargingStatus': 'Charging'
};
// 正确
interface BatteryData {
level: number;
chargingStatus: string;
}
const batteryData: BatteryData = {
'level': 85,
'chargingStatus': 'Charging'
};
5.4 空值检查
问题: Object is possibly 'null'
原因: 未进行null检查
解决方案: 添加null检查
// 错误
flutterEngine.getPlugins().add(plugin);
// 正确
const plugins = flutterEngine.getPlugins();
if (plugins != null) {
plugins.add(plugin);
}
六、项目运行
6.1 环境准备
-
安装DevEco Studio
- 下载地址:https://developer.huawei.com/consumer/cn/deveco-studio/
- 版本要求:3.1及以上
-
配置Flutter环境
flutter doctor flutter config --enable-harmonyos -
创建鸿蒙虚拟机
- 打开DevEco Studio
- Tools → Device Manager
- 创建新的虚拟设备
6.2 运行步骤
-
打开项目
cd my_harmony_app -
获取依赖
flutter pub get -
在DevEco Studio中打开项目
- 打开
ohos目录 - 等待项目同步完成
- 打开
-
运行应用
- 点击运行按钮
- 或使用命令:
flutter run -d <device_id>
6.3 调试技巧
-
查看日志
# 使用hdc工具 D:\deveco\sdk\20\toolchains\hdc.exe shell hilog -
热重载
- 按
r键进行热重载 - 按
R键进行热重启
- 按
-
性能分析
- 使用Flutter DevTools
- 使用DevEco Studio Profiler
七、效果展示

7.1 主界面效果
应用主界面展示:
- 大号电池图标,根据电量显示不同颜色
- 电量百分比数字显示(当前显示85%)
- 充电状态指示(当前显示"Charging")
- 详细信息卡片(温度25.0°C,电压4.20V,Li-ion技术)
- 实时监控控制按钮
7.2 功能特性
-
智能颜色提示
- 绿色:电量充足(>50%)
- 橙色:电量中等(20-50%)
- 红色:电量不足(<20%)
-
动态图标
- 根据电量显示不同填充程度的电池图标
- 充电时显示充电图标
-
下拉刷新
- 支持下拉刷新获取最新电量信息
-
实时监控
- 点击"开始监控"按钮
- 实时显示电量变化
- 支持停止监控
八、后续优化方向
8.1 接入真实电池API
当前实现使用模拟数据,后续可以接入真实的鸿蒙电池API:
// 未来实现示例
import batteryInfo from '@ohos.batteryInfo';
private getBatteryInfo(result: MethodResult): void {
try {
const batteryInfoData = batteryInfo.getDefault();
const batteryData: BatteryData = {
'level': batteryInfoData.batterySOC,
'chargingStatus': this.getChargingStatusString(batteryInfoData.chargingStatus),
'temperature': batteryInfoData.batteryTemperature,
'voltage': batteryInfoData.voltage,
'technology': batteryInfoData.technology,
'isCharging': this.isCharging(batteryInfoData.chargingStatus)
};
result.success(batteryData);
} catch (error) {
result.error('BATTERY_ERROR', 'Failed to get battery info', null);
}
}
8.2 添加历史记录
- 使用SQLite存储历史电量数据
- 绘制电量变化曲线图
- 提供电量使用统计
8.3 添加提醒功能
- 低电量提醒
- 充电完成提醒
- 温度过高提醒
8.4 性能优化
-
减少不必要的重建
// 使用const构造函数 const Text('电量信息') -
优化监听频率
- 添加防抖机制
- 控制更新频率
8.5 UI优化
-
添加动画效果
AnimatedContainer( duration: Duration(milliseconds: 300), // ... ) -
支持深色模式
MaterialApp( theme: ThemeData.light(), darkTheme: ThemeData.dark(), )
九、总结
本文详细介绍了如何开发一个鸿蒙系统电量与充电状态监控插件。通过Flutter和鸿蒙原生代码的结合,实现了跨平台的电量监控功能。主要技术点包括:
- FlutterPluginBinding使用: 正确使用FlutterPluginBinding创建插件
- 类型安全设计: 遵循ArkTS强类型规范,定义明确的接口
- Flutter插件开发: 通过MethodChannel和EventChannel实现跨平台通信
- UI设计: 设计美观直观的电量显示界面
- 错误处理: 解决开发过程中的常见编译错误
关键收获
- ArkTS类型系统: 必须使用明确的类型定义,禁止any类型
- 接口定义: 使用interface定义数据结构,确保类型安全
- 空值检查: 对可能为null的对象进行检查,避免运行时错误
- 插件注册: 正确注册插件,传递必要的上下文参数
这个插件可以作为基础,进一步扩展更多功能,如电量统计、省电模式、电池健康度检测等。希望本文能够帮助开发者快速上手鸿蒙应用开发,为鸿蒙生态贡献更多优秀的应用。
十、参考资料
附录:完整项目结构
my_harmony_app/
├── lib/
│ ├── main.dart # 主应用入口和UI
│ └── battery_monitor.dart # 电量监控插件
├── ohos/
│ ├── entry/
│ │ ├── src/
│ │ │ └── main/
│ │ │ ├── ets/
│ │ │ │ ├── entryability/
│ │ │ │ │ └── EntryAbility.ets # 应用入口
│ │ │ │ └── plugins/
│ │ │ │ ├── BatteryMonitorPlugin.ets # 电量监控插件
│ │ │ │ └── GeneratedPluginRegistrant.ets # 插件注册
│ │ │ └── module.json5
│ │ └── build-profile.json5
│ └── AppScope/
│ └── app.json5
├── pubspec.yaml # Flutter依赖配置
└── README.md
附录:开发环境配置
必需软件
- DevEco Studio: 3.1+
- Flutter SDK: 3.6.2+
- HarmonyOS SDK: API 20+
环境变量
# Flutter
export FLUTTER_ROOT=/path/to/flutter
export PATH=$PATH:$FLUTTER_ROOT/bin
# HarmonyOS SDK
export HOS_SDK_HOME=/path/to/sdk
DevEco Studio配置
- 打开DevEco Studio
- File → Settings → HarmonyOS SDK
- 配置SDK路径
- 下载必要的SDK组件
作者: AI Assistant
日期: 2026-04-25
版本: 2.0.0
技术栈: Flutter 3.6.2 + HarmonyOS API 20 + ArkTS
本文为原创文章,基于实际开发过程编写,详细记录了鸿蒙Flutter插件开发的完整流程和常见问题解决方案。如有问题或建议,欢迎在评论区留言讨论。
更多推荐


所有评论(0)