进阶实战 Flutter for OpenHarmony:battery_plus 第三方库实战 - 电池状态监控

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net


🎯 一、组件概述与应用场景

📋 1.1 battery_plus 简介

在移动应用开发中,电池状态是一个重要的系统信息。battery_plus 是 Flutter 社区官方维护的电池信息获取插件,提供了跨平台的电池状态监控能力。开发者可以通过该插件获取设备电池电量、充电状态,以及监听电池状态变化,从而实现根据电池状态优化应用行为的功能。

核心特性:

特性 说明
🌐 跨平台支持 支持 Android、iOS、macOS、Web、Linux、Windows、OpenHarmony
📊 电量获取 获取当前电池电量百分比(0-100)
🔌 状态获取 获取电池状态(充电中、放电中、满电、未知)
📡 状态监听 实时监听电池状态变化
⚡ 节能模式 检测设备是否处于节能模式
🔒 单例模式 使用单例模式确保资源高效利用

💡 1.2 实际应用场景

低电量模式优化:当电量低于阈值时,自动降低应用性能以节省电量。

后台任务调度:根据电池状态决定是否执行后台同步任务。

游戏性能调节:在低电量时降低画质以保证续航。

下载任务管理:在充电时自动开始大文件下载。

省电提醒:当电量低于阈值时提醒用户充电。

🏗️ 1.3 系统架构设计

复制代码
┌─────────────────────────────────────────────────────────┐
│                    UI 展示层                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ 电量显示组件 │  │ 状态监控面板 │  │ 省电建议页面 │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                    业务逻辑层                            │
│  ┌─────────────────────────────────────────────────┐   │
│  │          BatteryService 电池服务                 │   │
│  │  • getLevel()  • getState()  • isSaveMode()    │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
                          │
                          ▼
┌─────────────────────────────────────────────────────────┐
│                    平台适配层                            │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐     │
│  │ Android     │  │ iOS         │  │ OpenHarmony │     │
│  └─────────────┘  └─────────────┘  └─────────────┘     │
└─────────────────────────────────────────────────────────┘

📦 二、项目配置与依赖安装

🔧 2.1 添加依赖配置

打开项目根目录下的 pubspec.yaml 文件,添加以下配置:

yaml 复制代码
dependencies:
  flutter:
    sdk: flutter

  # battery_plus - 电池状态监控插件
  battery_plus:
    git:
      url: https://atomgit.com/openharmony-sig/flutter_plus_plugins.git
      path: packages/battery_plus/battery_plus

配置说明:

  • 使用 git 方式引用开源鸿蒙适配的仓库
  • battery_plus 是 Flutter Community 官方维护的插件
  • 完整支持 OpenHarmony 平台所有功能

⚠️ 重要提示:对于 OpenHarmony 平台,必须使用 git 方式引用适配版本。

📥 2.2 下载依赖

配置完成后,在项目根目录执行以下命令:

bash 复制代码
flutter pub get

🔐 2.3 权限配置

在 OpenHarmony 平台上,使用 battery_plus 获取电池信息不需要额外配置权限。该插件使用系统公开的电池信息接口,无需申请特殊权限。

📱 2.4 支持的功能

功能 说明 OpenHarmony 支持
batteryLevel 获取电池等级 ✅ yes
isInBatterySaveMode 判断是否处于节能模式 ✅ yes
batteryState 获取电池状态 ✅ yes
onBatteryStateChanged 监听电池状态改变 ✅ yes

🔋 2.5 电池状态枚举

状态 说明
full 电池处于满电状态
charging 电池处于充电状态
discharging 电池处于耗电状态
unknown 电池处于未知状态

🔧 三、核心功能详解

🎯 3.1 创建 Battery 实例

dart 复制代码
import 'package:battery_plus/battery_plus.dart';

final Battery _battery = Battery();

📊 3.2 获取电池电量

dart 复制代码
Future<int> getBatteryLevel() async {
  final batteryLevel = await _battery.batteryLevel;
  return batteryLevel; // 返回 0-100 的整数
}

🔌 3.3 获取电池状态

dart 复制代码
Future<BatteryState> getBatteryState() async {
  final state = await _battery.batteryState;
  return state; // 返回 BatteryState 枚举
}

⚡ 3.4 检测节能模式

dart 复制代码
Future<bool> isInBatterySaveMode() async {
  final isInSaveMode = await _battery.isInBatterySaveMode;
  return isInSaveMode; // 返回 true/false
}

📡 3.5 监听电池状态变化

dart 复制代码
StreamSubscription<BatteryState>? _subscription;

void startListening() {
  _subscription = _battery.onBatteryStateChanged.listen((BatteryState state) {
    print('电池状态变化: $state');
  });
}

