From 6b0e459829862240cf3c8a3c1b0496c40d7e867b Mon Sep 17 00:00:00 2001 From: anfe <448468458@qq.com> Date: Tue, 7 May 2024 16:45:59 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=AE=8C=E6=88=90=E6=9C=AA?= =?UTF-8?q?=E9=85=8D=E5=AF=B9=20ota=20=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- star_lock/images/lan/lan_en.json | 10 + star_lock/images/lan/lan_keys.json | 11 +- star_lock/images/lan/lan_zh.json | 13 +- star_lock/images/ota_upgrade_icon.png | Bin 0 -> 10312 bytes star_lock/ios/Flutter/AppFrameworkInfo.plist | 2 +- star_lock/lib/blue/blue_manage.dart | 52 +-- .../lib/blue/io_protocol/io_otaUpgrade.dart | 44 ++- star_lock/lib/blue/io_sender.dart | 12 +- star_lock/lib/main.dart | 4 +- .../addLock/nearbyLock/nearbyLock_logic.dart | 334 ++++++++++++++---- .../addLock/nearbyLock/nearbyLock_page.dart | 178 ++++++++-- .../addLock/nearbyLock/nearbyLock_state.dart | 6 +- star_lock/pubspec.yaml | 2 +- 13 files changed, 515 insertions(+), 153 deletions(-) create mode 100644 star_lock/images/ota_upgrade_icon.png diff --git a/star_lock/images/lan/lan_en.json b/star_lock/images/lan/lan_en.json index f56c79b8..7a5e3144 100644 --- a/star_lock/images/lan/lan_en.json +++ b/star_lock/images/lan/lan_en.json @@ -796,4 +796,14 @@ "购买":"Buy", "实名认证为付费功能,请购买后再使用":"Real-name authentication is a paid function, please use it after purchase" "密码不一致哦":"The passwords are inconsistent", + "点击返回设备配对":"Tap Back to device pairing", + "无法连接?尝试升级":"Can't connect?Upgrade attempted", + "固件升级提示":"Firmware upgrade prompt", + "请先获取固件文件到手机本地,再选择升级":"Please obtain the firmware file to the local phone first, and then select Upgrade", + "固件升级中":"The firmware is being upgraded", + "取消升级":"Cancel the upgrade", + "固件传输中":"Firmware in transit", + "关闭":"Shut down", + "传输中'":"In transit" + } diff --git a/star_lock/images/lan/lan_keys.json b/star_lock/images/lan/lan_keys.json index 64c7c078..ef985320 100644 --- a/star_lock/images/lan/lan_keys.json +++ b/star_lock/images/lan/lan_keys.json @@ -822,5 +822,14 @@ "实名认证":"实名认证", "当前剩余数量":"当前剩余数量", "购买":"购买", - "实名认证为付费功能,请购买后再使用":"实名认证为付费功能,请购买后再使用" + "实名认证为付费功能,请购买后再使用":"实名认证为付费功能,请购买后再使用", + "点击返回设备配对":"点击返回设备配对", + "无法连接?尝试升级":"无法连接?尝试升级", + "固件升级提示":"固件升级提示", + "请先获取固件文件到手机本地,再选择升级":"请先获取固件文件到手机本地,再选择升级", + "固件升级中":"固件升级中", + "取消升级":"取消升级", + "固件传输中":"固件传输中", + "关闭":"关闭", + "传输中'":"传输中" } diff --git a/star_lock/images/lan/lan_zh.json b/star_lock/images/lan/lan_zh.json index 11104186..d8e7bc35 100644 --- a/star_lock/images/lan/lan_zh.json +++ b/star_lock/images/lan/lan_zh.json @@ -825,5 +825,16 @@ "实名认证":"实名认证", "当前剩余数量":"当前剩余数量", "购买":"购买", - "实名认证为付费功能,请购买后再使用":"实名认证为付费功能,请购买后再使用" + "实名认证为付费功能,请购买后再使用":"实名认证为付费功能,请购买后再使用", + "点击返回设备配对":"点击返回设备配对", + "无法连接?尝试升级":"无法连接?尝试升级", + "固件升级提示":"固件升级提示", + "请先获取固件文件到手机本地,再选择升级":"请先获取固件文件到手机本地,再选择升级", + "固件升级中":"固件升级中", + "取消升级":"取消升级", + "固件传输中":"固件传输中", + "关闭":"关闭", + "传输中'":"传输中" + + } diff --git a/star_lock/images/ota_upgrade_icon.png b/star_lock/images/ota_upgrade_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..14618cb5ddf4fc1da80a1472cb88306f7fd23e1d GIT binary patch literal 10312 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 X`O{zSulmaWcJb+G7^qjO+QCFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/star_lock/lib/blue/blue_manage.dart b/star_lock/lib/blue/blue_manage.dart index 0c34dd25..2f723984 100644 --- a/star_lock/lib/blue/blue_manage.dart +++ b/star_lock/lib/blue/blue_manage.dart @@ -145,7 +145,8 @@ class BlueManage { _connectionStateSubscription?.cancel(); _connectionStateSubscription = null; - _connectionStateSubscription = bluetoothConnectDevice!.connectionState.listen((state) async { + _connectionStateSubscription = + bluetoothConnectDevice!.connectionState.listen((state) async { bluetoothConnectionState = state; // AppLog.log("蓝牙连接状态:$state"); }); @@ -214,7 +215,9 @@ class BlueManage { completer.complete(); } }, onError: (e) { - AppLog.log("扫描失败:$e",); + AppLog.log( + "扫描失败:$e", + ); }); FlutterBluePlus.cancelWhenScanComplete(subscription); await completer.future; @@ -281,7 +284,9 @@ class BlueManage { // EventBusManager().eventBusFir(scanDevices); // FlutterBluePlus.stopScan(); }, onError: (e) { - AppLog.log("扫描失败:$e",); + AppLog.log( + "扫描失败:$e", + ); }); FlutterBluePlus.cancelWhenScanComplete(subscription); @@ -304,7 +309,9 @@ class BlueManage { } /// 调用发送数据 List senderData, - Future bludSendData(String deviceName, ConnectStateCallBack stateCallBack, {bool isAddEquipment = false}) async { + Future bludSendData( + String deviceName, ConnectStateCallBack stateCallBack, + {bool isAddEquipment = false}) async { FlutterBluePlus.isSupported.then((isAvailable) async { if (isAvailable) { if (_adapterState == BluetoothAdapterState.on) { @@ -336,21 +343,13 @@ class BlueManage { {bool isAddEquipment = false}) async { connectDeviceName = deviceName; List devicesList = scanDevices; - //判断列表里面有设备则不开启扫描 - bool isExistDevice = scanDevices.any((element) => - element.device.platformName == connectDeviceName || - element.advertisementData.advName == connectDeviceName); - if (isAddEquipment == false && isExistDevice == false) { - // AppLog.log("需要开启扫描"); - // startScan(10, (scanDevices){ - startScanSingle(deviceName, 10, (List scanDevices) { - // AppLog.log("扫描到的设备:$scanDevices"); - devicesList = scanDevices; + if (isAddEquipment == false) { + //取消缓存直接使用,存在配对场景设备信息会更变 + startScan(10, (List scanDevices) { _connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment); }); } else { - // AppLog.log("不需要开启扫描"); _connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment); } @@ -364,6 +363,7 @@ class BlueManage { final knownDeviceIndex = devicesList.indexWhere((d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName)); + if (knownDeviceIndex >= 0) { // 存在的时候赋值 connectDeviceMacAddress = @@ -375,6 +375,7 @@ class BlueManage { // AppLog.log('bluetoothConnectDevice: $bluetoothConnectDevice'); scanResult = devicesList[knownDeviceIndex]; + _initGetMtuSubscription(); _initListenConnectionState(); } @@ -446,7 +447,8 @@ class BlueManage { } on Exception catch (e) { bluetoothConnectionState = BluetoothConnectionState.disconnected; connectStateCallBack(bluetoothConnectionState!); - AppLog.log('发现设备时失败 e:$e bluetoothConnectionState:$bluetoothConnectionState'); + AppLog.log( + '发现设备时失败 e:$e bluetoothConnectionState:$bluetoothConnectionState'); rethrow; } } @@ -461,7 +463,7 @@ class BlueManage { _subScribeToCharacteristic(BluetoothCharacteristic characteristic) async { final subscription = characteristic.onValueReceived.listen((data) { - // AppLog.log("订阅获取的数据:$data"); + AppLog.log("订阅获取的数据:$data"); if (data == lastTimeData || data.isEmpty) { return; } else { @@ -477,7 +479,7 @@ class BlueManage { // 判断是否需要分包 dataLen = data[8] * 256 + data[9]; // 高16位用来指示后面数据块内容的长度 // AppLog.log("dataLen1111:$dataLen getDataLength:${data.length} data:$data"); - if (dataLen! + 12 > data.length) { + if (dataLen! + 14 > data.length) { // 当前包的长度小于实际的包时 分包添加 不解析 allData.addAll(data); } else { @@ -555,15 +557,16 @@ class BlueManage { // 写入 Future writeCharacteristicWithResponse(List value) async { - - List services = await bluetoothConnectDevice!.discoverServices(); + List services = + await bluetoothConnectDevice!.discoverServices(); for (BluetoothService service in services) { // AppLog.log("33333 service.remoteId:${service.remoteId}" // " service.uuid:${service.uuid}\n\n" // " service.characteristics:${service.characteristics}\n\n" // " service.includedServices:${service.includedServices}"); if (service.uuid == _serviceIdConnect) { - for (BluetoothCharacteristic characteristic in service.characteristics) { + for (BluetoothCharacteristic characteristic + in service.characteristics) { // AppLog.log("44444 characteristic.remoteId:${characteristic.remoteId}" // " characteristic.uuid:${characteristic.uuid}\n\n" // " characteristic.secondaryServiceUuid:${characteristic @@ -578,7 +581,9 @@ class BlueManage { for (int i = 0; i < subData.length; i++) { if (characteristic.properties.writeWithoutResponse) { // 使用WRITE_NO_RESPONSE属性写入值 - await characteristic.write(subData[i],withoutResponse: true).then((value) async { + await characteristic + .write(subData[i], withoutResponse: true) + .then((value) async { // await Future.delayed(const Duration(milliseconds: 1)).then(( // value) async { // AppLog.log('分包发送成功了'); @@ -594,7 +599,8 @@ class BlueManage { }); } else { // 特性不支持写入 - throw Exception('This characteristic does not support writing.'); + throw Exception( + 'This characteristic does not support writing.'); } } } on Exception catch (e, s) { diff --git a/star_lock/lib/blue/io_protocol/io_otaUpgrade.dart b/star_lock/lib/blue/io_protocol/io_otaUpgrade.dart index c4b37137..3d358a74 100644 --- a/star_lock/lib/blue/io_protocol/io_otaUpgrade.dart +++ b/star_lock/lib/blue/io_protocol/io_otaUpgrade.dart @@ -26,6 +26,7 @@ class OTAUpgradeCommand extends SenderProtocol { List? signKey; List? privateKey; List? token; + bool encrypt; OTAUpgradeCommand( {this.lockID, @@ -40,10 +41,10 @@ class OTAUpgradeCommand extends SenderProtocol { this.needAuthor, this.signKey, this.privateKey, - this.token}) + this.token, + this.encrypt = true}) : super(CommandType.startOATUpgrade); - @override String toString() { return 'OTAUpgradeCommand{lockID: $lockID, userID: $userID, ' @@ -53,6 +54,15 @@ class OTAUpgradeCommand extends SenderProtocol { 'privateKey: $privateKey, token: $token}'; } + @override + int identifierValue() { + if (encrypt) { + return super.identifierValue(); + } else { + return 0x20; + } + } + @override List messageDetail() { List data = []; @@ -66,21 +76,18 @@ class OTAUpgradeCommand extends SenderProtocol { data.add(type1); data.add(type2); - AppLog.log('---> 指令 : $type1 $type2' ); // 锁id 40 int lockIDLength = utf8.encode(lockID!).length; data.addAll(utf8.encode(lockID!)); data = getFixedLengthList(data, 40 - lockIDLength); - AppLog.log('---> 锁id :${utf8.encode(lockID!)}'); //userID 20 int userIDLength = utf8.encode(userID!).length; data.addAll(utf8.encode(userID!)); data = getFixedLengthList(data, 20 - userIDLength); - AppLog.log('---> userID :${utf8.encode(userID!)}'); //platform 2 int platform0 = (platform! & 0xFF00) >> 8; @@ -88,36 +95,31 @@ class OTAUpgradeCommand extends SenderProtocol { data.add(platform0); data.add(platform1); - AppLog.log('---> platform : $platform0 $platform1'); //product 2 // int product0 = (product! & 0xFF00) >> 8; // int product1 = product! & 0xFF; // data.add(product0); // data.add(product1); - data.addAll([0,1]);//先默认是 01 + data.addAll([0, 1]); //先默认是 01 - AppLog.log('---> platform : ${[0,1]}'); //HwVersion 20 int hwVersionLength = utf8.encode(hwVersion!).length; data.addAll(utf8.encode(hwVersion!)); data = getFixedLengthList(data, 20 - hwVersionLength); - //FwVersion 20 int fwVersionLength = utf8.encode(fwVersion!).length; data.addAll(utf8.encode(fwVersion!)); data = getFixedLengthList(data, 20 - fwVersionLength); - //fwSize 4 ByteData bytes = ByteData(4); // 创建一个长度为4的字节数据 bytes.setInt32(0, fwSize!); List byteList = bytes.buffer.asUint8List(); data.addAll(byteList); - // 创建一个16字节的字节数组 Uint8List result = Uint8List(16); // 将每个十六进制字符转换为4位二进制数据,并将其存储到结果字节数组中 @@ -142,11 +144,9 @@ class OTAUpgradeCommand extends SenderProtocol { authCodeData.addAll(utf8.encode(userID!)); //token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 - authCodeData.addAll(token!); + authCodeData.addAll(token??[]); - authCodeData.addAll(signKey!); - - AppLog.log('---> ${utf8.encode(keyID!)} ${utf8.encode(userID!)} $token $signKey'); + authCodeData.addAll(signKey??[]); // 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode var authCode = crypto.md5.convert(authCodeData); @@ -161,11 +161,17 @@ class OTAUpgradeCommand extends SenderProtocol { data.add(0); } } - printLog(data); - // 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864 - ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB); - return ebcData; + + if (encrypt) { + + // 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864 + ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB); + return ebcData; + } else { + data.add(0); + return data; + } } } diff --git a/star_lock/lib/blue/io_sender.dart b/star_lock/lib/blue/io_sender.dart index 8c470f38..045b46d9 100644 --- a/star_lock/lib/blue/io_sender.dart +++ b/star_lock/lib/blue/io_sender.dart @@ -33,8 +33,9 @@ abstract class SenderProtocol extends IOData { _commandIndex = IoManager().commandIndex; } - void printLog(List data){ - AppLog.log("App -> 锁,指令类型:${commandType!.typeName} \n\n参数是:\n${toString()} \n\n加密之前数据是:\n$data"); + void printLog(List data) { + AppLog.log( + "App -> 锁,指令类型:${commandType!.typeName} \n\n参数是:\n${toString()} \n\n加密之前数据是:\n$data"); } //TODO:拼装数据Ï @@ -58,7 +59,8 @@ abstract class SenderProtocol extends IOData { // 包标识 // 指令类型 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) - commandList.add(commandType!.identifierValue); + int value = identifierValue(); + commandList.add(value); // 数据长度 int dataLen = dataSourceLength(); @@ -84,6 +86,10 @@ abstract class SenderProtocol extends IOData { return commandList; } + // 包标识 + // 指令类型 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥) + int identifierValue() => commandType!.identifierValue; + //TODO:长度 int dataSourceLength() => commandData!.length; diff --git a/star_lock/lib/main.dart b/star_lock/lib/main.dart index 54dd55eb..5b7c18bc 100644 --- a/star_lock/lib/main.dart +++ b/star_lock/lib/main.dart @@ -20,9 +20,7 @@ FutureOr main() async { // 设置国际化信息 await _initTranslation(); - DebugConsole.listen(() { - runApp(const MyApp()); - }); + runApp(const MyApp()); if (AppPlatform.isAndroid) { SystemUiOverlayStyle systemUiOverlayStyle = diff --git a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart index 05cd0e47..1e6faeba 100644 --- a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart +++ b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_logic.dart @@ -1,10 +1,20 @@ - import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; +import 'package:crypto/crypto.dart'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; +import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.dart'; +import 'package:permission_handler/permission_handler.dart'; import 'package:star_lock/blue/io_protocol/io_getPrivateKey.dart'; import 'package:star_lock/blue/io_protocol/io_getPublicKey.dart'; +import 'package:star_lock/blue/io_protocol/io_otaUpgrade.dart'; +import 'package:star_lock/blue/io_protocol/io_processOtaUpgrade.dart'; +import 'package:star_lock/mine/addLock/nearbyLock/nearbyLock_page.dart'; +import 'package:star_lock/permission/permission_dialog.dart'; import 'package:star_lock/tools/baseGetXController.dart'; import '../../../appRouters.dart'; @@ -21,6 +31,15 @@ import 'nearbyLock_state.dart'; class NearbyLockLogic extends BaseGetXController { final NearbyLockState state = NearbyLockState(); + int otaCount = 0; + int otaIndex = 0; + Uint8List? otaBin; + int startSecond = 0; + Map? headJson; + + String? deviceName; + StreamSubscription? _replySubscription; + // 点击连接设备 void connect(String deviceName) { showTitleEasyLoading("获取锁信息 1/3"); @@ -30,11 +49,12 @@ class NearbyLockLogic extends BaseGetXController { // state.sureBtnState.value = 1; // showEasyLoading(); - showBlueConnetctToastTimer(action: (){ + showBlueConnetctToastTimer(action: () { dismissEasyLoading(); // state.sureBtnState.value = 0; }); - BlueManage().bludSendData(deviceName, (BluetoothConnectionState state) async { + BlueManage().bludSendData(deviceName, + (BluetoothConnectionState state) async { AppLog.log("点击要添加的设备了"); if (state == BluetoothConnectionState.connected) { AppLog.log("开始获取公钥"); @@ -45,12 +65,11 @@ class NearbyLockLogic extends BaseGetXController { }, isAddEquipment: true); } - // 获取解析后的数据 - late StreamSubscription _replySubscription; void _initReplySubscription() { - _replySubscription = EventBusManager().eventBus!.on().listen((reply) { + _replySubscription = + EventBusManager().eventBus!.on().listen((reply) { if (reply is GetPublicKeyReply) { - _replyGetPublicKey(reply); + _replyGetPublicKey(reply); } if (reply is GetPrivateKeyReply) { @@ -61,6 +80,23 @@ class NearbyLockLogic extends BaseGetXController { if (reply is GetStarLockStatuInfoReply) { _replyGetStarLockStatusInfo(reply); } + + if (reply is OTAUpgradeReply) { + if (reply.status == 0x00) { + //验证通过,开始发送数据包 + dismissEasyLoading(); + startOTAData(); + processOtaUpgrade(); + } else if (reply.status == 0x06) { + blueOTAUpgrade(headJson!, reply.token); + } + } else if (reply is ProcessOtaUpgradeReply && reply.status == 0x00) { + otaIndex++; + processOtaUpgrade(); + } else if (reply is ConfirmationOTAUpgradeReply && reply.status == 0x00) { + showToast('固件升级完成'.tr); + closeOTADAta(); + } }); } @@ -197,8 +233,10 @@ class NearbyLockLogic extends BaseGetXController { // 重置次数 var restoreCounter = reply.data.sublist(133, 135); - state.lockInfo["restoreCount"] = restoreCounter[0] * 256 + restoreCounter[1]; - AppLog.log("重置次数 restoreCounter:${restoreCounter[0] * 256 + restoreCounter[1]}"); + state.lockInfo["restoreCount"] = + restoreCounter[0] * 256 + restoreCounter[1]; + AppLog.log( + "重置次数 restoreCounter:${restoreCounter[0] * 256 + restoreCounter[1]}"); // 重置时间 var restoreDate = reply.data.sublist(135, 139); @@ -312,21 +350,6 @@ class NearbyLockLogic extends BaseGetXController { } } - // List charListChangeIntList(List featureValue){ - // // 字符数组转化为16进制字符串 - // String featureValueStr = asciiString(featureValue); - // // 16进制字符串转化为2进制的字符串 获取的是逆序的需要倒序 前面有0会消失 需要自动补全 暂时定位57个功能 要补全60 - // String featureValueTwoStr = int.parse(featureValueStr,radix: 16).toRadixString(2); - // List featureValueTwoList = []; - // for(int i = 0;i _getStarLockStatus() async { // 进来之后首先连接 @@ -334,39 +357,26 @@ class NearbyLockLogic extends BaseGetXController { // if (state == BluetoothConnectionState.connected) { // dismissEasyLoading(); - AppLog.log("开始获取锁状态"); - var privateKey = await Storage.getStringList(saveBluePrivateKey); - List getPrivateKeyList = changeStringListToIntList(privateKey!); - // IoSenderManage.senderGetLockStatu( - // lockID:BlueManage().connectDeviceName, - // userID:await Storage.getUid(), - // privateKey:getPrivateKeyList, - // ); - IoSenderManage.senderGetStarLockStatuInfo( - lockID: BlueManage().connectDeviceName, - userID: await Storage.getUid(), - isBeforeAddUser: true, - privateKey: getPrivateKeyList, - ); + AppLog.log("开始获取锁状态"); + var privateKey = await Storage.getStringList(saveBluePrivateKey); + List getPrivateKeyList = changeStringListToIntList(privateKey!); + // IoSenderManage.senderGetLockStatu( + // lockID:BlueManage().connectDeviceName, + // userID:await Storage.getUid(), + // privateKey:getPrivateKeyList, + // ); + IoSenderManage.senderGetStarLockStatuInfo( + lockID: BlueManage().connectDeviceName, + userID: await Storage.getUid(), + isBeforeAddUser: true, + privateKey: getPrivateKeyList, + ); // } else if (state == BluetoothConnectionState.disconnected) { // dismissEasyLoading(); // } // }, isAddEquipment: true); } - // late StreamSubscription>_scanListDiscoveredDeviceSubscription; - // void _scanListDiscoveredDeviceSubscriptionAction() { - // _scanListDiscoveredDeviceSubscription = EventBusManager().eventBus!.on>().listen((List list) { - // state.devices.clear(); - // for (int i = 0; i < list.length; i++) { - // ScanResult device = list[i]; - // if (((device.advertisementData.serviceUuids.isNotEmpty ? device.advertisementData.serviceUuids[0] : "").toString()[31] != "1")) { - // state.devices.add(list[i]); - // } - // } - // }); - // } - void startScanBlueList() { BlueManage().startScan(2000, (List list) { state.devices.clear(); @@ -388,30 +398,234 @@ class NearbyLockLogic extends BaseGetXController { BlueManage().stopScan(); } + // 点击连接设备,升级 ota 固件 + void oTAUpgrade(String deviceName) { + showTitleEasyLoading("连接设备中..."); + this.deviceName = deviceName; + BlueManage().bludSendData(deviceName, + (BluetoothConnectionState state) async { + AppLog.log("连接设备"); + if (state == BluetoothConnectionState.connected) { + AppLog.log("连接成功"); + dismissEasyLoading(); + otaUpdate(); + } else if (state == BluetoothConnectionState.disconnected) { + AppLog.log("连接失败"); + dismissEasyLoading(); + } + }, isAddEquipment: true); + } + + //手动升级 + Future otaUpdate() async { + var status = await PermissionDialog.request( + Permission.storage, '需要访问读写权限才能使用手动升级固件'.tr); + if (status != true) { + return; + } + FilePickerResult? result = await FilePicker.platform.pickFiles(); + if (result == null || result.files.single.path is! String) { + return; + } + File file = File(result.files.single.path!); + Uint8List data = await file.readAsBytes(); + headJson = await getHeadFile(data); + if (headJson is! Map) { + return; + } + otaBin = await checkFile(data, headJson!); + if (otaBin == null) { + return; + } + String md5Str = md5.convert(otaBin!).toString(); + headJson!['fwMd5'] = md5Str; + blueOTAUpgrade(headJson!, [0, 0, 0, 0]); + } + + //蓝牙操作 ota 升级 + void blueOTAUpgrade(Map data, List token) { + if (deviceName == null) { + AppLog.log('blueOTAUpgrade:设备名字为 null'); + return; + } + BlueManage().bludSendData(deviceName!, + (BluetoothConnectionState deviceConnectionState) async { + if (deviceConnectionState == BluetoothConnectionState.connected) { + String uid = await Storage.getUid() ?? ''; + BlueManage().writeCharacteristicWithResponse(OTAUpgradeCommand( + lockID: deviceName, + userID: uid, + keyID: deviceName, + platform: int.tryParse(data['platform']) ?? 0, + product: int.tryParse(data['product']) ?? 0, + hwVersion: data['hwVersion'], + fwVersion: data['fwVersion'], + fwSize: data['fwSize'], + fwMD5: data['fwMd5'], + needAuthor: 1, + token: token, + encrypt: false, + ).packageData()); + showTitleEasyLoading("连接设备中..."); + } else if (deviceConnectionState == + BluetoothConnectionState.disconnected) {} + },isAddEquipment: true); + } + + //循环传输升级固件包 + Future processOtaUpgrade() async { + if (!state.otaUpdateIng.value) { + return; + } + int length = otaBin?.length ?? 0; + if (otaCount == 0) { + //首次 + int difference = length % 240; + otaCount = length ~/ 240 + (difference > 0 ? 1 : 0); + startSecond = DateTime.now().millisecondsSinceEpoch ~/ 1000; + } + if (otaCount <= otaIndex) { + int now = DateTime.now().millisecondsSinceEpoch ~/ 1000; + String msg = + '传输完成 时间:${now - startSecond}秒 otaCount:$otaCount otaIndex:$otaIndex '; + closeOTADAta(); + AppLog.log(msg); + // showToast(msg); + return; + } + int star = otaIndex * 240; + int end = (otaIndex + 1) * 240; + if (end > length) { + end = length; + } + int size = end - star; + List data = otaBin!.sublist(star, end); + state.otaProgress.value = otaIndex / otaCount; + await BlueManage().writeCharacteristicWithResponse( + ProcessOtaUpgradeCommand(index: otaIndex, size: size, data: data) + .packageData()); + } + + //开始 ota升级 + void startOTAData() { + state.otaUpdateIng.value = true; + state.oTAProgressDialog = true; + Get.dialog( + OTAProgressDialog( + logic: this, + ), + barrierDismissible: false) + .then((value) => state.oTAProgressDialog = false); + } + + //清楚 ata 安装文件 + void closeOTADAta() { + if (state.oTAProgressDialog) { + Get.back(); + } + state.otaUpdateIng.value = false; + state.otaProgress.value = 0; + otaIndex = 0; + otaCount = 0; + startSecond = 0; + otaBin = null; + } + + // 拦截返回事件 + void getBack() { + if (state.otaUpdateIng.value) { + closeOTADAta(); + } else { + Get.back(); + } + } + +// 检查文件头 + Future getHeadFile(Uint8List data) async { + if (data.length <= 16) { + showToast('错误固件,请选择正确的文件'.tr); + return null; + } + // 检查文件头 + String header; + try { + header = utf8.decode(data.sublist(0, 12)); + } catch (e) { + showToast('非SYD固件,请选择正确的文件'.tr); + return null; + } + if (header != 'SYD-BIN-DATA') { + showToast('非SYD固件,请选择正确的文件'.tr); + return null; + } + // 解析元数据长度 + Uint8List metaLenList; + int metaLen; + try { + metaLenList = data.sublist(12, 16); + metaLen = ByteData.sublistView(metaLenList).getUint32(0); + } catch (e) { + showToast('文件校验失败 0x01'.tr); + return null; + } + if (metaLen < 2 || metaLen > 10240) { + showToast('文件校验失败 0x01'.tr); + return null; + } + // 读取和解析元数据 + Uint8List metaStrList; + String metaStr; + try { + metaStrList = data.sublist(16, 16 + metaLen); + metaStr = utf8.decode(metaStrList); + } catch (e) { + showToast('解析元数据失败,请选择正确的文件'.tr); + return null; + } + AppLog.log(metaStr); + var meta = jsonDecode(metaStr); + if (meta is! Map) { + showToast('解析元数据失败,请选择正确的文件'.tr); + return null; + } + return meta..['metaLen'] = metaLen; + } + + //检测升级文件并读取 bin + Future checkFile(Uint8List data, Map meta) async { + num binOffset = 16 + (meta['metaLen'] ?? 0); + // 获取固件数据部分 + Uint8List bin = data.sublist(binOffset.toInt(), data.length); + //md5 校验有问题,暂时不解析 + String md5Str = md5.convert(bin).toString().toUpperCase(); + AppLog.log('---> $md5Str ${meta['fwMd5']}'); + if (md5Str != meta['fwMd5']) { + showToast('文件校验失败 0x02'.tr); + return null; + } + if (bin.length != meta['fwSize']) { + showToast('文件校验失败 0x03'.tr); + return null; + } + return bin; + } + @override void onReady() { - // TODO: implement onReady super.onReady(); - _initReplySubscription(); - // _scanListDiscoveredDeviceSubscriptionAction(); - state.ifCurrentScreen.value = true; - startScanBlueList(); } @override void onInit() { - // TODO: implement onInit super.onInit(); } @override void onClose() { - // TODO: implement onClose super.onClose(); - _replySubscription.cancel(); - // _scanListDiscoveredDeviceSubscription.cancel(); + _replySubscription?.cancel(); } } diff --git a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_page.dart b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_page.dart index a474bc92..3740694b 100644 --- a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_page.dart +++ b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_page.dart @@ -23,12 +23,6 @@ class _NearbyLockPageState extends State with RouteAware { final logic = Get.put(NearbyLockLogic()); final state = Get.find().state; - @override - void initState() { - // TODO: implement initState - super.initState(); - } - @override Widget build(BuildContext context) { return Scaffold( @@ -60,32 +54,62 @@ class _NearbyLockPageState extends State with RouteAware { ]), ), body: Obx(() { - return ListView.separated( - itemCount: state.devices.length, - itemBuilder: (c, index) { - return nearbyLockItem( - 'images/icon_lockGroup_item.png', state.devices[index], () { - // Navigator.pushNamed(context, Routers.lockAddressPage); - // logic.getPublicKey(state.devices[index].serviceUuids[0].toString()); - state.selectLockName.value = - state.devices[index].advertisementData.advName; - logic.connect(state.devices[index].advertisementData.advName); - // Get.toNamed(Routers.lockAddressGaoDePage); - }); - }, - separatorBuilder: (BuildContext context, int index) { - return Divider( - height: 1, - color: AppColors.greyLineColor, - indent: 20.w, - endIndent: 0, - ); - }, - ); + return listView(); }), ); } + Widget listView() { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: ListView.separated( + itemCount: state.devices.length, + itemBuilder: (c, index) { + return nearbyLockItem( + 'images/icon_lockGroup_item.png', state.devices[index], () { + String advName = state.devices[index].advertisementData.advName; + state.selectLockName.value = advName; + if (state.otaState.value) { + logic.oTAUpgrade(advName); + } else { + logic.connect(advName); + } + }); + }, + separatorBuilder: (BuildContext context, int index) { + return Divider( + height: 1, + color: AppColors.greyLineColor, + indent: 20.w, + endIndent: 0, + ); + }, + ), + ), + Padding( + padding: EdgeInsets.only(left: 15.w, bottom: 10.h), + child: TextButton( + onPressed: () async { + bool skip = false; + if (!state.otaState.value) { + skip = await Get.dialog( + const _TipDialog(), + ); + } + state.otaState.value = skip; + }, + child: Text( + state.otaState.value ? '点击返回设备配对'.tr : '无法连接?尝试升级'.tr, + style: TextStyle(fontSize: 22.sp), + ), + ), + ), + ], + ); + } + Widget nearbyLockItem( String lockTypeIcon, ScanResult scanResult, Function() action) { return GestureDetector( @@ -97,7 +121,6 @@ class _NearbyLockPageState extends State with RouteAware { ? action : null, child: Column( - // mainAxisAlignment: MainAxisAlignment.center, children: [ Container( height: 89.h, @@ -141,9 +164,12 @@ class _NearbyLockPageState extends State with RouteAware { ), Expanded(child: SizedBox(width: 20.w)), Image.asset( - 'images/main/icon_main_addLock.png', + state.otaState.value + ? 'images/ota_upgrade_icon.png' + : 'images/main/icon_main_addLock.png', width: 36.w, height: 36.w, + color: AppColors.mainColor, ), SizedBox(width: 30.w), ], @@ -156,7 +182,6 @@ class _NearbyLockPageState extends State with RouteAware { @override void didChangeDependencies() { - // TODO: implement didChangeDependencies super.didChangeDependencies(); /// 路由订阅 @@ -165,7 +190,6 @@ class _NearbyLockPageState extends State with RouteAware { @override void dispose() { - // TODO: implement dispose /// 取消路由订阅 AppRouteObserver().routeObserver.unsubscribe(this); super.dispose(); @@ -183,11 +207,9 @@ class _NearbyLockPageState extends State with RouteAware { super.didPop(); EasyLoading.isShow ? EasyLoading.dismiss() : null; - state.ifCurrentScreen.value = false; logic.cancelBlueConnetctToastTimer(); logic.stopScanBlueList(); - BlueManage().disconnect(); } /// 从下级返回 当前界面即将出现 @@ -203,10 +225,88 @@ class _NearbyLockPageState extends State with RouteAware { @override void didPushNext() { super.didPushNext(); - - state.ifCurrentScreen.value = false; - logic.cancelBlueConnetctToastTimer(); - logic.stopScanBlueList(); - BlueManage().disconnect(); + if (!logic.state.otaState.value) { + state.ifCurrentScreen.value = false; + logic.cancelBlueConnetctToastTimer(); + logic.stopScanBlueList(); + } + } +} + +class _TipDialog extends StatelessWidget { + const _TipDialog({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return CupertinoAlertDialog( + title: Text( + '固件升级提示'.tr, + ), + content: Text('请先获取固件文件到手机本地,再选择升级'.tr), + actions: [ + TextButton( + onPressed: () { + Get.back(); + }, + child: Text( + '取消'.tr, + style: TextStyle(fontSize: 22.sp, color: AppColors.blackColor), + ), + ), + TextButton( + onPressed: () async { + Get.back(result: true); + }, + child: Text( + '确定'.tr, + style: TextStyle(fontSize: 22.sp, color: AppColors.blackColor), + ), + ), + ], + ); + } +} + +class OTAProgressDialog extends StatelessWidget { + NearbyLockLogic logic; + + OTAProgressDialog({required this.logic, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Obx(() { + return CupertinoAlertDialog( + title: Text( + '固件升级中'.tr, + ), + content: Row( + children: [ + Text( + '传输中'.tr, + style: TextStyle(fontSize: 22.sp, color: AppColors.mainColor), + ), + SizedBox( + width: 15.w, + ), + Expanded( + child: LinearProgressIndicator( + value: logic.state.otaProgress.value, + color: AppColors.mainColor, + )), + ], + ), + actions: [ + TextButton( + onPressed: () { + logic.closeOTADAta(); + }, + child: Text( + '取消升级'.tr, + style: TextStyle(fontSize: 22.sp, color: AppColors.blackColor), + ), + ), + ], + ); + }); } } diff --git a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_state.dart b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_state.dart index 4e7d61c2..82a63f33 100644 --- a/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_state.dart +++ b/star_lock/lib/mine/addLock/nearbyLock/nearbyLock_state.dart @@ -1,9 +1,7 @@ - import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:get/get.dart'; class NearbyLockState { - RxList devices = [].obs; var ifCurrentScreen = true.obs; // 是否是当前界面,用于判断是否需要针对当前界面进行展示 // var sureBtnState = 0.obs;// 0可点击 1 不可点击 @@ -16,4 +14,8 @@ class NearbyLockState { var featureSettingValue = ''; var featureSettingParams = []; + var otaState = false.obs; //ota 升级 + var otaUpdateIng = false.obs; + var otaProgress = 0.00.obs; + bool oTAProgressDialog = false; } diff --git a/star_lock/pubspec.yaml b/star_lock/pubspec.yaml index 71d1dd87..8ea7e109 100644 --- a/star_lock/pubspec.yaml +++ b/star_lock/pubspec.yaml @@ -99,7 +99,7 @@ dependencies: url_launcher: ^6.1.10 #蓝牙 # flutter_reactive_ble: ^5.1.1 - flutter_blue_plus: ^1.31.16 + flutter_blue_plus: 1.31.16 # event_bus: ^2.0.0 #菊花