Browse Source

优化ota升级

weicu
fdp 1 year ago
parent
commit
756c1001be
  1. 13
      lib/data/services/ble_manager.dart
  2. 52
      lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart
  3. 175
      lib/modules/ota_upgrade/views/ota_upgrade_view.dart
  4. BIN
      local_plugins/opus/.gradle/buildOutputCleanup/buildOutputCleanup.lock
  5. 2
      local_plugins/opus/.gradle/buildOutputCleanup/cache.properties
  6. 26
      local_plugins/ota/android/src/main/kotlin/com/example/ota/DeviceConnection.kt
  7. 9
      local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt
  8. 3
      local_plugins/ota/android/src/main/kotlin/com/example/ota/tool/ota/ble/BleManager.java
  9. 94
      local_plugins/ota/lib/ota.dart
  10. 1
      local_plugins/ota/pubspec.yaml

13
lib/data/services/ble_manager.dart

@ -179,6 +179,19 @@ class BleManager extends GetxService {
state == BleConnectionState.error) { state == BleConnectionState.error) {
Logger.info('BLE设备已断开或发生错误'); Logger.info('BLE设备已断开或发生错误');
_isConnected.value = false; _isConnected.value = false;
// 更新设备信息
_updateDeviceInfoIfNeeded(
batteryLevel: 0,
leftEarBattery: 0,
rightEarBattery: 0,
caseBattery: 0,
leftEarCharging: false,
rightEarCharging: false,
caseCharging: false,
firmwareVersion: '',
firmwareProductId: '',
firmwareProductColor: '',
);
} }
} }

52
lib/modules/ota_upgrade/controllers/ota_upgrade_controller.dart