void stopListening() {
  _subscription?.cancel();
}

📝 四、完整示例代码

下面是一个完整的智能电池状态监控系统示例:

dart 复制代码
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:battery_plus/battery_plus.dart';

void main() {
  runApp(const BatteryMonitorApp());
}

class BatteryMonitorApp extends StatelessWidget {
  const BatteryMonitorApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '智能电池状态监控系统',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
        useMaterial3: true,
      ),
      home: const MainPage(),
    );
  }
}

class MainPage extends StatefulWidget {
  const MainPage({super.key});

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _currentIndex = 0;

  final List<Widget> _pages = [
    const BatteryStatusPage(),
    const PowerSavingPage(),
    const BatteryHistoryPage(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _pages[_currentIndex],
      bottomNavigationBar: NavigationBar(
        selectedIndex: _currentIndex,
        onDestinationSelected: (index) {
          setState(() => _currentIndex = index);
        },
        destinations: const [
          NavigationDestination(icon: Icon(Icons.battery_std), label: '电池状态'),
          NavigationDestination(icon: Icon(Icons.power), label: '省电模式'),
          NavigationDestination(icon: Icon(Icons.history), label: '历史记录'),
        ],
      ),
    );
  }
}

// ============ 电池状态页面 ============

class BatteryStatusPage extends StatefulWidget {
  const BatteryStatusPage({super.key});

  @override
  State<BatteryStatusPage> createState() => _BatteryStatusPageState();
}

class _BatteryStatusPageState extends State<BatteryStatusPage> {
  final Battery _battery = Battery();

  int _batteryLevel = 0;
  BatteryState _batteryState = BatteryState.unknown;
  bool _isInBatterySaveMode = false;
  StreamSubscription<BatteryState>? _subscription;

  @override
  void initState() {
    super.initState();
    _initBatteryInfo();
    _listenBatteryState();
  }

  Future<void> _initBatteryInfo() async {
    final level = await _battery.batteryLevel;
    final state = await _battery.batteryState;
    final saveMode = await _battery.isInBatterySaveMode;

    setState(() {
      _batteryLevel = level;
      _batteryState = state;
      _isInBatterySaveMode = saveMode;
    });
  }

  void _listenBatteryState() {
    _subscription = _battery.onBatteryStateChanged.listen((state) {
      _initBatteryInfo();
    });
  }

  String _getStateText(BatteryState state) {
    switch (state) {
      case BatteryState.full:
        return '满电';
      case BatteryState.charging:
        return '充电中';
      case BatteryState.discharging:
        return '放电中';
      case BatteryState.unknown:
        return '未知';
    }
  }

  IconData _getBatteryIcon(BatteryState state, int level) {
    if (state == BatteryState.charging) {
      return Icons.battery_charging_full;
    } else if (state == BatteryState.full) {
      return Icons.battery_full;
    } else if (level <= 20) {
      return Icons.battery_alert;
    } else if (level <= 50) {
      return Icons.battery_4_bar;
    } else {
      return Icons.battery_6_bar;
    }
  }

  Color _getBatteryColor(int level) {
    if (level <= 20) {
      return Colors.red;
    } else if (level <= 50) {
      return Colors.orange;
    } else {
      return Colors.green;
    }
  }

