Flutter for OpenHarmony 实战:电池优化应用开发指南
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
作者:maaath
前言
Flutter 作为 Google 推出的跨平台 UI 框架,凭借其高性能、热重载和丰富的组件生态,已经成为移动端跨平台开发的首选方案之一。而 OpenHarmony 作为国产操作系统,正在积极拥抱跨平台开发框架。Flutter for OpenHarmony 的出现,让开发者能够使用同一套代码同时开发 Android、iOS 和 OpenHarmony 应用,大大提升了开发效率。
本文将通过一个实际的电池优化应用案例,详细讲解如何在 Flutter 项目中适配 OpenHarmony 平台,实现跨平台开发。项目中涉及的网络请求、本地存储等核心功能均采用 Flutter 官方推荐的实现方式,确保代码的可移植性和可维护性。
一、项目概述
本文要开发的是一个功能完善的电池优化应用,主要功能包括:
- 实时显示电池电量、温度、电压等关键信息
- 展示电池使用历史曲线
- 功耗应用排行榜
- 后台进程管理与优化
- 省电模式设置
该项目采用 Flutter 实现 UI 界面,通过平台通道(Platform Channel)调用 OpenHarmony 原生能力获取电池数据。这种架构设计既保证了 Flutter 的跨平台优势,又能够充分发挥 OpenHarmony 的系统能力。
二、项目结构设计
一个良好的项目结构是代码可维护性的基础。本项目采用分层架构设计,将界面层、业务层和数据层分离:
lib/
├── main.dart # 应用入口
├── model/ # 数据模型层
│ └── battery_model.dart # 电池相关数据模型
├── service/ # 业务服务层
│ └── battery_service.dart # 电池数据服务
├── pages/ # 页面层
│ └── battery_page.dart # 电池页面
├── components/ # 组件层
│ ├── battery_circle_progress.dart # 电量圆环组件
│ ├── battery_indicators.dart # 电池指标卡片
│ ├── battery_history.dart # 历史记录组件
│ ├── process_manager.dart # 进程管理组件
│ └── common_components.dart # 通用组件
└── utils/ # 工具层
└── battery_utils.dart # 电池工具函数
这种分层设计的优势在于:各层职责清晰,便于单元测试;上层依赖下层,依赖关系明确;当需要更换底层实现时,对上层代码影响最小。
三、核心代码实现
3.1 数据模型层
数据模型是应用的基础数据结构,定义了电池信息的统一格式。良好的模型设计应该具备以下特点:类型安全、不可变性(对于纯数据类)以及与后端数据结构的一致性。
dart
// lib/model/battery_model.dart
// 电池信息数据模型
class BatteryInfo {
final int level;
final String chargingStatus;
final String health;
final double temperature;
final int voltage;
final int currentNow;
final int remainingEnergy;
final int totalEnergy;
BatteryInfo({
required this.level,
required this.chargingStatus,
required this.health,
required this.temperature,
required this.voltage,
required this.currentNow,
required this.remainingEnergy,
required this.totalEnergy,
});
// 工厂方法:从 JSON 创建对象
factory BatteryInfo.fromJson(Map<String, dynamic> json) {
return BatteryInfo(
level: json['level'] as int,
chargingStatus: json['chargingStatus'] as String,
health: json['health'] as String,
temperature: (json['temperature'] as num).toDouble(),
voltage: json['voltage'] as int,
currentNow: json['currentNow'] as int,
remainingEnergy: json['remainingEnergy'] as int,
totalEnergy: json['totalEnergy'] as int,
);
}
// 转换为 JSON
Map<String, dynamic> toJson() {
return {
'level': level,
'chargingStatus': chargingStatus,
'health': health,
'temperature': temperature,
'voltage': voltage,
'currentNow': currentNow,
'remainingEnergy': remainingEnergy,
'totalEnergy': totalEnergy,
};
}
}
// 功耗排行数据模型
class PowerConsumptionInfo {
final String appName;
final String packageName;
final int consumptionLevel;
final double powerConsumptionMah;
PowerConsumptionInfo({
required this.appName,
required this.packageName,
required this.consumptionLevel,
required this.powerConsumptionMah,
});
}
// 进程项数据模型
class ProcessItem {
final String appName;
final String packageName;
final double memoryUsage;
final double cpuUsage;
final bool isHighConsumption;
ProcessItem({
required this.appName,
required this.packageName,
required this.memoryUsage,
required this.cpuUsage,
required this.isHighConsumption,
});
}
// 历史记录数据模型
class HistoryData {
final DateTime timestamp;
final int level;
final bool isCharging;
HistoryData({
required this.timestamp,
required this.level,
required this.isCharging,
});
}
上述模型设计采用了不可变(Immutable)模式,所有字段均为 final,通过构造函数初始化。这种设计的好处是:线程安全、无隐式修改、便于状态管理和调试。当需要修改对象时,创建新的实例替代旧实例。
3.2 电池服务层
服务层负责数据的获取和处理逻辑。在本项目中,电池数据通过平台通道从 OpenHarmony 原生层获取。服务层还负责数据的转换、缓存和错误处理。
dart
// lib/service/battery_service.dart
import '../model/battery_model.dart';
// 电池服务类
class BatteryService {
static final BatteryService _instance = BatteryService._internal();
factory BatteryService() => _instance;
BatteryService._internal();
// 获取电池信息
Future<BatteryInfo> getBatteryInfo() async {
// 实际项目中通过平台通道调用原生 API
// 这里使用模拟数据演示
return Future.delayed(
const Duration(milliseconds: 300),
() => BatteryInfo(
level: 75,
chargingStatus: 'none',
health: 'good',
temperature: 28.0,
voltage: 3800,
currentNow: -500,
remainingEnergy: 3800,
totalEnergy: 5000,
),
);
}
// 获取电池电量
Future<int> getBatteryLevel() async {
final info = await getBatteryInfo();
return info.level;
}
// 获取充电状态
Future<String> getChargingStatus() async {
final info = await getBatteryInfo();
return info.chargingStatus;
}
// 获取电池健康状态
Future<String> getBatteryHealth() async {
final info = await getBatteryInfo();
return info.health;
}
// 获取电池温度
Future<double> getBatteryTemperature() async {
final info = await getBatteryInfo();
return info.temperature;
}
// 获取电池电压
Future<int> getBatteryVoltage() async {
final info = await getBatteryInfo();
return info.voltage;
}
// 判断是否在充电
Future<bool> isCharging() async {
final status = await getChargingStatus();
return status == 'charging' || status == 'full';
}
// 获取功耗排行数据
Future<List<PowerConsumptionInfo>> getPowerConsumptionData() async {
return Future.delayed(
const Duration(milliseconds: 200),
() => [
PowerConsumptionInfo(
appName: '微信',
packageName: 'com.tencent.mm',
consumptionLevel: 28,
powerConsumptionMah: 420.0,
),
PowerConsumptionInfo(
appName: '抖音',
packageName: 'com.ss.android.ugc.aweme',
consumptionLevel: 22,
powerConsumptionMah: 330.0,
),
PowerConsumptionInfo(
appName: '淘宝',
packageName: 'com.taobao.taobao',
consumptionLevel: 15,
powerConsumptionMah: 225.0,
),
PowerConsumptionInfo(
appName: '支付宝',
packageName: 'com.eg.android.AlipayGphone',
consumptionLevel: 10,
powerConsumptionMah: 150.0,
),
PowerConsumptionInfo(
appName: 'QQ',
packageName: 'com.tencent.mobileqq',
consumptionLevel: 8,
powerConsumptionMah: 120.0,
),
],
);
}
// 获取后台进程列表
Future<List<ProcessItem>> getBackgroundProcesses() async {
return Future.delayed(
const Duration(milliseconds: 200),
() => [
ProcessItem(
appName: '微信',
packageName: 'com.tencent.mm',
memoryUsage: 320.0,
cpuUsage: 2.5,
isHighConsumption: false,
),
ProcessItem(
appName: '抖音',
packageName: 'com.ss.android.ugc.aweme',
memoryUsage: 450.0,
cpuUsage: 5.8,
isHighConsumption: true,
),
ProcessItem(
appName: '支付宝',
packageName: 'com.eg.android.AlipayGphone',
memoryUsage: 150.0,
cpuUsage: 0.8,
isHighConsumption: false,
),
],
);
}
// 获取历史数据
Future<List<HistoryData>> getHistoryData() async {
final now = DateTime.now();
final data = <HistoryData>[];
double level = 85.0;
for (int i = 23; i >= 0; i--) {
final timestamp = now.subtract(Duration(hours: i));
level = (level - (5 + (i % 3) * 2)).clamp(15.0, 100.0);
final isCharging = i == 12 || i == 6;
if (isCharging) {
level = (level + 15).clamp(15.0, 100.0);
}
data.add(HistoryData(
timestamp: timestamp,
level: level.round(),
isCharging: isCharging,
));
}
return data;
}
}
服务层采用了单例模式,确保全局只有一个服务实例,避免资源浪费。同时,所有方法都设计为异步返回 Future,这符合 Flutter 响应式编程的最佳实践,便于处理耗时操作和错误情况。
3.3 工具函数层
工具函数层包含数据格式化、颜色计算等辅助功能。这些函数应该是纯函数,无副作用,便于测试和复用。
dart
// lib/utils/battery_utils.dart
import 'package:flutter/material.dart';
// 格式化时间显示
String formatTime(int minutes) {
if (minutes <= 0) return '计算中...';
final hours = minutes ~/ 60;
final mins = minutes % 60;
if (hours > 0) {
return '${hours}小时${mins}分钟';
}
return '${mins}分钟';
}
// 格式化温度显示
String formatTemperature(double temp) {
return '${temp.toStringAsFixed(1)}°C';
}
// 格式化电压显示
String formatVoltage(int voltage) {
return '${(voltage / 1000).toStringAsFixed(2)}V';
}
// 获取健康状态文本
String getHealthStatusText(String health) {
const healthMap = {
'good': '优秀',
'overheat': '过热',
'dead': '损坏',
'over_voltage': '过压',
'cold': '过冷',
'unknown': '未知',
};
return healthMap[health] ?? '未知';
}
// 根据电量获取颜色
Color getBatteryLevelColor(int level) {
if (level > 60) {
return const Color(0xFF4CAF50); // 绿色
} else if (level > 30) {
return const Color(0xFFFF9800); // 橙色
} else if (level > 15) {
return const Color(0xFFFF5722); // 深橙
} else {
return const Color(0xFFF44336); // 红色
}
}
// 根据温度获取状态信息
Map<String, dynamic> getTemperatureStatus(double temp) {
if (temp >= 20 && temp <= 35) {
return {'text': '正常', 'color': const Color(0xFF4CAF50)};
} else if (temp > 35 && temp <= 40) {
return {'text': '轻微发热', 'color': const Color(0xFFFF9800)};
} else if (temp > 40) {
return {'text': '过热', 'color': const Color(0xFFF44336)};
} else if (temp < 10) {
return {'text': '过冷', 'color': const Color(0xFF2196F3)};
} else {
return {'text': '偏低', 'color': const Color(0xFF03A9F4)};
}
}
// 获取应用图标
String getAppIcon(String packageName) {
const iconMap = {
'com.tencent.mm': '💬',
'com.tencent.mobileqq': '💬',
'com.ss.android.ugc.aweme': '🎵',
'com.eg.android.AlipayGphone': '💰',
'com.taobao.taobao': '🛒',
'com.autonavi.minimap': '🗺️',
'com.tencent.tmgp.sgame': '🎮',
'android': '⚙️',
};
return iconMap[packageName] ?? '📱';
}
// 获取功耗等级颜色
Color getConsumptionColor(int percentage) {
if (percentage >= 20) {
return const Color(0xFFF44336);
} else if (percentage >= 10) {
return const Color(0xFFFF9800);
} else {
return const Color(0xFF4CAF50);
}
}
工具函数采用静态方法实现,便于直接调用而无需实例化。每个函数职责单一,易于理解和测试。
3.4 组件层设计
组件是 Flutter 应用的核心构成单元。本项目设计了多个可复用组件,实现关注点分离。
dart
// lib/components/battery_circle_progress.dart
import 'package:flutter/material.dart';
import '../utils/battery_utils.dart';
// 电池电量圆环组件
class BatteryCircleProgress extends StatelessWidget {
final int level;
final bool isCharging;
const BatteryCircleProgress({
super.key,
required this.level,
required this.isCharging,
});
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 200,
height: 200,
child: Stack(
alignment: Alignment.center,
children: [
// 背景圆环
SizedBox(
width: 180,
height: 180,
child: CircularProgressIndicator(
value: 1.0,
strokeWidth: 12,
backgroundColor: Colors.transparent,
valueColor: AlwaysStoppedAnimation<Color>(
Colors.grey.shade200,
),
),
),
// 进度圆环
SizedBox(
width: 180,
height: 180,
child: CircularProgressIndicator(
value: level / 100,
strokeWidth: 12,
backgroundColor: Colors.transparent,
valueColor: AlwaysStoppedAnimation<Color>(
getBatteryLevelColor(level),
),
strokeCap: StrokeCap.round,
),
),
// 中心文字
Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'$level%',
style: TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
color: getBatteryLevelColor(level),
),
),
if (isCharging)
Row(
mainAxisSize: MainAxisSize.min,
children: [
const Text('⚡', style: TextStyle(fontSize: 16)),
const SizedBox(width: 4),
Text(
'充电中',
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade600,
),
),
],
)
else
Text(
getRemainingText(),
style: TextStyle(
fontSize: 14,
color: Colors.grey.shade600,
),
),
],
),
],
),
),
],
);
}
String getRemainingText() {
if (level > 80) return '电量充足';
if (level > 60) return '电量良好';
if (level > 30) return '电量偏低';
if (level > 15) return '电量不足';
return '请及时充电';
}
}
组件设计遵循单一职责原则,每个组件只负责一个功能点。圆环组件通过 CustomPaint 或 CircularProgressIndicator 实现视觉效果,内部状态由父组件通过参数传入,实现了良好的解耦。
3.5 页面层实现
页面是应用视图的顶层容器,负责组装各个组件并管理页面级状态。
dart
// lib/pages/battery_page.dart
import 'package:flutter/material.dart';
import '../model/battery_model.dart';
import '../service/battery_service.dart';
import '../utils/battery_utils.dart';
import '../components/battery_circle_progress.dart';
import '../components/battery_indicators.dart';
import '../components/battery_history.dart';
import '../components/process_manager.dart';
import '../components/common_components.dart';
// 电池页面主组件
class BatteryPage extends StatefulWidget {
const BatteryPage({super.key});
@override
State<BatteryPage> createState() => _BatteryPageState();
}
class _BatteryPageState extends State<BatteryPage> {
final BatteryService _batteryService = BatteryService();
int _currentTab = 0;
bool _isLoading = true;
bool _powerSavingEnabled = false;
bool _backgroundRestricted = false;
BatteryInfo? _batteryInfo;
List<PowerConsumptionInfo> _consumptionList = [];
List<HistoryData> _historyData = [];
List<ProcessItem> _processes = [];
bool _showOptimizeDialog = false;
String _selectedAppName = '';
String _selectedPackageName = '';
double _averageUsage = 35.0;
double _screenOnTime = 4.5;
double _drainRate = 8.2;
String _lastFullCharge = '今天 09:30';
@override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
setState(() => _isLoading = true);
try {
final results = await Future.wait([
_batteryService.getBatteryInfo(),
_batteryService.getPowerConsumptionData(),
_batteryService.getHistoryData(),
_batteryService.getBackgroundProcesses(),
]);
setState(() {
_batteryInfo = results[0] as BatteryInfo;
_consumptionList = results[1] as List<PowerConsumptionInfo>;
_historyData = results[2] as List<HistoryData>;
_processes = results[3] as List<ProcessItem>;
_isLoading = false;
});
} catch (e) {
setState(() => _isLoading = false);
debugPrint('Error loading battery data: $e');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F7FA),
body: Column(
children: [
_buildHeader(),
_buildTabBar(),
Expanded(child: _buildContent()),
],
),
);
}
Widget _buildHeader() {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
color: Colors.white,
child: Row(
children: [
const Text(
'电池优化',
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Color(0xFF333333),
),
),
const Spacer(),
Text(
_getStatusText(),
style: TextStyle(
fontSize: 13,
color: _isCharging() ? const Color(0xFF4CAF50) : const Color(0xFF666666),
),
),
],
),
);
}
Widget _buildTabBar() {
final tabs = ['概览', '耗电排行', '使用历史', '设置'];
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
color: Colors.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(tabs.length, (index) {
return GestureDetector(
onTap: () => setState(() => _currentTab = index),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: _currentTab == index
? const Color(0xFF2196F3).withOpacity(0.1)
: Colors.transparent,
borderRadius: BorderRadius.circular(8),
),
child: Text(
tabs[index],
style: TextStyle(
fontSize: 15,
color: _currentTab == index
? const Color(0xFF2196F3)
: const Color(0xFF999999),
fontWeight: _currentTab == index
? FontWeight.bold
: FontWeight.normal,
),
),
),
);
}),
),
);
}
Widget _buildContent() {
if (_isLoading) {
return const Center(child: CircularProgressIndicator());
}
switch (_currentTab) {
case 0:
return _buildOverviewTab();
case 1:
return _buildPowerTab();
case 2:
return _buildHistoryTab();
case 3:
return _buildSettingsTab();
default:
return _buildOverviewTab();
}
}
Widget _buildOverviewTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
children: [
BatteryCircleProgress(
level: _batteryInfo?.level ?? 0,
isCharging: _isCharging(),
),
const SizedBox(height: 20),
HealthStatusCard(
health: _batteryInfo?.health ?? 'unknown',
temperature: _batteryInfo?.temperature ?? 0,
voltage: _batteryInfo?.voltage ?? 0,
),
],
),
);
}
Widget _buildPowerTab() {
return Stack(
children: [
SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SectionHeader(title: '耗电应用排行', icon: '📊'),
..._consumptionList.asMap().entries.map((entry) {
return _buildPowerItem(entry.value, entry.key);
}),
],
),
),
if (_showOptimizeDialog)
_buildOptimizeDialog(),
],
);
}
Widget _buildHistoryTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
children: [
BatteryHistoryChart(dataArray: _historyData),
const SizedBox(height: 20),
UsageStatsCard(
averageUsage: _averageUsage,
screenOnTime: _screenOnTime,
drainRate: _drainRate,
lastFullCharge: _lastFullCharge,
),
],
),
);
}
Widget _buildSettingsTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SectionHeader(title: '省电模式', icon: '⚡'),
ToggleCard(
title: '省电模式',
subtitle: '降低性能以延长电池续航',
icon: '🔋',
isOn: _powerSavingEnabled,
onToggle: (value) => setState(() => _powerSavingEnabled = value),
),
],
),
);
}
bool _isCharging() {
final status = _batteryInfo?.chargingStatus;
return status == 'charging' || status == 'full';
}
String _getStatusText() {
if (_isCharging()) {
return _batteryInfo?.chargingStatus == 'full' ? '已充满' : '充电中';
}
return '未充电';
}
}
页面组件采用了 StatefulWidget,以便管理动态变化的状态。代码中使用了 Future.wait 并行加载多个数据源,提升了数据加载效率。
四、代码仓库
本项目的完整代码已托管至 AtomGit 平台,欢迎各位开发者 Star、Fork 并提出宝贵意见。
仓库地址:https://atomgit.com/maaath/battery-optimization-flutter
五、截图运行板块
以下是应用在鸿蒙设备上的实际运行截图,验证了 Flutter for OpenHarmony 跨平台开发的可行性。
5.1 应用主界面(概览页)
应用启动后显示电池概览页面,展示了电池电量圆环、温度指示器和充电时间预估。界面流畅度良好,与原生应用无明显差异。

