battery_ffi 0.0.1
battery_ffi: ^0.0.1 copied to clipboard
A comprehensive Flutter plugin for real-time battery monitoring across platforms using FFI/JNI for optimal performance.
import 'package:flutter/material.dart';
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:battery_ffi/battery_ffi.dart';
import 'widgets/streamable_battery_section.dart';
import 'widgets/non_streamable_battery_section.dart';
import 'widgets/wake_lock_control_section.dart';
void main() async {
// Initialize the battery monitoring singleton
await BatteryFFI.instance.initialize();
runApp(const BatteryMonitorApp());
}
class BatteryMonitorApp extends StatelessWidget {
const BatteryMonitorApp({super.key});
@override
Widget build(BuildContext context) {
return ShadApp(
title: 'Battery Monitor',
home: const BatteryMonitorHomePage(),
);
}
}
class BatteryMonitorHomePage extends StatefulWidget {
const BatteryMonitorHomePage({super.key});
@override
State<BatteryMonitorHomePage> createState() => _BatteryMonitorHomePageState();
}
class _BatteryMonitorHomePageState extends State<BatteryMonitorHomePage>
with WidgetsBindingObserver {
final BatteryFFI _battery = BatteryFFI.instance;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
// Dispose of battery monitoring resources
_battery.dispose();
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
// Dispose resources when app is detached/permanently closed
if (state == AppLifecycleState.detached) {
_battery.dispose();
}
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(title: const Text('Battery Monitor')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header Card
ShadCard(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.battery_full,
size: 48,
color: Colors.green,
),
const SizedBox(width: 16),
Text(
'${_battery.batteryLevel}%',
style: Theme.of(context).textTheme.displayLarge
?.copyWith(
color: Colors.green,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 16),
ShadProgress(
value: _battery.batteryLevel / 100,
minHeight: 8,
),
],
),
),
),
const SizedBox(height: 24),
// Real-time Streamable Section
Text(
'🔄 Real-time Monitoring (Streamable)',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
const SizedBox(height: 8),
Text(
'These values update automatically when battery conditions change',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Colors.blue.shade700),
),
const SizedBox(height: 16),
StreamableBatterySection(battery: _battery),
const SizedBox(height: 32),
// Current Status Section
Text(
'📊 Current Status (Non-streamable)',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.orange,
),
),
const SizedBox(height: 8),
Text(
'These are the current values at the time of access',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Colors.orange.shade700),
),
const SizedBox(height: 16),
NonStreamableBatterySection(battery: _battery),
const SizedBox(height: 32),
// Wake Lock Control Section (Android only) - MOVED UP FOR PROMINENCE
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.purple.shade50,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.purple.shade200),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.lock, color: Colors.purple.shade700),
const SizedBox(width: 8),
Expanded(
child: Text(
'🔋 Background Monitoring (Android Only)',
style: Theme.of(context).textTheme.titleLarge
?.copyWith(
fontWeight: FontWeight.bold,
color: Colors.purple.shade800,
),
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 8),
Text(
'Enable wake locks to receive battery updates even when the app is in background or screen is off.',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.purple.shade700,
),
),
const SizedBox(height: 16),
WakeLockControlSection(battery: _battery),
],
),
),
const SizedBox(height: 24),
// Technical Details
ShadCard(
backgroundColor: ShadTheme.of(context).colorScheme.muted,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Technical Details',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
'This app demonstrates JNI (Java Native Interface) integration with Flutter. '
'The battery information is retrieved directly from Android\'s system APIs using '
'compiled Java code that communicates with Dart through FFI bindings generated by JniGen.\n\n'
'🔄 Streamable properties provide real-time updates via BroadcastReceiver callbacks.\n'
'📊 Non-streamable properties return current values synchronously.\n'
'🔋 Wake locks enable continuous background monitoring (Android only).',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: ShadTheme.of(
context,
).colorScheme.mutedForeground,
),
),
],
),
),
),
],
),
),
),
);
}
}