  @override
  void dispose() {
    _subscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('电池状态'),
        centerTitle: true,
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: _initBatteryInfo,
          ),
        ],
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            _buildBatteryCard(),
            const SizedBox(height: 24),
            _buildStatusCard(),
            const SizedBox(height: 24),
            _buildTipsCard(),
          ],
        ),
      ),
    );
  }

  Widget _buildBatteryCard() {
    return Container(
      padding: const EdgeInsets.all(32),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: [_getBatteryColor(_batteryLevel).withOpacity(0.8), _getBatteryColor(_batteryLevel)],
        ),
        borderRadius: BorderRadius.circular(24),
      ),
      child: Column(
        children: [
          Icon(
            _getBatteryIcon(_batteryState, _batteryLevel),
            size: 80,
            color: Colors.white,
          ),
          const SizedBox(height: 16),
          Text(
            '$_batteryLevel%',
            style: const TextStyle(
              fontSize: 56,
              fontWeight: FontWeight.bold,
              color: Colors.white,
            ),
          ),
          const SizedBox(height: 8),
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
            decoration: BoxDecoration(
              color: Colors.white.withOpacity(0.2),
              borderRadius: BorderRadius.circular(20),
            ),
            child: Text(
              _getStateText(_batteryState),
              style: const TextStyle(color: Colors.white, fontSize: 16),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildStatusCard() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            _buildStatusItem(
              Icons.power,
              '节能模式',
              _isInBatterySaveMode ? '已开启' : '未开启',
              _isInBatterySaveMode ? Colors.orange : Colors.grey,
            ),
            const Divider(),
            _buildStatusItem(
              _batteryState == BatteryState.charging ? Icons.bolt : Icons.bolt_outlined,
              '充电状态',
              _getStateText(_batteryState),
              _batteryState == BatteryState.charging ? Colors.green : Colors.grey,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildStatusItem(IconData icon, String title, String value, Color color) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Row(
        children: [
          Icon(icon, color: color),
          const SizedBox(width: 16),
          Expanded(child: Text(title)),
          Text(value, style: TextStyle(color: color, fontWeight: FontWeight.w500)),
        ],
      ),
    );
  }

  Widget _buildTipsCard() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('省电建议', style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 12),
            if (_batteryLevel <= 20) ...[
              _buildTipItem('电量较低,建议尽快充电', Colors.red),
            ],
            if (_batteryLevel <= 50 && _batteryLevel > 20) ...[
              _buildTipItem('电量中等,可开启节能模式延长续航', Colors.orange),
            ],
            if (_isInBatterySaveMode) ...[
              _buildTipItem('节能模式已开启,部分功能可能受限', Colors.orange),
            ],
            if (_batteryLevel > 50 && !_isInBatterySaveMode) ...[
              _buildTipItem('电量充足,可正常使用', Colors.green),
            ],
          ],
        ),
      ),
    );
  }

  Widget _buildTipItem(String text, Color color) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        children: [
          Container(
            width: 8,
            height: 8,
            decoration: BoxDecoration(
              color: color,
              shape: BoxShape.circle,
            ),
          ),
          const SizedBox(width: 12),
          Expanded(child: Text(text, style: TextStyle(color: color))),
        ],
      ),
    );
  }
}

// ============ 省电模式页面 ============

class PowerSavingPage extends StatelessWidget {
  const PowerSavingPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('省电模式'),
        centerTitle: true,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            _buildInfoCard(),
            const SizedBox(height: 24),
            _buildTipsList(),
          ],
        ),
      ),
    );
  }

  Widget _buildInfoCard() {
    return Container(
      padding: const EdgeInsets.all(24),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          colors: [Colors.green.shade400, Colors.green.shade600],
        ),
        borderRadius: BorderRadius.circular(16),
      ),
      child: const Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Icon(Icons.power, color: Colors.white),
              SizedBox(width: 8),
              Text(
                '省电模式说明',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ],
          ),
          SizedBox(height: 12),
          Text(
            '开启省电模式后,系统会限制后台活动、降低性能以延长电池续航时间。',
            style: TextStyle(color: Colors.white70, height: 1.5),
          ),
        ],
      ),
    );
  }

  Widget _buildTipsList() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('省电技巧', style: TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 16),
            _buildTipItem('降低屏幕亮度'),
            _buildTipItem('关闭不必要的后台应用'),
            _buildTipItem('关闭蓝牙和定位服务'),
            _buildTipItem('使用深色主题'),
            _buildTipItem('减少通知推送'),
          ],
        ),
      ),
    );
  }

  Widget _buildTipItem(String text) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Row(
        children: [
          Icon(Icons.check_circle, color: Colors.green.shade400, size: 20),
          const SizedBox(width: 12),
          Text(text),
        ],
      ),
    );
  }
}

// ============ 历史记录页面 ============

class BatteryHistoryPage extends StatefulWidget {
  const BatteryHistoryPage({super.key});

  @override
  State<BatteryHistoryPage> createState() => _BatteryHistoryPageState();
}

class _BatteryHistoryPageState extends State<BatteryHistoryPage> {
  final Battery _battery = Battery();
  final List<BatteryRecord> _records = [];
  StreamSubscription<BatteryState>? _subscription;

  @override
  void initState() {
    super.initState();
    _addRecord();
    _listenBatteryState();
  }

  void _addRecord() async {
    final level = await _battery.batteryLevel;
    final state = await _battery.batteryState;
    setState(() {
      _records.insert(0, BatteryRecord(
        level: level,
        state: state,
        time: DateTime.now(),
      ));
      if (_records.length > 20) {
        _records.removeLast();
      }
    });
  }

  void _listenBatteryState() {
    _subscription = _battery.onBatteryStateChanged.listen((_) {
      _addRecord();
    });
  }

