import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:path/path.dart'; import 'dart:async'; import '../../../data/services/network/api.dart'; import '../model/ota_upgrade_model.dart'; import 'dart:io'; import 'package:dio/dio.dart'; import 'package:path_provider/path_provider.dart'; import 'package:ota/ota.dart'; import '../../../data/services/ble_manager.dart'; class OtaUpgradeController extends GetxController { static const int NOT_STARTED = -1; // 未开始 static const int VALIDATION_FILE = 0; // 验证文件 static const int ONUPGRADE = 1; // 升级中 static const int START_UPGRADING = 2; // 开始升级 static const int UPGRADE_SUCCESS = 3; // 升级成功 static const int UPGRADE_FAILED = 4; // 升级失败 static const int CONNECTION_DISCONNECTION = 5; // 连接断开 static const int CONNECTION_SUCCESS = 6; // 连接成功 static const int DOWNLOADING_UP_FILES = 7; // 下载升级文件 final RxString errorMessage = ''.obs; final RxBool isFetchingDeviceInfo = false.obs; final RxString latestVersion = ''.obs; final RxString currentVersion = ''.obs; String updatepackageaddress = ''; final RxDouble downloadProgress = 0.0.obs; final isUpdateAvailable = true.obs; //int currentProgress = 0; // 当前进度值,范围0-100 final RxDouble progress = 0.0.obs; final jlota = Ota.instance; final RxBool isDownloading = false.obs; // 蓝牙服务 final _bleManager = Get.find(); @override void onInit() { super.onInit(); _getCurrentVersion(); } @override void onClose() { jlota.onOtaClose(); super.onClose(); } // 添加重试方法 void retryConnection() { errorMessage.value = ''; _getCurrentVersion(); } String getStatusMessage(int type) { switch (type) { case NOT_STARTED: // -1 return "未开始".tr; case VALIDATION_FILE: // 0 return "验证文件中".tr; case ONUPGRADE: // 1 return "升级中".tr; case START_UPGRADING: // 2 return "开始升级".tr; case UPGRADE_SUCCESS: // 3 return "升级成功".tr; case UPGRADE_FAILED: // 4 return "升级失败".tr; case CONNECTION_DISCONNECTION: // 5 return "连接断开".tr; case CONNECTION_SUCCESS: // 6 return "连接成功".tr; case DOWNLOADING_UP_FILES: // 7 (新增) return "下载升级文件".tr; default: return "未知状态".tr; // 更安全的默认值 } } // 添加更新方法 Future startUpdate() async { try { checkUpdate(); // 实现更新逻辑... } catch (e) { errorMessage.value = e.toString(); Get.snackbar('更新失败', e.toString()); } } Future _getCurrentVersion() async { try { // 添加获取设备信息的重试机制 DeviceInfo? deviceInfo = _bleManager.deviceInfo.value; // 第一次检查设备信息 if (deviceInfo == null) { // 显示加载提示 isFetchingDeviceInfo.value = true; // 尝试重新获取设备信息 await _bleManager.fetchDeviceInfo(); // 等待后再次获取设备信息 deviceInfo = _bleManager.deviceInfo.value; isFetchingDeviceInfo.value = false; // 仍然为空则抛出异常 if (deviceInfo == null) { throw const FormatException('无法获取设备信息,请检查设备连接'); } } // 检查固件信息有效性 if (deviceInfo.firmwareVersion.isEmpty || deviceInfo.firmwareProductId.isEmpty) { throw const FormatException('设备固件信息不完整'); } // 正常流程 currentVersion.value = deviceInfo.firmwareVersion; print('getequipmentinfo,id: ${deviceInfo.firmwareProductId}'); // API请求 final response = await Api.getequipmentinfo({ "id": deviceInfo.firmwareProductId, }); // 处理API响应 if (response['info'] == null) { throw const FormatException('API 响应格式错误'); } final resp = OtaConfigResp.fromJson(response); print('getequipmentinfo,resp.systemversion: ${resp.systemversion}'); latestVersion.value = "1"; updatepackageaddress = resp.updatepackageaddress!; // 版本检查 isUpdateAvailable.value = _isNewVersionAvailable(resp.systemversion!); } catch (e) { // 统一错误处理 errorMessage.value = e.toString(); Get.snackbar('错误', e.toString(), snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red, colorText: Colors.white); // 重要:重新抛出异常以便上层处理(可选) } finally { isFetchingDeviceInfo.value = false; } } // 版本比较方法优化 bool _isNewVersionAvailable(String latest) { try { List currentParts = currentVersion.value .split('.') .map((e) => int.parse(e.trim())) .toList(); List latestParts = latest.split('.').map((e) => int.parse(e.trim())).toList(); for (int i = 0; i < latestParts.length; i++) { int current = (i < currentParts.length) ? currentParts[i] : 0; if (latestParts[i] > current) return true; if (latestParts[i] < current) return false; } return false; } catch (e) { print('版本比较错误: $e'); return false; } } // 版本更新 Future checkUpdate() async { try { if (latestVersion.value != "") _showUpdateDialog(latestVersion.value); else { Get.snackbar('错误', '获取最新版本信息失败'); } } catch (e) { Get.snackbar('错误', '获取版本信息失败'); } } // 显示更新对话框 void _showUpdateDialog(String latest) { Get.dialog( AlertDialog( title: Text('发现新版本 $latest'), content: Text('是否立即更新?'), actions: [ TextButton( onPressed: () { if (Get.isDialogOpen!) { Get.back(); // 确保只关闭对话框 } }, child: Text('取消'), ), TextButton( onPressed: () { if (Get.isDialogOpen!) { Get.back(); // 确保只关闭对话框 } startDownload(); }, child: Text('更新'), ), ], ), ); } // 修改后的startDownload方法 Future startDownload() async { isDownloading.value = true; int lastIndex = updatepackageaddress.lastIndexOf('/'); String fileName = updatepackageaddress.substring(lastIndex + 1); String directoryName = "ota_upgrades"; final dio = Dio(BaseOptions( connectTimeout: const Duration(seconds: 5), receiveTimeout: Duration.zero, sendTimeout: const Duration(seconds: 5), headers: {'Accept-Encoding': 'gzip'}, )); jlota.type.value = DOWNLOADING_UP_FILES; try { final Directory? downloadsDir = await getDownloadsDirectory(); if (downloadsDir == null) { throw FileSystemException('无法访问下载目录'); } final targetDir = Directory('${downloadsDir.path}/$directoryName'); if (!await targetDir.exists()) { await targetDir.create(recursive: true); } final savePath = '${targetDir.path}/$fileName'; // 新增:检查同名文件逻辑 bool existingSameFile = false; try { var files = await targetDir.list().toList(); for (var entity in files) { if (await FileSystemEntity.isFile(entity.path)) { String name = basename(entity.path); // 使用path包中的basename if (name == fileName) { existingSameFile = true; break; } } } } catch (e) { Get.snackbar('错误', '检查本地文件失败: $e'); return; } if (existingSameFile) { Get.snackbar('文件已存在', '跳过下载,直接更新'); _installApp(savePath); return; } // 新增:删除其他文件逻辑 try { var files = await targetDir.list().toList(); for (var entity in files) { if (await FileSystemEntity.isFile(entity.path)) { await entity.delete(); } } } catch (e) { Get.snackbar('错误', '删除旧文件失败: $e'); //isUpgrade.value = false; return; } print('文件保存路径: $savePath'); final options = Options( receiveTimeout: Duration.zero, followRedirects: true, maxRedirects: 5, ); // 修改下载部分 await dio.download( updatepackageaddress, savePath, options: options, onReceiveProgress: (received, total) { if (total != -1) { downloadProgress.value = received / total; } }, ); File file = File(savePath); if (await file.exists()) { Get.snackbar('下载完成', '文件已保存至: $savePath'); } else { Get.snackbar('错误', '文件未找到,请检查写入权限'); } isDownloading.value = false; _installApp(savePath); return; } on DioException catch (e) { Get.snackbar('下载失败', '错误: ${e.message}'); } on FileSystemException catch (e) { Get.snackbar('存储失败', '无法写入文件: ${e.message}'); } catch (e) { Get.snackbar('未知错误', e.toString()); } } // 开始升级 void _installApp(String path) async { jlota.searchDevices(path); return; // isUpgrade.value = false; } }