diff --git a/android/app/build.gradle.kts.txt b/android/app/build.gradle.kts.txt
new file mode 100644
index 0000000..cdca13c
--- /dev/null
+++ b/android/app/build.gradle.kts.txt
@@ -0,0 +1,73 @@
+plugins {
+ id("com.android.application")
+ id("kotlin-android")
+ id("dev.flutter.flutter-gradle-plugin")
+}
+
+android {
+ namespace = "com.lxh.battery_health"
+ compileSdk = 34
+ ndkVersion = flutter.ndkVersion
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+
+ defaultConfig {
+ applicationId = "com.lxh.battery_health"
+ minSdk = flutter.minSdkVersion
+ targetSdk = 34
+ versionCode = flutter.versionCode
+ versionName = flutter.versionName
+ multiDexEnabled = true
+ }
+
+ signingConfigs {
+ // 如果没有正式签名,可以用 debug 签名代替(测试用)
+ // 正式发布时请替换为自己的密钥
+ getByName("debug") {
+ // debug 签名已经存在,无需额外配置
+ }
+ create("release") {
+ // 如果有正式签名,在这里配置
+ // keyAlias = "..."
+ // keyPassword = "..."
+ // storeFile = file("...")
+ // storePassword = "..."
+ }
+ }
+
+ buildTypes {
+ debug {
+ // 🟢 关键:debug 版本包名加 .dev 后缀
+ applicationIdSuffix = ".dev"
+ signingConfig = signingConfigs.getByName("debug")
+ isDebuggable = true
+ isMinifyEnabled = false
+ isShrinkResources = false
+ }
+ release {
+ // release 版本不加后缀,保持原包名
+ signingConfig = signingConfigs.getByName("debug") // 若没有正式签名,先用 debug 签名
+ isMinifyEnabled = true
+ isShrinkResources = true
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+}
+
+flutter {
+ source = "../.."
+}
+
+dependencies {
+ // 无需额外添加 Activity KTX,因为已改用 startActivityForResult
+}
diff --git a/android/app/src/main/AndroidManifest.xml.txt b/android/app/src/main/AndroidManifest.xml.txt
new file mode 100644
index 0000000..c76ece7
--- /dev/null
+++ b/android/app/src/main/AndroidManifest.xml.txt
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/logic/capacity_extractor.dart b/lib/logic/capacity_extractor.dart
new file mode 100644
index 0000000..c53dcfe
--- /dev/null
+++ b/lib/logic/capacity_extractor.dart
@@ -0,0 +1,41 @@
+/// 容量提取工具
+/// 支持两种日志格式:
+/// 1. learned_cap(21 系列):单位 µAh,除以 1000 得到 mAh
+/// 2. remaining_cap(20 系列):单位 mAh,直接使用(但 21 系列的 remaining_cap 也是 µAh,需判断)
+class CapacityExtractor {
+ static int? extractCapacity(List lines) {
+ final validLines = lines.where((line) => line.contains('tbat=')).toList();
+ if (validLines.isEmpty) return null;
+
+ // 模式一:learned_cap(21 系列)
+ final learnedReg = RegExp(r'learned_cap=(\d+)');
+ for (String line in validLines.reversed) {
+ final match = learnedReg.firstMatch(line);
+ if (match != null) {
+ return int.parse(match.group(1)!) ~/ 1000;
+ }
+ }
+
+ // 模式二:remaining_cap 最大值
+ final remainingReg = RegExp(r'remaining_cap=(\d+)');
+ int? maxRemaining;
+ for (String line in validLines) {
+ final match = remainingReg.firstMatch(line);
+ if (match != null) {
+ final value = int.parse(match.group(1)!);
+ if (maxRemaining == null || value > maxRemaining) {
+ maxRemaining = value;
+ }
+ }
+ }
+ if (maxRemaining == null) return null;
+
+ // 🟢 判断单位:如果数值大于 100000(约 100 mAh),则认为是 µAh,需除以 1000
+ // 否则认为是 mAh,直接使用
+ if (maxRemaining > 100000) {
+ return maxRemaining ~/ 1000;
+ } else {
+ return maxRemaining;
+ }
+ }
+}
diff --git a/lib/logic/charge_parser.dart b/lib/logic/charge_parser.dart
new file mode 100644
index 0000000..7e5c2ad
--- /dev/null
+++ b/lib/logic/charge_parser.dart
@@ -0,0 +1,139 @@
+import 'dart:developer' as dev;
+import '../utils/time_utils.dart';
+
+/// 充电日志解析器
+class ChargeParser {
+ /// 解析充电数据,返回解析结果
+ static ParseResult parse(List lines, DateTime? chargingStartTime) {
+ dev.log('[ChargeParser] 开始解析,共 ${lines.length} 行', name: 'BatteryHealth');
+
+ final validLines = _collectValidLines(lines, chargingStartTime);
+ if (validLines.isEmpty) {
+ dev.log('[ChargeParser] 无有效时间窗口内的数据行', name: 'BatteryHealth');
+ return ParseResult.empty();
+ }
+
+ // 按时间戳从新到旧排序
+ validLines.sort((a, b) => b['timestamp'].compareTo(a['timestamp']));
+ final latest = validLines.first;
+ final latestLine = latest['line'] as String;
+ final latestType = latest['type'] as String;
+
+ dev.log(
+ '[ChargeParser] 最新有效数据: $latestType, 时间: ${latest['timestamp']}',
+ name: 'BatteryHealth',
+ );
+
+ if (latestType == 'wls') {
+ return _parseWireless(latestLine);
+ } else {
+ return _parseWired(latestLine);
+ }
+ }
+
+ static List