  @override
  void dispose() {
    _subscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('历史记录'),
        centerTitle: true,
      ),
      body: _records.isEmpty
          ? const Center(child: Text('暂无记录'))
          : ListView.builder(
              padding: const EdgeInsets.all(16),
              itemCount: _records.length,
              itemBuilder: (context, index) {
                final record = _records[index];
                return _buildRecordCard(record);
              },
            ),
    );
  }

  Widget _buildRecordCard(BatteryRecord record) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            Container(
              width: 48,
              height: 48,
              decoration: BoxDecoration(
                color: _getColor(record.level).withOpacity(0.1),
                borderRadius: BorderRadius.circular(12),
              ),
              child: Center(
                child: Text(
                  '${record.level}%',
                  style: TextStyle(
                    color: _getColor(record.level),
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ),
            ),
            const SizedBox(width: 16),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    _getStateText(record.state),
                    style: const TextStyle(fontWeight: FontWeight.w500),
                  ),
                  Text(
                    _formatTime(record.time),
                    style: TextStyle(color: Colors.grey.shade600, fontSize: 12),
                  ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Color _getColor(int level) {
    if (level <= 20) return Colors.red;
    if (level <= 50) return Colors.orange;
    return Colors.green;
  }

  String _getStateText(BatteryState state) {
    switch (state) {
      case BatteryState.full:
        return '满电';
      case BatteryState.charging:
        return '充电中';
      case BatteryState.discharging:
        return '放电中';
      case BatteryState.unknown:
        return '未知';
    }
  }

  String _formatTime(DateTime time) {
    return '${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}:${time.second.toString().padLeft(2, '0')}';
  }
}

class BatteryRecord {
  final int level;
  final BatteryState state;
  final DateTime time;

  BatteryRecord({
    required this.level,
    required this.state,
    required this.time,
  });
}

🏆 五、最佳实践与注意事项

⚠️ 5.1 单例使用

Battery 类设计为单例模式,建议在应用中只创建一个实例:

dart 复制代码
class BatteryService {
  static final Battery _instance = Battery();
  static Battery get instance => _instance;
}

📡 5.2 及时取消订阅

监听电池状态变化时,务必在组件销毁时取消订阅:

dart 复制代码
@override
void dispose() {
  _subscription?.cancel();
  super.dispose();
}

🔋 5.3 结合其他信息优化体验

将电池信息与网络状态、应用状态等结合,实现更智能的资源管理:

dart 复制代码
Future<bool> shouldPerformSync() async {
  final level = await _battery.batteryLevel;
  final state = await _battery.batteryState;
  final isInSaveMode = await _battery.isInBatterySaveMode;
  
  return level > 30 && state != BatteryState.discharging && !isInSaveMode;
}

📱 5.4 常见问题处理

状态返回 unknown:某些设备或模拟器可能返回 unknown,建议进行容错处理。

监听不触发:确保在正确的生命周期中启动监听,并在 dispose 中取消。


📌 六、总结

本文通过一个完整的智能电池状态监控系统案例,深入讲解了 battery_plus 插件的使用方法与最佳实践:

电量获取:掌握获取电池电量的基本方法。

状态监控:实现电池状态的实时监听。

节能模式:检测设备是否处于节能模式。

智能优化:根据电池状态优化应用行为。

掌握这些技巧,你就能构建出专业级的电池状态监控功能,提升应用的续航体验。


参考资料

相关推荐
lili-felicity2 小时前
进阶实战 Flutter for OpenHarmony:image_gallery_saver 第三方库实战 - 图片保存
flutter
lili-felicity3 小时前
进阶实战 Flutter for OpenHarmony:app_settings 第三方库实战 - 系统设置跳转
flutter
恋猫de小郭17 小时前
iOS + AI ,国外一个叫 Rork Max 的项目打算替换掉 Xcode
android·前端·flutter
左手厨刀右手茼蒿19 小时前
Flutter for OpenHarmony:dart_console 打造炫酷命令行界面,绘制表格、控制光标与进度条(CLI 交互库) 深度解析与鸿蒙适配指南
flutter·交互·harmonyos·绘制
加农炮手Jinx19 小时前
Flutter for OpenHarmony 实战:疯狂头像 App(三)— 复合动画与交互反馈 — 让 UI 跃动起来
flutter·ui·交互·harmonyos·鸿蒙
王码码203519 小时前
lutter for OpenHarmony 实战之基础组件:第六十二篇 SystemChannels — 探秘 Flutter 与系统交互的捷径
flutter·microsoft·交互·harmonyos
RaidenLiu21 小时前
别再手写 MethodChannel 了:Flutter Pigeon 工程级实践与架构设计
前端·flutter·前端框架
Bowen_J1 天前
HarmonyOS 主流跨平台开发框架对比: ArkUI、Flutter、React Native、KMP、UniApp
flutter·react native·harmonyos
九狼JIULANG1 天前
Flutter SSE 流式响应用 Dio 实现 OpenAI 兼容接口的逐 Token 输出
flutter