5.2 耗电排行页面
耗电应用排行页面以列表形式展示各应用的功耗情况,按功耗从高到低排序,直观清晰。

5.3 使用历史页面
电池历史曲线图以折线形式展示过去24小时的电量变化,用户可以清楚地了解电池使用规律。

5.4 设置页面
省电模式和后台管理等设置功能正常可用,开关切换响应迅速。

以上截图均来自实际鸿蒙设备运行效果,证明 Flutter for OpenHarmony 已具备实际应用开发的能力。
六、总结与展望
本文通过一个完整的电池优化应用案例,展示了 Flutter for OpenHarmony 跨平台开发的核心流程和关键技术点。总结起来,有以下几点经验分享:
架构设计层面,采用分层架构将 UI、业务和数据分离,是保证代码可维护性的关键。无论是 Flutter 还是原生开发,良好的架构设计都能大大降低后期维护成本。
跨平台适配层面,Flutter 的平台通道机制为调用系统原生能力提供了标准方案。开发者应该充分利用这一特性,在保证跨平台能力的同时,发挥各平台的独特优势。
性能优化层面 ,Flutter 渲染引擎的高效性保证了应用的流畅度。但在实际开发中,仍需注意避免不必要的重绘,合理使用 const 构造函数和 RepaintBoundary。
生态系统层面,Flutter for OpenHarmony 仍在快速发展中,部分第三方库可能尚未完全适配。建议开发者在选择依赖时,优先选择官方推荐的方案,或考虑自己实现相关功能。
展望未来,随着 OpenHarmony 生态的不断完善和 Flutter for OpenHarmony 的持续优化,跨平台开发将在鸿蒙生态中发挥越来越重要的作用。希望本文能为广大开发者提供一些参考,共同推动国产操作系统的繁荣发展。
参考资料:
- Flutter 官方文档:https://flutter.dev/docs
- OpenHarmony 开发者文档:https://developer.harmonyos.com
- AtomGit 代码托管平台:https://atomgit.com