@ -40,7 +40,7 @@ class OtaUpgradeController extends GetxController {
final isUpdateAvailable = true.obs; final isUpdateAvailable = true.obs;
// 当前升级进度,范围为 0.0 到 1.0 // 当前升级进度,范围为 0.0 到 1.0
final RxDouble progress = 0.0.obs; // final RxDouble progress = 0.0.obs;
// OTA 单例实例,用于处理升级相关逻辑 // OTA 单例实例,用于处理升级相关逻辑
final jlota = Ota.instance; final jlota = Ota.instance;
@ -52,7 +52,12 @@ class OtaUpgradeController extends GetxController {
final _bleManager = Get.find<BleManager>(); final _bleManager = Get.find<BleManager>();
final maxRetryAttempts = 3; // 最大重试次数 final maxRetryAttempts = 3; // 最大重试次数
int currentRetryCount = 0; int currentRetryCount = 0;
final RxBool isFetchingDeviceInfo = true.obs; final RxBool isFetchingDeviceInfo = true.obs;
final RxDouble progress = 0.0.obs; // 控制器自己的可观察属性
final RxInt type = OtaEvent.NOT_STARTED.obs;
final RxBool isUpgrade = false.obs;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
@ -62,6 +67,7 @@ class OtaUpgradeController extends GetxController {
@override @override
void onClose() { void onClose() {
jlota.onOtaClose(); jlota.onOtaClose();
isUpgrade.value = false;
super.onClose(); super.onClose();
} }
@ -109,6 +115,7 @@ class OtaUpgradeController extends GetxController {
} }
Future<void> _getCurrentVersion() async { Future<void> _getCurrentVersion() async {
_listenToEvents();
try { try {
isFetchingDeviceInfo.value = true; isFetchingDeviceInfo.value = true;
errorMessage.value = ''; errorMessage.value = '';
@ -256,7 +263,7 @@ class OtaUpgradeController extends GetxController {
headers: {'Accept-Encoding': 'gzip'}, headers: {'Accept-Encoding': 'gzip'},
)); ));
jlota.type.value = DOWNLOADING_UP_FILES; type.value = DOWNLOADING_UP_FILES;
try { try {
final Directory? downloadsDir = await getDownloadsDirectory(); final Directory? downloadsDir = await getDownloadsDirectory();
if (downloadsDir == null) { if (downloadsDir == null) {
@ -352,4 +359,45 @@ class OtaUpgradeController extends GetxController {
return; return;
// isUpgrade.value = false; // isUpgrade.value = false;
} }
// 停止升级
void stopUpgrading() async {
jlota.onOtaClose();
return;
// isUpgrade.value = false;
}
void _listenToEvents() {
Ota.instance.eventStream.listen((event) {
if (event.event == 'onProgress' &&
event.type != null &&
event.progress != null) {
progress.value = event.progress!;
type.value = event.type!;
isUpgrade.value = true; // 开始升级
}
if (event.event == 'onStartOTA') {
type.value = OtaEvent.START_UPGRADING;
isUpgrade.value = true; // 开始升级
}
if (event.event == 'onStopOTA') {
type.value = OtaEvent.UPGRADE_SUCCESS;
isUpgrade.value = false;
Get.snackbar('升级成功', '请退出重新连接设备');
_getCurrentVersion();
}
if (event.event == 'onError') {
type.value = OtaEvent.UPGRADE_FAILED;
isUpgrade.value = false;
}
if (event.event == 'NOCONNECTION') {
type.value = OtaEvent.CONNECTION_DISCONNECTION;
isUpgrade.value = false;
}
if (event.event == 'CONNECTION_SUCCESS') {
type.value = OtaEvent.CONNECTION_SUCCESS;
isUpgrade.value = true; // 开始升级
}
});
}
} }

175
lib/modules/ota_upgrade/views/ota_upgrade_view.dart

@ -10,70 +10,125 @@ class OtaUpgradeView extends GetView<OtaUpgradeController> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isDarkMode = Theme.of(context).brightness == Brightness.dark; final isDarkMode = Theme.of(context).brightness == Brightness.dark;
return Scaffold( return WillPopScope(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[100], onWillPop: () async {
appBar: AppBar( if (controller.isUpgrade.value) {
automaticallyImplyLeading: false, // 显示确认弹窗
centerTitle: true, await Get.dialog(
elevation: 0, AlertDialog(
backgroundColor: isDarkMode ? Colors.black : Colors.white, title: Text('提示'),
leading: IconButton( content: Text('当前正在升级,退出将中断升级进程,确定要退出吗?'),
icon: Icon( actions: [
Icons.arrow_back_ios, TextButton(
size: 20.sp, onPressed: () => Get.back(), // 关闭弹窗
color: isDarkMode ? Colors.white : Colors.black, child: Text('取消'),
),
TextButton(
onPressed: () {
controller.stopUpgrading();
Get.back(); // 关闭弹窗
Get.back(); // 返回上一页
},
child: Text('确定'),
),
],
),
);
return false; // 阻止默认返回
}
return true; // 允许返回
},
child: Scaffold(
backgroundColor: isDarkMode ? Colors.black : Colors.grey[100],
appBar: AppBar(
automaticallyImplyLeading: false,
centerTitle: true,
elevation: 0,
backgroundColor: isDarkMode ? Colors.black : Colors.white,
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
size: 20.sp,
color: isDarkMode ? Colors.white : Colors.black,
),
onPressed: () {
if (controller.isUpgrade.value) {
// 显示确认弹窗
Get.dialog(
AlertDialog(
title: Text('提示'),
content: Text('当前正在升级,退出将中断升级进程,确定要退出吗?'),
actions: [
TextButton(
onPressed: () => Get.back(), // 关闭弹窗
child: Text('取消'),
),
TextButton(
onPressed: () {
controller.stopUpgrading();
Get.back(); // 关闭弹窗
Get.back(); // 返回上一页
},
child: Text('确定'),
),
],
),
);
} else {
Get.back(); // 正常返回
}
},
), ),
onPressed: () => Get.back(), title: Text(
), '固件升级'.tr,
title: Text( style: TextStyle(
'固件升级'.tr, fontSize: 20.sp,
style: TextStyle( color: isDarkMode ? Colors.white : Colors.black,
fontSize: 20.sp, ),
color: isDarkMode ? Colors.white : Colors.black,
), ),
), ),
), body: SingleChildScrollView(
body: SingleChildScrollView( child: Padding(
child: Padding( padding: EdgeInsets.all(20),
padding: EdgeInsets.all(20), child: Column(
child: Column( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, children: [
children: [ // 设备信息卡片
// 设备信息卡片 Card(
Card( elevation: 2,
elevation: 2, shape: RoundedRectangleBorder(
shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16),
borderRadius: BorderRadius.circular(16), ),
), color: isDarkMode ? Colors.grey[900] : Colors.white,
color: isDarkMode ? Colors.grey[900] : Colors.white, child: Padding(
child: Padding( padding: EdgeInsets.all(20),
padding: EdgeInsets.all(20), child: Column(
child: Column( children: [
children: [ _buildDeviceIcon(isDarkMode),
_buildDeviceIcon(isDarkMode), SizedBox(height: 20),
SizedBox(height: 20), _buildVersionInfo(isDarkMode),
_buildVersionInfo(isDarkMode), ],
], ),
), ),
), ),
), SizedBox(height: 20),
SizedBox(height: 20),
// 更新说明 // 更新说明
_buildUpdateNotes(isDarkMode), _buildUpdateNotes(isDarkMode),
SizedBox(height: 20), SizedBox(height: 20),
// 状态显示区域 // 状态显示区域
Obx(() { Obx(() {
if (controller.isFetchingDeviceInfo.value) { if (controller.isFetchingDeviceInfo.value) {
return _buildLoadingIndicator(isDarkMode); return _buildLoadingIndicator(isDarkMode);
} }
if (controller.errorMessage.value.isNotEmpty) { if (controller.errorMessage.value.isNotEmpty) {
return _buildErrorInfo(isDarkMode); return _buildErrorInfo(isDarkMode);
} }
return _buildUpdateButton(isDarkMode); return _buildUpdateButton(isDarkMode);
}), }),
], ],
),
), ),
), ),
), ),
@ -227,7 +282,7 @@ class OtaUpgradeView extends GetView<OtaUpgradeController> {
); );
Widget _buildUpdateButton(bool isDarkMode) { Widget _buildUpdateButton(bool isDarkMode) {
return controller.jlota.isUpgrade.value return controller.isUpgrade.value
? _buildProgressIndicator(isDarkMode) ? _buildProgressIndicator(isDarkMode)
: Container( : Container(
width: double.infinity, width: double.infinity,
@ -276,8 +331,8 @@ class OtaUpgradeView extends GetView<OtaUpgradeController> {
Widget _buildProgressIndicator(bool isDarkMode) { Widget _buildProgressIndicator(bool isDarkMode) {
return Obx(() { return Obx(() {
final progress = controller.jlota.progress.value; final progress = controller.progress.value;
final type = controller.jlota.type.value; final type = controller.type.value;
// // 处理升级失败状态:弹出 snackbar 并显示错误提示 // // 处理升级失败状态:弹出 snackbar 并显示错误提示
// if (type == OtaUpgradeController.UPGRADE_FAILED || // if (type == OtaUpgradeController.UPGRADE_FAILED ||

BIN
local_plugins/opus/.gradle/buildOutputCleanup/buildOutputCleanup.lock

Binary file not shown.

2
local_plugins/opus/.gradle/buildOutputCleanup/cache.properties

@ -1,2 +0,0 @@
#Wed May 21 01:03:35 CST 2025
gradle.version=8.9

26
local_plugins/ota/android/src/main/kotlin/com/example/ota/DeviceConnection.kt

@ -1,26 +0,0 @@
package com.jieli.otasdk.model
import android.bluetooth.BluetoothDevice
/**
* @author zqjasonZhong
* @since 2022/9/9
* @email zhongzhuocheng@zh-jieli.com
* @desc 设备连接状态
*/
class DeviceConnection(val device: BluetoothDevice?, var state: Int) {
override fun hashCode(): Int {
return device.hashCode()
}
override fun equals(other: Any?): Boolean {
if (other !is DeviceConnection) return false
return device == other.device
}
override fun toString(): String {
return "DeviceConnection(device=$device, state=$state)"
}
}

9
local_plugins/ota/android/src/main/kotlin/com/example/ota/OtaPlugin.kt

@ -20,7 +20,6 @@ import com.jieli.jl_bt_ota.util.CHexConver
import com.jieli.jl_bt_ota.util.JL_Log import com.jieli.jl_bt_ota.util.JL_Log
import com.jieli.otasdk.tool.bluetooth.BluetoothHelper import com.jieli.otasdk.tool.bluetooth.BluetoothHelper
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.jieli.otasdk.model.DeviceConnection
import android.util.Log import android.util.Log
import androidx.annotation.NonNull import androidx.annotation.NonNull
import com.jieli.otasdk.tool.config.ConfigHelper import com.jieli.otasdk.tool.config.ConfigHelper
@ -309,7 +308,11 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
otaDevice = bluetoothGatt.device otaDevice = bluetoothGatt.device
BleService.disconnect() BleService.disconnect()
} else { } else if(otaDevice != null)
{ isDisconnect = true
BleService.disconnect()
}
else{
Log.e("TAG", "BluetoothGatt 或 device 为 null,无法执行操作") Log.e("TAG", "BluetoothGatt 或 device 为 null,无法执行操作")
sendEventOnMainThread( sendEventOnMainThread(
mapOf( mapOf(
@ -324,6 +327,8 @@ class OtaPlugin : BleService.Callback, FlutterPlugin, MethodCallHandler {
} else if (call.method == "onOtaClose") { } else if (call.method == "onOtaClose") {
BleService.isEnterOta = false BleService.isEnterOta = false
isDisconnect = false isDisconnect = false
otaManager.bluetoothHelper.stopScan()
otaManager.bluetoothHelper.disconnectDevice(otaDevice)
} else { } else {
result.notImplemented() result.notImplemented()
} }

3
local_plugins/ota/android/src/main/kotlin/com/example/ota/tool/ota/ble/BleManager.java

@ -646,9 +646,10 @@ public class BleManager {
} else { } else {
Log.e(TAG, "连接设备失败: ${device.name} (${device.address})"); Log.e(TAG, "连接设备失败: ${device.name} (${device.address})");
} }
}
mDiscoveredBleDevices.add(device); mDiscoveredBleDevices.add(device);
handleDiscoveryBle(device, new BleScanInfo().setRawData(scanRecord).setRssi(rssi).setEnableConnect(isBleEnableConnect)); handleDiscoveryBle(device, new BleScanInfo().setRawData(scanRecord).setRssi(rssi).setEnableConnect(isBleEnableConnect));
}
} }
} }

94
local_plugins/ota/lib/ota.dart

@ -2,7 +2,6 @@ import 'ota_platform_interface.dart';
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:get/get.dart';
class OtaEvent { class OtaEvent {
static final int NOT_STARTED = -1; // 未开始 static final int NOT_STARTED = -1; // 未开始
@ -57,7 +56,7 @@ class Ota {
// 私有构造函数 // 私有构造函数
Ota._internal() { Ota._internal() {
// 初始化时设置事件监听 // 初始化时设置事件监听
_setupEventListener(); // _setupEventListener();
} }
// 公共访问点 // 公共访问点
@ -66,13 +65,13 @@ class Ota {
static const EventChannel _eventChannel = EventChannel( static const EventChannel _eventChannel = EventChannel(
'com.example.ota/events', 'com.example.ota/events',
); );
final RxDouble progress = 0.0.obs; // double progress = 0.0;
final RxInt type = OtaEvent.NOT_STARTED.obs; // late int type = OtaEvent.NOT_STARTED;
final RxBool isUpgrade = false.obs; // bool isUpgrade = false;
/// 事件流 /// 事件流
Stream<OtaEvent>? _eventStream; Stream<OtaEvent>? _eventStream;
bool _isEventListenerSet = false; // 防止重复监听 // bool _isEventListenerSet = false; // 防止重复监听
/// 获取事件流 /// 获取事件流
Stream<OtaEvent> get eventStream { Stream<OtaEvent> get eventStream {
@ -90,53 +89,48 @@ class Ota {
onOtaClose(); onOtaClose();
// 停止事件监听 // 停止事件监听
_eventStream = null; _eventStream = null;
_isEventListenerSet = false; //_isEventListenerSet = false;
// 清理 Rx 对象
progress.close();
type.close();
isUpgrade.value = false;
print("Ota 对象资源已释放"); print("Ota 对象资源已释放");
} }
/// 内部设置事件监听(只执行一次) // /// 内部设置事件监听(只执行一次)
void _setupEventListener() { // void _setupEventListener() {
if (_isEventListenerSet) return; // if (_isEventListenerSet) return;
eventStream.listen((event) { // eventStream.listen((event) {
if (event.event == 'onProgress' && // if (event.event == 'onProgress' &&
event.type != null && // event.type != null &&
event.progress != null) { // event.progress != null) {
print("flutter 收到数据${event.progress}type=${type.value}"); // print("flutter 收到数据${event.progress}type=${type}");
progress.value = event.progress!; // progress = event.progress!;
type.value = event.type!; // type = event.type!;
} // }
if (event.event == 'onStartOTA') { // if (event.event == 'onStartOTA') {
type.value = OtaEvent.START_UPGRADING; // type = OtaEvent.START_UPGRADING;
isUpgrade.value = true; // 开始升级 // isUpgrade = true; // 开始升级
} // }
if (event.event == 'onStopOTA') { // if (event.event == 'onStopOTA') {
type.value = OtaEvent.UPGRADE_SUCCESS; // type = OtaEvent.UPGRADE_SUCCESS;
isUpgrade.value = false; // isUpgrade = false;
} // }
if (event.event == 'onError' && // if (event.event == 'onError' &&
event.code != null && // event.code != null &&
event.message != null) { // event.message != null) {
print("flutter onError${event.code}type=${event.message}"); // print("flutter onError${event.code}type=${event.message}");
type.value = OtaEvent.UPGRADE_FAILED; // type = OtaEvent.UPGRADE_FAILED;
isUpgrade.value = false; // isUpgrade = false;
} // }
if (event.event == 'NOCONNECTION') { // if (event.event == 'NOCONNECTION') {
type.value = OtaEvent.CONNECTION_DISCONNECTION; // type = OtaEvent.CONNECTION_DISCONNECTION;
isUpgrade.value = false; // isUpgrade = false;
} // }
if (event.event == 'CONNECTION_SUCCESS') { // if (event.event == 'CONNECTION_SUCCESS') {
type.value = OtaEvent.CONNECTION_SUCCESS; // type = OtaEvent.CONNECTION_SUCCESS;
} // }
}); // });
_isEventListenerSet = true; // _isEventListenerSet = true;
} // }
Future<String?> startUpgrading(String? filePath) { Future<String?> startUpgrading(String? filePath) {
return OtaPlatform.instance.startUpgrading(filePath); return OtaPlatform.instance.startUpgrading(filePath);

1
local_plugins/ota/pubspec.yaml

@ -11,7 +11,6 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
plugin_platform_interface: ^2.0.2 plugin_platform_interface: ^2.0.2
get: ^4.6.5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter

Loading…
Cancel
Save