feat:完成 ota 升级调用,优化蓝牙传输速度
This commit is contained in:
parent
c505fcd2f3
commit
ad4f6c286f
@ -769,7 +769,7 @@
|
||||
"异常警告":"Abnormal warning",
|
||||
"短信提醒":"SMS reminder",
|
||||
"邮件提醒":"Email reminder",
|
||||
"关锁":"关锁",
|
||||
"功能":"功能",
|
||||
"配件":"配件"
|
||||
"关锁":"close lock",
|
||||
"功能":"function",
|
||||
"配件":"parts"
|
||||
}
|
||||
|
||||
@ -41,7 +41,41 @@ PODS:
|
||||
- ReachabilitySwift
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- DKImagePickerController/Core (4.3.8):
|
||||
- DKImagePickerController/ImageDataManager
|
||||
- DKImagePickerController/Resource
|
||||
- DKImagePickerController/ImageDataManager (4.3.8)
|
||||
- DKImagePickerController/PhotoGallery (4.3.8):
|
||||
- DKImagePickerController/Core
|
||||
- DKPhotoGallery
|
||||
- DKImagePickerController/Resource (4.3.8)
|
||||
- DKPhotoGallery (0.0.17):
|
||||
- DKPhotoGallery/Core (= 0.0.17)
|
||||
- DKPhotoGallery/Model (= 0.0.17)
|
||||
- DKPhotoGallery/Preview (= 0.0.17)
|
||||
- DKPhotoGallery/Resource (= 0.0.17)
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Core (0.0.17):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Preview
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Model (0.0.17):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Preview (0.0.17):
|
||||
- DKPhotoGallery/Model
|
||||
- DKPhotoGallery/Resource
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- DKPhotoGallery/Resource (0.0.17):
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- EMASRest (11.1.1.2)
|
||||
- file_picker (0.0.1):
|
||||
- DKImagePickerController/PhotoGallery
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
- flutter_blue_plus (0.0.1):
|
||||
- Flutter
|
||||
@ -95,12 +129,16 @@ PODS:
|
||||
- permission_handler_apple (9.3.0):
|
||||
- Flutter
|
||||
- ReachabilitySwift (5.2.2)
|
||||
- SDWebImage (5.19.1):
|
||||
- SDWebImage/Core (= 5.19.1)
|
||||
- SDWebImage/Core (5.19.1)
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- sqflite (0.0.3):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- SwiftyGif (5.4.5)
|
||||
- system_settings (0.0.1):
|
||||
- Flutter
|
||||
- Toast (4.1.1)
|
||||
@ -126,6 +164,7 @@ DEPENDENCIES:
|
||||
- camera_avfoundation (from `.symlinks/plugins/camera_avfoundation/ios`)
|
||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- file_picker (from `.symlinks/plugins/file_picker/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_blue_plus (from `.symlinks/plugins/flutter_blue_plus/ios`)
|
||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||
@ -163,11 +202,15 @@ SPEC REPOS:
|
||||
- AMap3DMap
|
||||
- AMapFoundation
|
||||
- AMapLocation
|
||||
- DKImagePickerController
|
||||
- DKPhotoGallery
|
||||
- GoogleMaps
|
||||
- ios-voice-processor
|
||||
- JCore
|
||||
- JPush
|
||||
- ReachabilitySwift
|
||||
- SDWebImage
|
||||
- SwiftyGif
|
||||
- Toast
|
||||
- WechatOpenSDK-XCFramework
|
||||
|
||||
@ -194,6 +237,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
file_picker:
|
||||
:path: ".symlinks/plugins/file_picker/ios"
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_blue_plus:
|
||||
@ -261,7 +306,10 @@ SPEC CHECKSUMS:
|
||||
camera_avfoundation: 8b8d780bcfb6a4a02b0fbe2b4bd17b5b71946e68
|
||||
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
|
||||
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
|
||||
DKImagePickerController: a7836546cfdfe014171694f643a7d575bc8ace7f
|
||||
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
|
||||
EMASRest: 8df6f87836767a9415ad5cc4af739bc9d215b475
|
||||
file_picker: ce3938a0df3cc1ef404671531facef740d03f920
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
flutter_blue_plus: 4837da7d00cf5d441fdd6635b3a57f936778ea96
|
||||
flutter_local_notifications: 4cde75091f6327eb8517fa068a0a5950212d2086
|
||||
@ -284,8 +332,10 @@ SPEC CHECKSUMS:
|
||||
path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c
|
||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||
ReachabilitySwift: 2128f3a8c9107e1ad33574c6e58e8285d460b149
|
||||
SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb
|
||||
shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695
|
||||
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
system_settings: 8f5cdbfa72c677fc8d665b863bcc20d393d87e9d
|
||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||
url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
@ -12,7 +11,8 @@ import 'reciver_data.dart';
|
||||
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
||||
|
||||
//连接状态回调
|
||||
typedef ConnectStateCallBack = Function(BluetoothConnectionState connectionState);
|
||||
typedef ConnectStateCallBack = Function(
|
||||
BluetoothConnectionState connectionState);
|
||||
typedef ScanDevicesCallBack = Function(List<ScanResult>);
|
||||
|
||||
class BlueManage {
|
||||
@ -57,7 +57,8 @@ class BlueManage {
|
||||
ScanResult? scanResult;
|
||||
|
||||
// 监听蓝牙连接状态
|
||||
BluetoothConnectionState? bluetoothConnectionState = BluetoothConnectionState.disconnected;
|
||||
BluetoothConnectionState? bluetoothConnectionState =
|
||||
BluetoothConnectionState.disconnected;
|
||||
|
||||
BluetoothAdapterState? _adapterState = BluetoothAdapterState.unknown;
|
||||
StreamSubscription<BluetoothAdapterState>? _adapterStateStateSubscription;
|
||||
@ -80,6 +81,7 @@ class BlueManage {
|
||||
|
||||
void _initBlue() {
|
||||
Get.log("蓝牙功能初始化监听");
|
||||
FlutterBluePlus.setLogLevel(LogLevel.error, color: true);
|
||||
_initSendStreamSubscription();
|
||||
_initAdapterStateStateSubscription();
|
||||
// _initListenscanResults();
|
||||
@ -94,7 +96,8 @@ class BlueManage {
|
||||
}
|
||||
|
||||
void _initAdapterStateStateSubscription() {
|
||||
_adapterStateStateSubscription ??= FlutterBluePlus.adapterState.listen((state) {
|
||||
_adapterStateStateSubscription ??=
|
||||
FlutterBluePlus.adapterState.listen((state) {
|
||||
_adapterState = state;
|
||||
});
|
||||
}
|
||||
@ -142,14 +145,18 @@ class BlueManage {
|
||||
_connectionStateSubscription?.cancel();
|
||||
_connectionStateSubscription = null;
|
||||
|
||||
_connectionStateSubscription = bluetoothConnectDevice!.connectionState.listen((state) async {
|
||||
_connectionStateSubscription =
|
||||
bluetoothConnectDevice!.connectionState.listen((state) async {
|
||||
bluetoothConnectionState = state;
|
||||
print("蓝牙连接状态:$state");
|
||||
});
|
||||
}
|
||||
|
||||
void _initSendStreamSubscription() {
|
||||
_sendStreamSubscription ??= EventBusManager().eventBus!.on<EventSendModel>().listen((EventSendModel model) {
|
||||
_sendStreamSubscription ??= EventBusManager()
|
||||
.eventBus!
|
||||
.on<EventSendModel>()
|
||||
.listen((EventSendModel model) {
|
||||
if (model.sendChannel == DataChannel.ble) {
|
||||
FlutterBluePlus.isSupported.then((isAvailable) async {
|
||||
if (isAvailable) {
|
||||
@ -157,9 +164,7 @@ class BlueManage {
|
||||
// 蓝牙已开启,可以进行蓝牙操作
|
||||
writeCharacteristicWithResponse(model.data);
|
||||
} else {
|
||||
try {
|
||||
|
||||
} catch (e) {
|
||||
try {} catch (e) {
|
||||
print("Error Turning On:");
|
||||
}
|
||||
}
|
||||
@ -172,7 +177,8 @@ class BlueManage {
|
||||
}
|
||||
|
||||
/// 开始指定设备名称的扫描蓝牙设备
|
||||
Future<void> startScanSingle(String deviceName, int timeout, ScanDevicesCallBack scanDevicesCallBack) async {
|
||||
Future<void> startScanSingle(String deviceName, int timeout,
|
||||
ScanDevicesCallBack scanDevicesCallBack) async {
|
||||
FlutterBluePlus.isSupported.then((isAvailable) async {
|
||||
if (isAvailable) {
|
||||
if (_adapterState == BluetoothAdapterState.on) {
|
||||
@ -180,8 +186,10 @@ class BlueManage {
|
||||
FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
|
||||
Completer<dynamic> completer = Completer<dynamic>();
|
||||
var subscription = FlutterBluePlus.scanResults.listen((results) {
|
||||
print("startScanSingle扫描到的设备:$results");
|
||||
bool isExit = results.any((element) => (element.device.platformName == deviceName) || (element.advertisementData.advName == deviceName));
|
||||
// print("startScanSingle扫描到的设备:$results");
|
||||
bool isExit = results.any((element) =>
|
||||
(element.device.platformName == deviceName) ||
|
||||
(element.advertisementData.advName == deviceName));
|
||||
if (isExit) {
|
||||
for (var scanResult in results) {
|
||||
if (((scanResult.advertisementData.serviceUuids.isNotEmpty
|
||||
@ -191,8 +199,11 @@ class BlueManage {
|
||||
.contains("758824")) &&
|
||||
(scanResult.rssi >= -100)) {
|
||||
// 查询id相同的元素
|
||||
final knownDeviceIndex = scanDevices
|
||||
.indexWhere((d) => (d.device.platformName == scanResult.device.platformName) || (d.advertisementData.advName == scanResult.advertisementData.advName));
|
||||
final knownDeviceIndex = scanDevices.indexWhere((d) =>
|
||||
(d.device.platformName ==
|
||||
scanResult.device.platformName) ||
|
||||
(d.advertisementData.advName ==
|
||||
scanResult.advertisementData.advName));
|
||||
// 不存在的时候返回-1
|
||||
if (knownDeviceIndex >= 0) {
|
||||
scanDevices[knownDeviceIndex] = scanResult;
|
||||
@ -231,7 +242,8 @@ class BlueManage {
|
||||
}
|
||||
|
||||
/// 开始扫描蓝牙设备
|
||||
Future<void> startScan(int timeout, ScanDevicesCallBack scanDevicesCallBack, {List<Guid>? idList}) async {
|
||||
Future<void> startScan(int timeout, ScanDevicesCallBack scanDevicesCallBack,
|
||||
{List<Guid>? idList}) async {
|
||||
FlutterBluePlus.isSupported.then((isAvailable) async {
|
||||
if (isAvailable) {
|
||||
if (_adapterState == BluetoothAdapterState.on) {
|
||||
@ -255,8 +267,11 @@ class BlueManage {
|
||||
.contains("758824")) &&
|
||||
(scanResult.rssi >= -100)) {
|
||||
// 查询id相同的元素
|
||||
final knownDeviceIndex = scanDevices
|
||||
.indexWhere((d) => (d.device.platformName == scanResult.device.platformName) || (d.advertisementData.advName == scanResult.advertisementData.advName));
|
||||
final knownDeviceIndex = scanDevices.indexWhere((d) =>
|
||||
(d.device.platformName ==
|
||||
scanResult.device.platformName) ||
|
||||
(d.advertisementData.advName ==
|
||||
scanResult.advertisementData.advName));
|
||||
// 不存在的时候返回-1
|
||||
if (knownDeviceIndex >= 0) {
|
||||
scanDevices[knownDeviceIndex] = scanResult;
|
||||
@ -294,7 +309,9 @@ class BlueManage {
|
||||
}
|
||||
|
||||
/// 调用发送数据 List senderData,
|
||||
Future<void> bludSendData(String deviceName, ConnectStateCallBack stateCallBack, {bool isAddEquipment = false}) async {
|
||||
Future<void> bludSendData(
|
||||
String deviceName, ConnectStateCallBack stateCallBack,
|
||||
{bool isAddEquipment = false}) async {
|
||||
FlutterBluePlus.isSupported.then((isAvailable) async {
|
||||
if (isAvailable) {
|
||||
if (_adapterState == BluetoothAdapterState.on) {
|
||||
@ -321,33 +338,43 @@ class BlueManage {
|
||||
}
|
||||
|
||||
/// 连接
|
||||
Future<void> _connect(String deviceName, ConnectStateCallBack connectStateCallBack,
|
||||
Future<void> _connect(
|
||||
String deviceName, ConnectStateCallBack connectStateCallBack,
|
||||
{bool isAddEquipment = false}) async {
|
||||
connectDeviceName = deviceName;
|
||||
List<ScanResult> devicesList = scanDevices;
|
||||
//判断列表里面有设备则不开启扫描
|
||||
bool isExistDevice = scanDevices.any((element) => element.device.platformName == connectDeviceName || element.advertisementData.advName == connectDeviceName);
|
||||
bool isExistDevice = scanDevices.any((element) =>
|
||||
element.device.platformName == connectDeviceName ||
|
||||
element.advertisementData.advName == connectDeviceName);
|
||||
if (isAddEquipment == false && isExistDevice == false) {
|
||||
// startScan(10, (scanDevices){
|
||||
startScanSingle(deviceName, 10, (List<ScanResult> scanDevices) {
|
||||
print("扫描到的设备:$scanDevices");
|
||||
devicesList = scanDevices;
|
||||
_connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment);
|
||||
_connectDevice(devicesList, deviceName, connectStateCallBack,
|
||||
isAddEquipment: isAddEquipment);
|
||||
});
|
||||
} else {
|
||||
_connectDevice(devicesList, deviceName, connectStateCallBack, isAddEquipment: isAddEquipment);
|
||||
_connectDevice(devicesList, deviceName, connectStateCallBack,
|
||||
isAddEquipment: isAddEquipment);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _connectDevice(
|
||||
List<ScanResult> devicesList, String deviceName, ConnectStateCallBack connectStateCallBack,
|
||||
Future<void> _connectDevice(List<ScanResult> devicesList, String deviceName,
|
||||
ConnectStateCallBack connectStateCallBack,
|
||||
{bool isAddEquipment = false}) async {
|
||||
// 判断数组列表里面是否有这个设备
|
||||
print("devicesList:$devicesList");
|
||||
final knownDeviceIndex = devicesList.indexWhere((d) => (d.device.platformName == deviceName) || (d.advertisementData.advName == deviceName));
|
||||
final knownDeviceIndex = devicesList.indexWhere((d) =>
|
||||
(d.device.platformName == deviceName) ||
|
||||
(d.advertisementData.advName == deviceName));
|
||||
if (knownDeviceIndex >= 0) {
|
||||
// 存在的时候赋值
|
||||
connectDeviceMacAddress = devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty ? devicesList[knownDeviceIndex].advertisementData.advName : devicesList[knownDeviceIndex].device.platformName;
|
||||
connectDeviceMacAddress =
|
||||
devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty
|
||||
? devicesList[knownDeviceIndex].advertisementData.advName
|
||||
: devicesList[knownDeviceIndex].device.platformName;
|
||||
|
||||
bluetoothConnectDevice = devicesList[knownDeviceIndex].device;
|
||||
print('bluetoothConnectDevice: $bluetoothConnectDevice');
|
||||
@ -356,7 +383,8 @@ class BlueManage {
|
||||
_initGetMtuSubscription();
|
||||
_initListenConnectionState();
|
||||
}
|
||||
print("1 connectDeviceId:$connectDeviceMacAddress connectDeviceName:$connectDeviceName");
|
||||
print(
|
||||
"1 connectDeviceId:$connectDeviceMacAddress connectDeviceName:$connectDeviceName");
|
||||
// stopScan();
|
||||
if (connectDeviceMacAddress.isEmpty) {
|
||||
// connectStateCallBack(BluetoothConnectionState.disconnected!);
|
||||
@ -366,7 +394,8 @@ class BlueManage {
|
||||
print("调用了停止扫描的方法");
|
||||
await stopScan();
|
||||
|
||||
if ((scanResult!.advertisementData.serviceUuids[0].toString()[31] == "0") && isAddEquipment == false) {
|
||||
if ((scanResult!.advertisementData.serviceUuids[0].toString()[31] == "0") &&
|
||||
isAddEquipment == false) {
|
||||
connectStateCallBack(BluetoothConnectionState.disconnected);
|
||||
EasyLoading.showToast("该锁已被重置", duration: 2000.milliseconds);
|
||||
return;
|
||||
@ -403,12 +432,14 @@ class BlueManage {
|
||||
" service.characteristics:${service.characteristics}"
|
||||
" service.includedServices:${service.includedServices}");
|
||||
if (service.uuid == _serviceIdConnect) {
|
||||
for (BluetoothCharacteristic characteristic in service.characteristics) {
|
||||
for (BluetoothCharacteristic characteristic
|
||||
in service.characteristics) {
|
||||
// Get.log("22222characteristic.remoteId:${characteristic.remoteId}"
|
||||
// " characteristic.uuid:${characteristic.uuid}"
|
||||
// " characteristic.secondaryServiceUuid:${characteristic.secondaryServiceUuid}"
|
||||
// " characteristic.characteristicUuid:${characteristic.characteristicUuid}");
|
||||
if (characteristic.characteristicUuid == _characteristicIdSubscription) {
|
||||
if (characteristic.characteristicUuid ==
|
||||
_characteristicIdSubscription) {
|
||||
_subScribeToCharacteristic(characteristic);
|
||||
print('Discovering services finished');
|
||||
bluetoothConnectionState = BluetoothConnectionState.connected;
|
||||
@ -446,18 +477,21 @@ class BlueManage {
|
||||
}
|
||||
// code to handle incoming data
|
||||
// print("subscribeToCharacteristic: deviceId = ${characteristic.deviceId} characteristicId =${characteristic.characteristicId}---上报来的数据data = $data");
|
||||
if ((data[0] == 0xEF) && (data[1] == 0x01) && (data[2] == 0xEE) && (data[3] == 0x02)) {
|
||||
if ((data[0] == 0xEF) &&
|
||||
(data[1] == 0x01) &&
|
||||
(data[2] == 0xEE) &&
|
||||
(data[3] == 0x02)) {
|
||||
// 当包有头时
|
||||
// 判断是否需要分包
|
||||
dataLen = data[8] * 256 + data[9]; // 高16位用来指示后面数据块内容的长度
|
||||
print("dataLen1111:$dataLen getDataLength:${data.length} data:$data");
|
||||
// print("dataLen1111:$dataLen getDataLength:${data.length} data:$data");
|
||||
if (dataLen! + 12 > data.length) {
|
||||
// 当前包的长度小于实际的包时 分包添加 不解析
|
||||
allData.addAll(data);
|
||||
} else {
|
||||
// 当前包的长度小于实际的包时 不分包 解析
|
||||
allData.addAll(data);
|
||||
print("dataLen2222:$dataLen getDataLength:${data.length}");
|
||||
// print("dataLen2222:$dataLen getDataLength:${data.length}");
|
||||
CommandReciverManager.appDataReceive(allData);
|
||||
// 发送完解析初始化数组
|
||||
allData = <int>[];
|
||||
@ -466,7 +500,8 @@ class BlueManage {
|
||||
// 当包没有头时 是分包的包 直接添加
|
||||
allData.addAll(data);
|
||||
// var len = allData[8] * 256 + allData[9];
|
||||
print("dataLen3333:$dataLen allData.length:${allData.length} allData:$allData");
|
||||
print(
|
||||
"dataLen3333:$dataLen allData.length:${allData.length} allData:$allData");
|
||||
if ((dataLen! + 14) <= allData.length) {
|
||||
print("44444数据被解析了");
|
||||
// 当长度小于等于当前包的数据时 直接解析数据
|
||||
@ -530,44 +565,44 @@ class BlueManage {
|
||||
|
||||
// 写入
|
||||
Future<void> writeCharacteristicWithResponse(List<int> value) async {
|
||||
bluetoothConnectDevice!.discoverServices().then((services) async {
|
||||
for (BluetoothService service in services) {
|
||||
// print("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) {
|
||||
// print("44444 characteristic.remoteId:${characteristic.remoteId}"
|
||||
// " characteristic.uuid:${characteristic.uuid}\n\n"
|
||||
// " characteristic.secondaryServiceUuid:${characteristic
|
||||
// .secondaryServiceUuid}\n\n"
|
||||
// " characteristic.characteristicUuid:${characteristic
|
||||
// .characteristicUuid}");
|
||||
if (characteristic.characteristicUuid == _characteristicIdWrite) {
|
||||
try {
|
||||
List<int> valueList = value;
|
||||
List subData = splitList(valueList, _mtuSize!);
|
||||
print('writeCharacteristicWithResponse _mtuSize:$_mtuSize 得到的分割数据:$subData');
|
||||
|
||||
for (int i = 0; i < subData.length; i++) {
|
||||
await characteristic.write(subData[i]).then((value) async {
|
||||
await Future.delayed(const Duration(milliseconds: 1)).then((
|
||||
value) async {
|
||||
print('分包发送成功了');
|
||||
});
|
||||
});
|
||||
}
|
||||
} on Exception catch (e, s) {
|
||||
print('Error occurred when writing: $e');
|
||||
// Get.log(s);
|
||||
rethrow;
|
||||
List<BluetoothService> services =
|
||||
await bluetoothConnectDevice!.discoverServices();
|
||||
for (BluetoothService service in services) {
|
||||
// print("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) {
|
||||
// print("44444 characteristic.remoteId:${characteristic.remoteId}"
|
||||
// " characteristic.uuid:${characteristic.uuid}\n\n"
|
||||
// " characteristic.secondaryServiceUuid:${characteristic
|
||||
// .secondaryServiceUuid}\n\n"
|
||||
// " characteristic.characteristicUuid:${characteristic
|
||||
// .characteristicUuid}");
|
||||
if (characteristic.characteristicUuid == _characteristicIdWrite) {
|
||||
try {
|
||||
List<int> valueList = value;
|
||||
List subData = splitList(valueList, _mtuSize!);
|
||||
// print('writeCharacteristicWithResponse _mtuSize:$_mtuSize 得到的分割数据:$subData');
|
||||
for (int i = 0; i < subData.length; i++) {
|
||||
await characteristic.write(subData[i],withoutResponse: true).then((value) async {
|
||||
// await Future.delayed(const Duration(milliseconds: 1)).then((
|
||||
// value) async {
|
||||
// print('分包发送成功了');
|
||||
// });
|
||||
});
|
||||
}
|
||||
} on Exception catch (e, s) {
|
||||
print('Error occurred when writing: $e');
|
||||
// Get.log(s);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// List<BluetoothService> services = await bluetoothConnectDevice!.discoverServices();
|
||||
// BluetoothCharacteristic characteristic = services
|
||||
// .firstWhere((service) => service.uuid == _serviceIdWrite)
|
||||
|
||||
149
star_lock/lib/blue/io_protocol/io_otaUpgrade.dart
Normal file
149
star_lock/lib/blue/io_protocol/io_otaUpgrade.dart
Normal file
@ -0,0 +1,149 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_type.dart';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
//oat升级
|
||||
class OTAUpgradeCommand extends SenderProtocol {
|
||||
String? lockID;
|
||||
String? userID;
|
||||
String? keyID;
|
||||
int? platform;
|
||||
int? product;
|
||||
String? hwVersion;
|
||||
String? fwVersion;
|
||||
int? fwSize;
|
||||
String? fwMD5;
|
||||
int? needAuthor;
|
||||
List<int>? publicKey;
|
||||
List<int>? privateKey;
|
||||
List<int>? token;
|
||||
|
||||
OTAUpgradeCommand(
|
||||
{this.lockID,
|
||||
this.userID,
|
||||
this.keyID,
|
||||
this.platform,
|
||||
this.product,
|
||||
this.hwVersion,
|
||||
this.fwVersion,
|
||||
this.fwSize,
|
||||
this.fwMD5,
|
||||
this.needAuthor,
|
||||
this.publicKey,
|
||||
this.privateKey,
|
||||
this.token})
|
||||
: super(CommandType.startOATUpgrade);
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = [];
|
||||
List<int> ebcData = [];
|
||||
|
||||
// 指令类型
|
||||
int type = commandType!.typeValue;
|
||||
double typeDouble = type / 256;
|
||||
int type1 = typeDouble.toInt();
|
||||
int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
// 锁id 40
|
||||
int lockIDLength = utf8.encode(lockID!).length;
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//userID 20
|
||||
int userIDLength = utf8.encode(userID!).length;
|
||||
data.addAll(utf8.encode(userID!));
|
||||
data = getFixedLengthList(data, 20 - userIDLength);
|
||||
|
||||
//platform 2
|
||||
int platform0 = (platform! & 0xFF00) >> 8;
|
||||
int platform1 = platform! & 0xFF;
|
||||
data.add(platform0);
|
||||
data.add(platform1);
|
||||
|
||||
//product 2
|
||||
int product0 = (product! & 0xFF00) >> 8;
|
||||
int product1 = product! & 0xFF;
|
||||
data.add(product0);
|
||||
data.add(product1);
|
||||
|
||||
//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<int> byteList = bytes.buffer.asUint8List();
|
||||
data.addAll(byteList);
|
||||
|
||||
//fwMD5 16
|
||||
int fwMD5Length = utf8.encode(fwMD5!).length;
|
||||
data.addAll(utf8.encode(fwMD5!));
|
||||
data = getFixedLengthList(data, 16 - fwMD5Length);
|
||||
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
|
||||
if (needAuthor == 0) {
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
|
||||
//authUserID
|
||||
authCodeData.addAll(utf8.encode(userID!));
|
||||
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(keyID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token!);
|
||||
|
||||
authCodeData.addAll(publicKey!);
|
||||
|
||||
// 把KeyID、authUserID、时间戳、公钥通过md5加密之后就是authCode
|
||||
var authCode = crypto.md5.convert(authCodeData);
|
||||
|
||||
data.add(authCode.bytes.length);
|
||||
data.addAll(authCode.bytes);
|
||||
}
|
||||
|
||||
if ((data.length % 16) != 0) {
|
||||
int add = (16 - data.length % 16);
|
||||
for (int i = 0; i < add; i++) {
|
||||
data.add(0);
|
||||
}
|
||||
}
|
||||
|
||||
Get.log("${commandType!.typeName} SM4Data:$data");
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
}
|
||||
}
|
||||
|
||||
class OTAUpgradeReply extends Reply {
|
||||
OTAUpgradeReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
int status = data[6];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
74
star_lock/lib/blue/io_protocol/io_processOtaUpgrade.dart
Normal file
74
star_lock/lib/blue/io_protocol/io_processOtaUpgrade.dart
Normal file
@ -0,0 +1,74 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
import '../io_reply.dart';
|
||||
import '../io_sender.dart';
|
||||
import '../io_type.dart';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
//oat升级
|
||||
class ProcessOtaUpgradeCommand extends SenderProtocol {
|
||||
int? index;
|
||||
int? size;
|
||||
List<int>? data;
|
||||
|
||||
ProcessOtaUpgradeCommand({
|
||||
this.index,
|
||||
this.size,
|
||||
this.data,
|
||||
}) : super(CommandType.processOTAUpgrade);
|
||||
|
||||
@override
|
||||
List<int> messageDetail() {
|
||||
List<int> data = [];
|
||||
|
||||
// 指令类型
|
||||
int type = commandType!.typeValue;
|
||||
double typeDouble = type / 256;
|
||||
int type1 = typeDouble.toInt();
|
||||
int type2 = type % 256;
|
||||
data.add(type1);
|
||||
data.add(type2);
|
||||
|
||||
//index 2
|
||||
ByteData indexBytes = ByteData(2); // 创建一个长度为4的字节数据
|
||||
indexBytes.setInt16(0, index!);
|
||||
List<int> indexList = indexBytes.buffer.asUint8List();
|
||||
data.addAll(indexList);
|
||||
|
||||
//size 2
|
||||
ByteData bytes = ByteData(2); // 创建一个长度为4的字节数据
|
||||
bytes.setInt16(0, size!);
|
||||
List<int> byteList = bytes.buffer.asUint8List();
|
||||
data.addAll(byteList);
|
||||
|
||||
data.addAll(this.data!);
|
||||
|
||||
//不加密
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class ProcessOtaUpgradeReply extends Reply {
|
||||
ProcessOtaUpgradeReply.parseData(
|
||||
CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
int status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
|
||||
class ConfirmationOTAUpgradeReply extends Reply {
|
||||
ConfirmationOTAUpgradeReply.parseData(
|
||||
CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
int status = data[2];
|
||||
errorWithStstus(status);
|
||||
}
|
||||
}
|
||||
@ -14,11 +14,11 @@ abstract class Reply{
|
||||
Reply.parseData(this.commandType, List<int> dataDetail);
|
||||
|
||||
void errorWithStstus(int status){
|
||||
Get.log("errorWithStstus status:$status commandType:$commandType");
|
||||
// Get.log("errorWithStstus status:$status commandType:$commandType");
|
||||
switch(status){
|
||||
case 0x00:
|
||||
// 成功
|
||||
Get.log("$commandType成功");
|
||||
// Get.log("$commandType成功");
|
||||
break;
|
||||
case 0x01:
|
||||
// 包格式错误
|
||||
@ -134,4 +134,9 @@ abstract class Reply{
|
||||
void showErrorMessage(String message){
|
||||
EasyLoading.showToast(message, duration: 2000.milliseconds);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Reply{commandType: $commandType, status: $status, data: $data}';
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,11 +12,17 @@ abstract class SenderProtocol extends IOData {
|
||||
// var uint8View1 = Uint8List(300);
|
||||
|
||||
CommandType? commandType; //指令类型
|
||||
final List<int> header = [0XEF, 0X01, 0XEE, 0X02]; //帧头 固定取值 0XEF01EE02,长度 4 字节
|
||||
final int ask = 0X01 ; // 包类型:0X01 表示请求包,0X11 表示应答包,长度 1 字节
|
||||
final List<int> header = [
|
||||
0XEF,
|
||||
0X01,
|
||||
0XEE,
|
||||
0X02
|
||||
]; //帧头 固定取值 0XEF01EE02,长度 4 字节
|
||||
final int ask = 0X01; // 包类型:0X01 表示请求包,0X11 表示应答包,长度 1 字节
|
||||
int? _commandIndex = 1; //包序号
|
||||
|
||||
int identifier = 0x20; // 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥)
|
||||
int identifier =
|
||||
0x20; // 高 4 位表示包版本,低 4 位用来指示后面数据的加密类型,长度为 1 字节,加密类型取值说明,0:明文,1:AES128,2:SM4(事先约定密钥),3:SM4(设备指定密钥)
|
||||
|
||||
List<int>? commandData = []; //数据块
|
||||
// final int? tail = 0xFF; //用来校验包的完整性,采用 CRC 校验方法,长度为 2 个字节
|
||||
@ -40,9 +46,9 @@ abstract class SenderProtocol extends IOData {
|
||||
|
||||
// 包序号
|
||||
int commandIndexChange = _commandIndex!;
|
||||
double commandIndexChangeDouble = commandIndexChange/256;
|
||||
double commandIndexChangeDouble = commandIndexChange / 256;
|
||||
int commandIndexChang1 = commandIndexChangeDouble.toInt();
|
||||
int commandIndexChang2 = commandIndexChange%256;
|
||||
int commandIndexChang2 = commandIndexChange % 256;
|
||||
commandList.add(commandIndexChang1);
|
||||
commandList.add(commandIndexChang2);
|
||||
// print("_commandIndex:$_commandIndex commandIndexChang1$commandIndexChang1 commandIndexChang2:$commandIndexChang2");
|
||||
@ -57,11 +63,11 @@ abstract class SenderProtocol extends IOData {
|
||||
// commandList.add(dataLength);
|
||||
// print("dataLen:$dataLen");
|
||||
// var dataLen = 42;
|
||||
double dataLength = dataLen/256;
|
||||
double dataLength = dataLen / 256;
|
||||
commandList.add(dataLength.toInt());
|
||||
commandList.add(dataLen%256);
|
||||
commandList.add(dataLen % 256);
|
||||
commandList.add(dataLength.toInt());
|
||||
commandList.add(dataLen%256);
|
||||
commandList.add(dataLen % 256);
|
||||
|
||||
// 数据块
|
||||
commandList.addAll(commandData!); //数据块
|
||||
@ -69,46 +75,284 @@ abstract class SenderProtocol extends IOData {
|
||||
|
||||
// 校验位
|
||||
var mcrc = crc_16(commandList);
|
||||
double mcrcDouble = mcrc/256;
|
||||
double mcrcDouble = mcrc / 256;
|
||||
int mcrcDouble1 = mcrcDouble.toInt();
|
||||
int mcrcDouble2 = mcrc%256;
|
||||
int mcrcDouble2 = mcrc % 256;
|
||||
commandList.add(mcrcDouble1); //帧尾
|
||||
commandList.add(mcrcDouble2);
|
||||
// print("mcrc:$mcrc");
|
||||
// print("mcrcDouble1:$mcrcDouble1");
|
||||
// print("mcrcDouble2:$mcrcDouble2");
|
||||
return commandList;
|
||||
}
|
||||
|
||||
//TODO:长度
|
||||
int dataSourceLength() => commandData!.length;
|
||||
|
||||
var crcTable =[
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0];
|
||||
var crcTable = [
|
||||
0x0000,
|
||||
0x1021,
|
||||
0x2042,
|
||||
0x3063,
|
||||
0x4084,
|
||||
0x50a5,
|
||||
0x60c6,
|
||||
0x70e7,
|
||||
0x8108,
|
||||
0x9129,
|
||||
0xa14a,
|
||||
0xb16b,
|
||||
0xc18c,
|
||||
0xd1ad,
|
||||
0xe1ce,
|
||||
0xf1ef,
|
||||
0x1231,
|
||||
0x0210,
|
||||
0x3273,
|
||||
0x2252,
|
||||
0x52b5,
|
||||
0x4294,
|
||||
0x72f7,
|
||||
0x62d6,
|
||||
0x9339,
|
||||
0x8318,
|
||||
0xb37b,
|
||||
0xa35a,
|
||||
0xd3bd,
|
||||
0xc39c,
|
||||
0xf3ff,
|
||||
0xe3de,
|
||||
0x2462,
|
||||
0x3443,
|
||||
0x0420,
|
||||
0x1401,
|
||||
0x64e6,
|
||||
0x74c7,
|
||||
0x44a4,
|
||||
0x5485,
|
||||
0xa56a,
|
||||
0xb54b,
|
||||
0x8528,
|
||||
0x9509,
|
||||
0xe5ee,
|
||||
0xf5cf,
|
||||
0xc5ac,
|
||||
0xd58d,
|
||||
0x3653,
|
||||
0x2672,
|
||||
0x1611,
|
||||
0x0630,
|
||||
0x76d7,
|
||||
0x66f6,
|
||||
0x5695,
|
||||
0x46b4,
|
||||
0xb75b,
|
||||
0xa77a,
|
||||
0x9719,
|
||||
0x8738,
|
||||
0xf7df,
|
||||
0xe7fe,
|
||||
0xd79d,
|
||||
0xc7bc,
|
||||
0x48c4,
|
||||
0x58e5,
|
||||
0x6886,
|
||||
0x78a7,
|
||||
0x0840,
|
||||
0x1861,
|
||||
0x2802,
|
||||
0x3823,
|
||||
0xc9cc,
|
||||
0xd9ed,
|
||||
0xe98e,
|
||||
0xf9af,
|
||||
0x8948,
|
||||
0x9969,
|
||||
0xa90a,
|
||||
0xb92b,
|
||||
0x5af5,
|
||||
0x4ad4,
|
||||
0x7ab7,
|
||||
0x6a96,
|
||||
0x1a71,
|
||||
0x0a50,
|
||||
0x3a33,
|
||||
0x2a12,
|
||||
0xdbfd,
|
||||
0xcbdc,
|
||||
0xfbbf,
|
||||
0xeb9e,
|
||||
0x9b79,
|
||||
0x8b58,
|
||||
0xbb3b,
|
||||
0xab1a,
|
||||
0x6ca6,
|
||||
0x7c87,
|
||||
0x4ce4,
|
||||
0x5cc5,
|
||||
0x2c22,
|
||||
0x3c03,
|
||||
0x0c60,
|
||||
0x1c41,
|
||||
0xedae,
|
||||
0xfd8f,
|
||||
0xcdec,
|
||||
0xddcd,
|
||||
0xad2a,
|
||||
0xbd0b,
|
||||
0x8d68,
|
||||
0x9d49,
|
||||
0x7e97,
|
||||
0x6eb6,
|
||||
0x5ed5,
|
||||
0x4ef4,
|
||||
0x3e13,
|
||||
0x2e32,
|
||||
0x1e51,
|
||||
0x0e70,
|
||||
0xff9f,
|
||||
0xefbe,
|
||||
0xdfdd,
|
||||
0xcffc,
|
||||
0xbf1b,
|
||||
0xaf3a,
|
||||
0x9f59,
|
||||
0x8f78,
|
||||
0x9188,
|
||||
0x81a9,
|
||||
0xb1ca,
|
||||
0xa1eb,
|
||||
0xd10c,
|
||||
0xc12d,
|
||||
0xf14e,
|
||||
0xe16f,
|
||||
0x1080,
|
||||
0x00a1,
|
||||
0x30c2,
|
||||
0x20e3,
|
||||
0x5004,
|
||||
0x4025,
|
||||
0x7046,
|
||||
0x6067,
|
||||
0x83b9,
|
||||
0x9398,
|
||||
0xa3fb,
|
||||
0xb3da,
|
||||
0xc33d,
|
||||
0xd31c,
|
||||
0xe37f,
|
||||
0xf35e,
|
||||
0x02b1,
|
||||
0x1290,
|
||||
0x22f3,
|
||||
0x32d2,
|
||||
0x4235,
|
||||
0x5214,
|
||||
0x6277,
|
||||
0x7256,
|
||||
0xb5ea,
|
||||
0xa5cb,
|
||||
0x95a8,
|
||||
0x8589,
|
||||
0xf56e,
|
||||
0xe54f,
|
||||
0xd52c,
|
||||
0xc50d,
|
||||
0x34e2,
|
||||
0x24c3,
|
||||
0x14a0,
|
||||
0x0481,
|
||||
0x7466,
|
||||
0x6447,
|
||||
0x5424,
|
||||
0x4405,
|
||||
0xa7db,
|
||||
0xb7fa,
|
||||
0x8799,
|
||||
0x97b8,
|
||||
0xe75f,
|
||||
0xf77e,
|
||||
0xc71d,
|
||||
0xd73c,
|
||||
0x26d3,
|
||||
0x36f2,
|
||||
0x0691,
|
||||
0x16b0,
|
||||
0x6657,
|
||||
0x7676,
|
||||
0x4615,
|
||||
0x5634,
|
||||
0xd94c,
|
||||
0xc96d,
|
||||
0xf90e,
|
||||
0xe92f,
|
||||
0x99c8,
|
||||
0x89e9,
|
||||
0xb98a,
|
||||
0xa9ab,
|
||||
0x5844,
|
||||
0x4865,
|
||||
0x7806,
|
||||
0x6827,
|
||||
0x18c0,
|
||||
0x08e1,
|
||||
0x3882,
|
||||
0x28a3,
|
||||
0xcb7d,
|
||||
0xdb5c,
|
||||
0xeb3f,
|
||||
0xfb1e,
|
||||
0x8bf9,
|
||||
0x9bd8,
|
||||
0xabbb,
|
||||
0xbb9a,
|
||||
0x4a75,
|
||||
0x5a54,
|
||||
0x6a37,
|
||||
0x7a16,
|
||||
0x0af1,
|
||||
0x1ad0,
|
||||
0x2ab3,
|
||||
0x3a92,
|
||||
0xfd2e,
|
||||
0xed0f,
|
||||
0xdd6c,
|
||||
0xcd4d,
|
||||
0xbdaa,
|
||||
0xad8b,
|
||||
0x9de8,
|
||||
0x8dc9,
|
||||
0x7c26,
|
||||
0x6c07,
|
||||
0x5c64,
|
||||
0x4c45,
|
||||
0x3ca2,
|
||||
0x2c83,
|
||||
0x1ce0,
|
||||
0x0cc1,
|
||||
0xef1f,
|
||||
0xff3e,
|
||||
0xcf5d,
|
||||
0xdf7c,
|
||||
0xaf9b,
|
||||
0xbfba,
|
||||
0x8fd9,
|
||||
0x9ff8,
|
||||
0x6e17,
|
||||
0x7e36,
|
||||
0x4e55,
|
||||
0x5e74,
|
||||
0x2e93,
|
||||
0x3eb2,
|
||||
0x0ed1,
|
||||
0x1ef0
|
||||
];
|
||||
|
||||
int crc_16(buffer) {
|
||||
var len = buffer.length;
|
||||
var value_ = 0x0000;//0xa635; //初始值,根据CRC类型设定
|
||||
var value_ = 0x0000; //0xa635; //初始值,根据CRC类型设定
|
||||
var tmp;
|
||||
for (var i = 0; i < buffer.length; i++)
|
||||
{
|
||||
for (var i = 0; i < buffer.length; i++) {
|
||||
tmp = reverse8(buffer[i]);
|
||||
value_ = ((value_ << 8) ^ crcTable[((value_ >> 8) ^ tmp) & 0xFF]) & 0xFFFF;
|
||||
value_ =
|
||||
((value_ << 8) ^ crcTable[((value_ >> 8) ^ tmp) & 0xFF]) & 0xFFFF;
|
||||
}
|
||||
value_ = reverse16(value_);
|
||||
return value_;
|
||||
@ -116,22 +360,21 @@ abstract class SenderProtocol extends IOData {
|
||||
|
||||
int reverse8(data) {
|
||||
var i;
|
||||
var temp=0;
|
||||
for(i=0;i<8;i++) {
|
||||
var temp = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
//字节反转
|
||||
temp |= ((data>>i) & 0x01)<<(7-i);
|
||||
temp |= ((data >> i) & 0x01) << (7 - i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
int reverse16(data) {
|
||||
var i;
|
||||
var temp=0;
|
||||
for(i=0;i<16;i++) {
|
||||
var temp = 0;
|
||||
for (i = 0; i < 16; i++) {
|
||||
//反转
|
||||
temp |= ((data>>i) & 0x0001)<<(15-i);
|
||||
temp |= ((data >> i) & 0x0001) << (15 - i);
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
///发送数据类
|
||||
enum DataChannel{
|
||||
ble,
|
||||
udp
|
||||
}
|
||||
enum DataChannel { ble, udp }
|
||||
|
||||
extension Extension on DataChannel {
|
||||
bool get isBLE => this == DataChannel.ble;
|
||||
bool get isUDP => this == DataChannel.udp;
|
||||
bool get isBLE => this == DataChannel.ble;
|
||||
|
||||
bool get isUDP => this == DataChannel.udp;
|
||||
}
|
||||
|
||||
class EventSendModel {
|
||||
@ -20,8 +17,16 @@ class EventSendModel {
|
||||
String? deviceId;
|
||||
Uuid? serviceId;
|
||||
Uuid? characteristicId;
|
||||
bool? allowLongWrite = false;
|
||||
|
||||
EventSendModel({required this.data,this.topic,this.sendChannel, this.deviceId, this.serviceId, this.characteristicId});
|
||||
EventSendModel(
|
||||
{required this.data,
|
||||
this.topic,
|
||||
this.sendChannel,
|
||||
this.deviceId,
|
||||
this.serviceId,
|
||||
this.characteristicId,
|
||||
this.allowLongWrite});
|
||||
}
|
||||
|
||||
///接收数据类
|
||||
@ -30,26 +35,23 @@ class EventReceiveModel {
|
||||
String? tag = '';
|
||||
DataChannel? sendChannel;
|
||||
|
||||
EventReceiveModel({
|
||||
required this.data,
|
||||
this.sendChannel,
|
||||
this.tag});
|
||||
EventReceiveModel({required this.data, this.sendChannel, this.tag});
|
||||
}
|
||||
|
||||
|
||||
///解析数据域
|
||||
class EventParseModel {
|
||||
int? type;
|
||||
int? commandIndex;
|
||||
dynamic data;
|
||||
|
||||
EventParseModel({required this.type, required this.data, this.commandIndex});
|
||||
}
|
||||
|
||||
|
||||
///debug info model
|
||||
class StateModel {
|
||||
final String title;
|
||||
final String subTitle;
|
||||
final bool result;
|
||||
StateModel({this.title= '',this.subTitle = '',this.result = false});
|
||||
}
|
||||
|
||||
StateModel({this.title = '', this.subTitle = '', this.result = false});
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
//TODO:发送指令类型
|
||||
enum CommandType {
|
||||
addUser, //增加用户 = 0x3001
|
||||
@ -13,6 +12,9 @@ enum CommandType {
|
||||
getLockPrivateKey, // 获取锁私钥 = 0x3091
|
||||
calibrationTime, // 校时 = 0x30f0
|
||||
readStarLockStatusInfo, //读星锁状态信息 0x3040
|
||||
startOATUpgrade, //OTA升级开始 0x30E0
|
||||
confirmationOTAUpgrade, //OTA升级开始 0x30E1
|
||||
processOTAUpgrade, //OTA升级过程 0x30E2
|
||||
|
||||
generalExtendedCommond, // 通用扩展指令 = 0x3030
|
||||
gecChangeAdministratorPassword, // 通用扩展指令子命令-修改管理员密码 = 2
|
||||
@ -41,11 +43,10 @@ enum CommandType {
|
||||
gecAddFaceConfirmation, // 通用扩展指令子命令-添加人脸确认 = 84
|
||||
}
|
||||
|
||||
extension ExtensionCommandType on CommandType {
|
||||
|
||||
static CommandType getCommandType(int value){
|
||||
extension ExtensionCommandType on CommandType {
|
||||
static CommandType getCommandType(int value) {
|
||||
CommandType type = CommandType.readLockStatusInfo;
|
||||
switch(value){
|
||||
switch (value) {
|
||||
case 0x3001:
|
||||
{
|
||||
type = CommandType.addUser;
|
||||
@ -111,6 +112,21 @@ extension ExtensionCommandType on CommandType {
|
||||
type = CommandType.readStarLockStatusInfo;
|
||||
}
|
||||
break;
|
||||
case 0x30E0:
|
||||
{
|
||||
type = CommandType.startOATUpgrade;
|
||||
}
|
||||
break;
|
||||
case 0x30E1:
|
||||
{
|
||||
type = CommandType.processOTAUpgrade;
|
||||
}
|
||||
break;
|
||||
case 0x30E2:
|
||||
{
|
||||
type = CommandType.confirmationOTAUpgrade;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
type = CommandType.readLockStatusInfo;
|
||||
@ -122,7 +138,7 @@ extension ExtensionCommandType on CommandType {
|
||||
|
||||
int get typeValue {
|
||||
int type = 0x300A;
|
||||
switch(this){
|
||||
switch (this) {
|
||||
case CommandType.addUser:
|
||||
type = 0x3001;
|
||||
break;
|
||||
@ -162,6 +178,15 @@ extension ExtensionCommandType on CommandType {
|
||||
case CommandType.readStarLockStatusInfo:
|
||||
type = 0x3040;
|
||||
break;
|
||||
case CommandType.startOATUpgrade:
|
||||
type = 0x30E0;
|
||||
break;
|
||||
case CommandType.processOTAUpgrade:
|
||||
type = 0x30E1;
|
||||
break;
|
||||
case CommandType.confirmationOTAUpgrade:
|
||||
type = 0x30E2;
|
||||
break;
|
||||
default:
|
||||
type = 0x300A;
|
||||
break;
|
||||
@ -171,10 +196,13 @@ extension ExtensionCommandType on CommandType {
|
||||
return type;
|
||||
}
|
||||
|
||||
//加密类型
|
||||
int get identifierValue {
|
||||
int type = 0x23;
|
||||
switch(this){
|
||||
switch (this) {
|
||||
case CommandType.getLockPublicKey:
|
||||
case CommandType.processOTAUpgrade:
|
||||
//不加密
|
||||
type = 0x20;
|
||||
break;
|
||||
case CommandType.getLockPrivateKey:
|
||||
@ -187,64 +215,73 @@ extension ExtensionCommandType on CommandType {
|
||||
return type;
|
||||
}
|
||||
|
||||
String get typeName {
|
||||
String t = '';
|
||||
switch(typeValue){
|
||||
String get typeName {
|
||||
String t = '';
|
||||
switch (typeValue) {
|
||||
case 0x3001:
|
||||
t = '增加用户';
|
||||
t = '增加用户';
|
||||
break;
|
||||
case 0x3002:
|
||||
t = '删除用户';
|
||||
t = '删除用户';
|
||||
break;
|
||||
case 0x3003:
|
||||
t = '修改用户';
|
||||
t = '修改用户';
|
||||
break;
|
||||
case 0x3004:
|
||||
t = '恢复出厂设置';
|
||||
t = '恢复出厂设置';
|
||||
break;
|
||||
case 0x3005:
|
||||
t = '开门';
|
||||
t = '开门';
|
||||
break;
|
||||
case 0x300A:
|
||||
t = '读取锁状态信息';
|
||||
t = '读取锁状态信息';
|
||||
break;
|
||||
case 0x300B:
|
||||
t = '转移权限';
|
||||
t = '转移权限';
|
||||
break;
|
||||
case 0x3020:
|
||||
t = '开门记录上报';
|
||||
t = '开门记录上报';
|
||||
break;
|
||||
case 0x3030:
|
||||
t = '通用扩展指令';
|
||||
t = '通用扩展指令';
|
||||
break;
|
||||
case 0x3090:
|
||||
t = '获取锁公钥';
|
||||
t = '获取锁公钥';
|
||||
break;
|
||||
case 0x3091:
|
||||
t = '获取锁私钥';
|
||||
t = '获取锁私钥';
|
||||
break;
|
||||
case 0x30f0:
|
||||
t = '校时';
|
||||
t = '校时';
|
||||
break;
|
||||
case 0x30f1:
|
||||
t = '同步位置信息';
|
||||
t = '同步位置信息';
|
||||
break;
|
||||
case 0x30f2:
|
||||
t = '运维开锁';
|
||||
t = '运维开锁';
|
||||
break;
|
||||
case 0x3016:
|
||||
t = '写酒店信息';
|
||||
t = '写酒店信息';
|
||||
break;
|
||||
case 0x3017:
|
||||
t = '读酒店信息';
|
||||
t = '读酒店信息';
|
||||
break;
|
||||
case 0x3040:
|
||||
t = '读星锁状态信息';
|
||||
t = '读星锁状态信息';
|
||||
break;
|
||||
case 0x30E0:
|
||||
t = 'oat升级';
|
||||
break;
|
||||
case 0x30E2:
|
||||
t = '确认oat升级';
|
||||
break;
|
||||
case 0x30E1:
|
||||
t = 'oat升级过程';
|
||||
break;
|
||||
default:
|
||||
t = '读星锁状态信息';
|
||||
t = '读星锁状态信息';
|
||||
break;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ import 'package:star_lock/blue/io_protocol/io_deletUser.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_editUser.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_factoryDataReset.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_getLockStatu.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/blue/io_protocol/io_queryingFaceStatus.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_readSupportFunctionsNoParameters.dart';
|
||||
@ -20,11 +22,14 @@ import 'package:star_lock/blue/io_protocol/io_timing.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_transferPermissions.dart';
|
||||
|
||||
import '../tools/storage.dart';
|
||||
|
||||
// import 'io_protocol/io_addFingerprint.dart';
|
||||
import 'io_protocol/io_addFingerprintWithTimeCycleCoercion.dart';
|
||||
|
||||
// import 'io_protocol/io_addICCard.dart';
|
||||
import 'io_protocol/io_addICCardWithTimeCycleCoercion.dart';
|
||||
import 'io_protocol/io_addStressFingerprint.dart';
|
||||
|
||||
// import 'io_protocol/io_addStressICCard.dart';
|
||||
import 'io_protocol/io_addStressPassword.dart';
|
||||
import 'io_protocol/io_addUser.dart';
|
||||
@ -59,7 +64,7 @@ class CommandReciverManager {
|
||||
return;
|
||||
}
|
||||
|
||||
Get.log("appDataReceiveData:$data"); // &&(data[4] == 0x11)
|
||||
// Get.log("appDataReceiveData:$data"); // &&(data[4] == 0x11)
|
||||
if ((data[0] == 0xEF) &&
|
||||
(data[1] == 0x01) &&
|
||||
(data[2] == 0xEE) &&
|
||||
@ -69,7 +74,7 @@ class CommandReciverManager {
|
||||
|
||||
var dataLen = data[8] * 256 + data[9]; // 高16位用来指示后面数据块内容的长度
|
||||
var oriLen = data[10] * 256 + data[11]; // 低16位用来指示数据加密前的原长度
|
||||
print("dataLen:$dataLen oriLen:$oriLen");
|
||||
// print("dataLen:$dataLen oriLen:$oriLen");
|
||||
// List<int> dataList = [];
|
||||
List<int> oriDataList = [];
|
||||
switch (tmpType) {
|
||||
@ -109,11 +114,11 @@ class CommandReciverManager {
|
||||
oriDataList = SM4.decrypt(getDataList,
|
||||
key: getPrivateKeyList, mode: SM4CryptoMode.ECB);
|
||||
oriDataList = oriDataList.sublist(0, oriLen);
|
||||
print("SM4 oriDataList:$oriDataList");
|
||||
// print("SM4 oriDataList:$oriDataList");
|
||||
break;
|
||||
}
|
||||
parseData(oriDataList).then((value) async {
|
||||
Get.log("parseData222 data:$value");
|
||||
// Get.log("parseData222 data:$value");
|
||||
EasyLoading.dismiss();
|
||||
await EventBusManager().eventBusFir(value);
|
||||
}).catchError((error) {
|
||||
@ -129,7 +134,7 @@ class CommandReciverManager {
|
||||
CommandType commandType = ExtensionCommandType.getCommandType(cmd);
|
||||
await IoManager().increaseCommandIndex();
|
||||
// data.removeRange(0, 2);
|
||||
Get.log("parseData cmd:$cmd commandType:$commandType data:$data");
|
||||
// Get.log("parseData cmd:$cmd commandType:$commandType data:$data");
|
||||
var reply;
|
||||
switch (commandType) {
|
||||
case CommandType.getLockPublicKey:
|
||||
@ -154,7 +159,7 @@ class CommandReciverManager {
|
||||
break;
|
||||
case CommandType.openLock:
|
||||
{
|
||||
Get.log("openLockReply data:$data");
|
||||
// Get.log("openLockReply data:$data");
|
||||
reply = OpenDoorReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
@ -189,6 +194,21 @@ class CommandReciverManager {
|
||||
reply = GetStarLockStatuInfoReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.startOATUpgrade:
|
||||
{
|
||||
reply = OTAUpgradeReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.confirmationOTAUpgrade:
|
||||
{
|
||||
reply = ConfirmationOTAUpgradeReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.processOTAUpgrade:
|
||||
{
|
||||
reply = ProcessOtaUpgradeReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.generalExtendedCommond:
|
||||
{
|
||||
// 子命令类型
|
||||
@ -279,8 +299,9 @@ class CommandReciverManager {
|
||||
case 36:
|
||||
{
|
||||
// 注册指纹开始(带限时、循环、胁迫...)
|
||||
reply = SenderAddFingerprintWithTimeCycleCoercionReply.parseData(
|
||||
commandType, data);
|
||||
reply =
|
||||
SenderAddFingerprintWithTimeCycleCoercionReply.parseData(
|
||||
commandType, data);
|
||||
}
|
||||
break;
|
||||
case 40:
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import '../app_settings/app_settings.dart';
|
||||
@ -11,22 +10,26 @@ import 'io_tool/manager_event_bus.dart';
|
||||
import 'sender_beforeDataManage.dart';
|
||||
|
||||
typedef CommandSendCallBack = void Function(ErrorType errorType);
|
||||
class CommandSenderManager {
|
||||
|
||||
class CommandSenderManager {
|
||||
static final CommandSenderManager _manager = CommandSenderManager._init();
|
||||
factory CommandSenderManager()=>_manager;
|
||||
static CommandSenderManager getInstance()=>_manager;
|
||||
CommandSenderManager._init(){
|
||||
|
||||
factory CommandSenderManager() => _manager;
|
||||
|
||||
static CommandSenderManager getInstance() => _manager;
|
||||
|
||||
CommandSenderManager._init() {
|
||||
init();
|
||||
}
|
||||
|
||||
init(){
|
||||
init() {
|
||||
initLockAddUserSucceedEvent();
|
||||
}
|
||||
|
||||
// 下级界面修改成功后传递数据
|
||||
StreamSubscription? _passCurrentLockInformationEvent;
|
||||
List<int> dataBeforeAddTheUser = [];
|
||||
|
||||
void initLockAddUserSucceedEvent() {
|
||||
// 蓝牙协议通知传输跟蓝牙之外的数据传输类不一样 eventBus
|
||||
_passCurrentLockInformationEvent = eventBus.on<LockAddUserSucceedEvent>().listen((event) {
|
||||
@ -55,7 +58,7 @@ class CommandSenderManager {
|
||||
}
|
||||
|
||||
List<int> value = command.packageData();
|
||||
print("CommonDataManage().currentLockUserNo:${CommonDataManage().currentLockUserNo}");
|
||||
// print("CommonDataManage().currentLockUserNo:${CommonDataManage().currentLockUserNo}");
|
||||
if(CommonDataManage().currentLockUserNo == 0){
|
||||
// 先添加用户
|
||||
var entity = await SenderBeforeDataManage().getAddUserKeyData();
|
||||
@ -63,7 +66,7 @@ class CommandSenderManager {
|
||||
dataBeforeAddTheUser = value;
|
||||
return;
|
||||
}else{
|
||||
print("继续发送数据了继续发送数据了继续发送数据了");
|
||||
// print("继续发送数据了继续发送数据了继续发送数据了");
|
||||
_sendNormalData(value);
|
||||
}
|
||||
}
|
||||
@ -132,4 +135,4 @@ class CommandSenderManager {
|
||||
dispose() {
|
||||
_passCurrentLockInformationEvent?.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,12 @@
|
||||
import 'package:star_lock/blue/io_protocol/io_addFace.dart';
|
||||
|
||||
// import 'package:star_lock/blue/io_protocol/io_addICCard.dart';
|
||||
// import 'package:star_lock/blue/io_protocol/io_addStressICCard.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_changeAdministratorPassword.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_deletUser.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_getLockStatu.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/blue/io_protocol/io_queryingFaceStatus.dart';
|
||||
import 'package:star_lock/blue/io_protocol/io_readAdminPassword.dart';
|
||||
|
||||
@ -359,23 +362,22 @@ class IoSenderManage {
|
||||
|
||||
//todo:添加指纹开始(带限时、循环、胁迫...)
|
||||
static void senderAddFingerprintWithTimeCycleCoercionCommand(
|
||||
{
|
||||
required String? keyID,
|
||||
required String? userID,
|
||||
required int? fingerNo,
|
||||
required int? useCountLimit,
|
||||
required int? isForce,
|
||||
required List<int>? token,
|
||||
required int? isRound,
|
||||
required int? weekRound,
|
||||
required int? startDate,
|
||||
required int? endDate,
|
||||
required String? startTime,
|
||||
required String? endTime,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
{required String? keyID,
|
||||
required String? userID,
|
||||
required int? fingerNo,
|
||||
required int? useCountLimit,
|
||||
required int? isForce,
|
||||
required List<int>? token,
|
||||
required int? isRound,
|
||||
required int? weekRound,
|
||||
required int? startDate,
|
||||
required int? endDate,
|
||||
required String? startTime,
|
||||
required String? endTime,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: SenderAddFingerprintWithTimeCycleCoercionCommand(
|
||||
keyID: keyID,
|
||||
@ -428,23 +430,22 @@ class IoSenderManage {
|
||||
|
||||
//todo:添加卡开始(带限时、循环、胁迫...)
|
||||
static void senderAddCardWithTimeCycleCoercionCommand(
|
||||
{
|
||||
required String? keyID,
|
||||
required String? userID,
|
||||
required int? cardNo,
|
||||
required int? useCountLimit,
|
||||
required int? isForce,
|
||||
required List<int>? token,
|
||||
required int? isRound,
|
||||
required int? weekRound,
|
||||
required int? startDate,
|
||||
required int? endDate,
|
||||
required String? startTime,
|
||||
required String? endTime,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
{required String? keyID,
|
||||
required String? userID,
|
||||
required int? cardNo,
|
||||
required int? useCountLimit,
|
||||
required int? isForce,
|
||||
required List<int>? token,
|
||||
required int? isRound,
|
||||
required int? weekRound,
|
||||
required int? startDate,
|
||||
required int? endDate,
|
||||
required String? startTime,
|
||||
required String? endTime,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: SenderAddICCardWithTimeCycleCoercionCommand(
|
||||
keyID: keyID,
|
||||
@ -469,20 +470,20 @@ class IoSenderManage {
|
||||
//todo:添加人脸开始
|
||||
static void senderAddFaceCommand(
|
||||
{required String? keyID,
|
||||
required String? userID,
|
||||
required int? faceNo,
|
||||
required int? useCountLimit,
|
||||
required int? isForce,
|
||||
required List<int>? token,
|
||||
required int? isRound,
|
||||
required int? weekRound,
|
||||
required int? startDate,
|
||||
required int? endDate,
|
||||
required String? startTime,
|
||||
required String? endTime,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
required String? userID,
|
||||
required int? faceNo,
|
||||
required int? useCountLimit,
|
||||
required int? isForce,
|
||||
required List<int>? token,
|
||||
required int? isRound,
|
||||
required int? weekRound,
|
||||
required int? startDate,
|
||||
required int? endDate,
|
||||
required String? startTime,
|
||||
required String? endTime,
|
||||
required int? needAuthor,
|
||||
required List<int>? signKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: SenderAddFaceCommand(
|
||||
@ -709,12 +710,12 @@ class IoSenderManage {
|
||||
//todo:wifi列表
|
||||
static void getWifiListCommand(
|
||||
{required String? keyID,
|
||||
required String? userID,
|
||||
required List<int>? token,
|
||||
required int? needAuthor,
|
||||
required List<int>? publicKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
required String? userID,
|
||||
required List<int>? token,
|
||||
required int? needAuthor,
|
||||
required List<int>? publicKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: SenderGetWifiCommand(
|
||||
keyID: keyID,
|
||||
@ -977,4 +978,54 @@ class IoSenderManage {
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
|
||||
//开始ota 升级
|
||||
static void senderOTAUpgradeCommand(
|
||||
{required String? lockID,
|
||||
required String? userID,
|
||||
required String? keyID,
|
||||
required int? platform,
|
||||
required int? product,
|
||||
required String? hwVersion,
|
||||
required String? fwVersion,
|
||||
required int? fwSize,
|
||||
required String? fwMD5,
|
||||
required int? needAuthor,
|
||||
required List<int>? token,
|
||||
required List<int>? publicKey,
|
||||
required List<int>? privateKey,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: OTAUpgradeCommand(
|
||||
lockID: lockID,
|
||||
userID: userID,
|
||||
keyID: keyID,
|
||||
platform: platform,
|
||||
product: product,
|
||||
hwVersion: hwVersion,
|
||||
fwVersion: fwVersion,
|
||||
fwSize: fwSize,
|
||||
fwMD5: fwMD5,
|
||||
token: token,
|
||||
needAuthor: needAuthor,
|
||||
publicKey: publicKey,
|
||||
privateKey: privateKey,
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
|
||||
//ota 升级过程
|
||||
static void senderProcessOtaUpgradeCommand(
|
||||
{required int? index,
|
||||
required int? size,
|
||||
required List<int>? data,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: ProcessOtaUpgradeCommand(
|
||||
index: index,
|
||||
size: size,
|
||||
data: data,
|
||||
),
|
||||
callBack: callBack);
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ class LockDetailLogic extends BaseGetXController {
|
||||
// 监听设备返回的数据
|
||||
void initReplySubscription() {
|
||||
state.replySubscription = EventBusManager().eventBus!.on<Reply>().listen((reply) async {
|
||||
Get.log("锁详情收到了蓝牙解析消息 reply:${reply.commandType}");
|
||||
// Get.log("锁详情收到了蓝牙解析消息 reply:${reply.commandType}");
|
||||
// 开门
|
||||
if (reply is OpenDoorReply && state.ifCurrentScreen.value == true) {
|
||||
_replyOpenLock(reply);
|
||||
|
||||
@ -1,14 +1,41 @@
|
||||
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:get/get.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:star_lock/blue/blue_manage.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/blue/io_reply.dart';
|
||||
import 'package:star_lock/blue/io_tool/io_tool.dart';
|
||||
import 'package:star_lock/blue/io_tool/manager_event_bus.dart';
|
||||
import 'package:star_lock/blue/sender_manage.dart';
|
||||
import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSet_logic.dart';
|
||||
import 'package:star_lock/permission/permission_dialog.dart';
|
||||
import 'package:star_lock/tools/advancedCalendar/src/datetime_util.dart';
|
||||
import 'package:star_lock/tools/baseGetXController.dart';
|
||||
import 'package:star_lock/tools/commonDataManage.dart';
|
||||
import 'package:star_lock/tools/pickers/time_picker/time_utils.dart';
|
||||
import 'package:star_lock/tools/storage.dart';
|
||||
|
||||
import 'lockEscalation_state.dart';
|
||||
|
||||
class LockEscalationLogic extends BaseGetXController{
|
||||
class LockEscalationLogic extends BaseGetXController {
|
||||
LockEscalationState state = LockEscalationState();
|
||||
StreamSubscription<Reply>? _replySubscription;
|
||||
|
||||
int otaCount = 0;
|
||||
int otaIndex = 0;
|
||||
Uint8List? otaBin;
|
||||
int startSecond = 0;
|
||||
|
||||
// 锁升级
|
||||
Future<void> setLockSetGeneralSetting() async{
|
||||
Future<void> setLockSetGeneralSetting() async {
|
||||
// var entity = await ApiRepository.to.getLockVersionInfoData(
|
||||
// lockId: state.getKeyInfosData.value.lockId.toString(),
|
||||
// );
|
||||
@ -17,24 +44,193 @@ class LockEscalationLogic extends BaseGetXController{
|
||||
// }
|
||||
}
|
||||
|
||||
//手动升级
|
||||
Future<void> otaUpdate() async {
|
||||
var status = await PermissionDialog.request(
|
||||
Permission.storage, '需要访问读写权限才能使用手动升级固件');
|
||||
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();
|
||||
Map? headJson = await getHeadFile(data);
|
||||
if (headJson is! Map) {
|
||||
return;
|
||||
}
|
||||
otaBin = await checkFile(data, headJson);
|
||||
if (otaBin == null) {
|
||||
return;
|
||||
}
|
||||
startOTAData();
|
||||
blueOTAUpgrade(headJson);
|
||||
}
|
||||
|
||||
//蓝牙操作 ota 升级
|
||||
void blueOTAUpgrade(Map data) {
|
||||
BlueManage().bludSendData(BlueManage().connectDeviceName,
|
||||
(BluetoothConnectionState deviceConnectionState) async {
|
||||
if (deviceConnectionState == BluetoothConnectionState.connected) {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
var publicKey = await Storage.getStringList(saveBluePublicKey);
|
||||
List<int> getPublicKeyList = changeStringListToIntList(publicKey!);
|
||||
String lockID = CommonDataManage.shareManager()
|
||||
?.currentLockSetInfoData
|
||||
.lockId
|
||||
?.toString() ??
|
||||
'';
|
||||
String keyID =
|
||||
CommonDataManage.shareManager()?.currentKeyInfo.keyId?.toString() ??
|
||||
'';
|
||||
BlueManage().writeCharacteristicWithResponse(OTAUpgradeCommand(
|
||||
lockID: lockID,
|
||||
userID: await Storage.getUid(),
|
||||
keyID: keyID,
|
||||
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: getTokenList,
|
||||
publicKey: getPublicKeyList,
|
||||
privateKey: getPrivateKeyList)
|
||||
.packageData());
|
||||
} else if (deviceConnectionState ==
|
||||
BluetoothConnectionState.disconnected) {}
|
||||
});
|
||||
}
|
||||
|
||||
//循环传输升级固件包
|
||||
Future<void> 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}秒';
|
||||
closeOTADAta();
|
||||
print(msg);
|
||||
showToast(msg);
|
||||
return;
|
||||
}
|
||||
int star = otaIndex * 240;
|
||||
int end = (otaIndex + 1) * 240;
|
||||
if (end > length) {
|
||||
end = length;
|
||||
}
|
||||
List<int> data = otaBin!.sublist(star, end);
|
||||
state.otaProgress.value = otaIndex / otaCount;
|
||||
await BlueManage().writeCharacteristicWithResponse(
|
||||
ProcessOtaUpgradeCommand(index: otaIndex, size: length, data: data)
|
||||
.packageData());
|
||||
}
|
||||
|
||||
//开始 ota升级
|
||||
void startOTAData() {
|
||||
state.otaUpdateIng.value = true;
|
||||
}
|
||||
|
||||
//清楚 ata 安装文件
|
||||
void closeOTADAta() {
|
||||
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<Map?> getHeadFile(Uint8List data) async {
|
||||
// 检查文件头
|
||||
String header = utf8.decode(data.sublist(0, 12));
|
||||
if (header != 'SYD-BIN-DATA') {
|
||||
showToast('非SYD固件,请选择正确的文件');
|
||||
return null;
|
||||
}
|
||||
// 解析元数据长度
|
||||
Uint8List metaLenList = data.sublist(12, 16);
|
||||
int metaLen = ByteData.sublistView(metaLenList).getUint32(0);
|
||||
if (metaLen < 2 || metaLen > 10240) {
|
||||
showToast('元数据长度错误');
|
||||
return null;
|
||||
}
|
||||
// 读取和解析元数据
|
||||
Uint8List metaStrList = data.sublist(16, 16 + metaLen);
|
||||
String metaStr = utf8.decode(metaStrList);
|
||||
print(metaStr);
|
||||
var meta = jsonDecode(metaStr);
|
||||
return meta..['metaLen'] = metaLen;
|
||||
}
|
||||
|
||||
//检测升级文件并读取 bin
|
||||
Future<Uint8List?> 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();
|
||||
// if (md5Str != meta['fwMd5']) {
|
||||
// showToast('固件MD5校验失败');
|
||||
// return false;
|
||||
// }
|
||||
if (bin.length != meta['fwSize']) {
|
||||
showToast('固件校验失败');
|
||||
return null;
|
||||
}
|
||||
return bin;
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
// TODO: implement onReady
|
||||
super.onReady();
|
||||
print("onReady()");
|
||||
setLockSetGeneralSetting();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
super.onInit();
|
||||
print("onInit()");
|
||||
_replySubscription =
|
||||
EventBusManager().eventBus!.on<Reply>().listen((reply) {
|
||||
if (reply is OTAUpgradeReply && reply.status == 0x00) {
|
||||
//验证通过,开始发送数据包
|
||||
processOtaUpgrade();
|
||||
} else if (reply is ProcessOtaUpgradeReply && reply.status == 0x00) {
|
||||
otaIndex++;
|
||||
processOtaUpgrade();
|
||||
} else if (reply is ConfirmationOTAUpgradeReply && reply.status == 0x00) {
|
||||
closeOTADAta();
|
||||
showToast('固件升级完成');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
// TODO: implement onClose
|
||||
_replySubscription?.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -16,66 +16,152 @@ class LockEscalationPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _LockEscalationPageState extends State<LockEscalationPage> {
|
||||
final logic = Get.put(LockEscalationLogic());
|
||||
final state = Get.find<LockEscalationLogic>().state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: TitleAppBar(
|
||||
barTitle: TranslationLoader.lanKeys!.lockEscalation!.tr,
|
||||
haveBack: true,
|
||||
backgroundColor: AppColors.mainColor),
|
||||
body: Container(
|
||||
padding: EdgeInsets.all(30.w),
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 60.h,
|
||||
return GetBuilder<LockEscalationLogic>(
|
||||
init: LockEscalationLogic(),
|
||||
builder: (LockEscalationLogic logic) {
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: TitleAppBar(
|
||||
barTitle: TranslationLoader.lanKeys!.lockEscalation!.tr,
|
||||
haveBack: true,
|
||||
backgroundColor: AppColors.mainColor,
|
||||
backAction: logic.getBack,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'images/main/icon_main_lockSet_lockEscalation.png',
|
||||
width: 36.w,
|
||||
height: 36.w,
|
||||
),
|
||||
SizedBox(
|
||||
width: 10.w,
|
||||
),
|
||||
Text(
|
||||
TranslationLoader.lanKeys!.haveNewVersion!.tr,
|
||||
style:
|
||||
TextStyle(fontSize: 24.sp, fontWeight: FontWeight.w600),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 30.h,
|
||||
),
|
||||
Text(
|
||||
"${TranslationLoader.lanKeys!.currentVersion!.tr}:1.0.0",
|
||||
style: TextStyle(
|
||||
fontSize: 18.sp, color: AppColors.darkGrayTextColor),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10.h,
|
||||
),
|
||||
Text(
|
||||
// "${TranslationLoader.lanKeys!.newVersion!.tr}:1.0.1",
|
||||
"未发现新版本",
|
||||
style: TextStyle(color: AppColors.mainColor, fontSize: 18.sp),
|
||||
),
|
||||
SizedBox(
|
||||
height: 40.h,
|
||||
),
|
||||
SubmitBtn(
|
||||
btnName: TranslationLoader.lanKeys!.upgrade!.tr,
|
||||
onClick: () {}),
|
||||
],
|
||||
),
|
||||
));
|
||||
body: Container(
|
||||
padding: EdgeInsets.all(30.w),
|
||||
child: Column(
|
||||
children: [
|
||||
Obx(() {
|
||||
return logic.state.otaUpdateIng.value
|
||||
? PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) async {
|
||||
if (logic.state.otaUpdateIng.value) {
|
||||
logic.closeOTADAta();
|
||||
}
|
||||
},
|
||||
child: SizedBox(),
|
||||
)
|
||||
: SizedBox();
|
||||
}),
|
||||
SizedBox(
|
||||
height: 60.h,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
'images/main/icon_main_lockSet_lockEscalation.png',
|
||||
width: 36.w,
|
||||
height: 36.w,
|
||||
),
|
||||
SizedBox(
|
||||
width: 10.w,
|
||||
),
|
||||
Text(
|
||||
TranslationLoader.lanKeys!.haveNewVersion!.tr,
|
||||
style: TextStyle(
|
||||
fontSize: 24.sp, fontWeight: FontWeight.w600),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 30.h,
|
||||
),
|
||||
Text(
|
||||
"${TranslationLoader.lanKeys!.currentVersion!.tr}:1.0.0",
|
||||
style: TextStyle(
|
||||
fontSize: 18.sp, color: AppColors.darkGrayTextColor),
|
||||
),
|
||||
SizedBox(
|
||||
height: 10.h,
|
||||
),
|
||||
Obx(() {
|
||||
return !logic.state.otaUpdateIng.value
|
||||
? Stack(
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(top: 8, bottom: 8),
|
||||
width: Get.width,
|
||||
child: Center(
|
||||
child: Text(
|
||||
// "${TranslationLoader.lanKeys!.newVersion!.tr}:1.0.1",
|
||||
"未发现新版本",
|
||||
style: TextStyle(
|
||||
color: AppColors.mainColor,
|
||||
fontSize: 18.sp),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 80.w,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
logic.otaUpdate();
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'手动升级',
|
||||
style: TextStyle(
|
||||
color: AppColors.mainColor,
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 50.w, vertical: 15.h),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
'固件传输中',
|
||||
style: TextStyle(
|
||||
color: AppColors.mainColor,
|
||||
fontSize: 18.sp,
|
||||
fontWeight: FontWeight.w400),
|
||||
),
|
||||
SizedBox(
|
||||
width: 10.w,
|
||||
),
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10.r)),
|
||||
child: LinearProgressIndicator(
|
||||
value: logic
|
||||
.state.otaProgress.value, // 50% 进度
|
||||
backgroundColor: Colors.grey[200],
|
||||
valueColor:
|
||||
AlwaysStoppedAnimation<Color>(
|
||||
AppColors.mainColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
SizedBox(
|
||||
height: 40.h,
|
||||
),
|
||||
Obx(() {
|
||||
return !logic.state.otaUpdateIng.value
|
||||
? SubmitBtn(
|
||||
btnName: TranslationLoader.lanKeys!.upgrade!.tr,
|
||||
onClick: () {})
|
||||
: SizedBox();
|
||||
}),
|
||||
],
|
||||
),
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class LockEscalationState{
|
||||
|
||||
class LockEscalationState {
|
||||
var otaUpdateIng = false.obs;
|
||||
var otaProgress = 0.00.obs;
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ class PermissionDialog {
|
||||
}
|
||||
|
||||
//显示权限判断申请框
|
||||
static Future<bool> request(Permission permission) async {
|
||||
static Future<bool> request(Permission permission, [String? content]) async {
|
||||
if (Get.context == null) {
|
||||
return false;
|
||||
}
|
||||
@ -99,7 +99,7 @@ class PermissionDialog {
|
||||
canPop: false,
|
||||
child: CupertinoAlertDialog(
|
||||
title: Text('${'申请'.tr}${titles[permission] ?? ''}${'权限'.tr}'),
|
||||
content: Text(contents[permission] ?? ''),
|
||||
content: Text(content ?? contents[permission] ?? ''),
|
||||
actions: [
|
||||
CupertinoDialogAction(
|
||||
child: Text('不允许'.tr),
|
||||
|
||||
@ -94,7 +94,7 @@ dependencies:
|
||||
#跳转到外部
|
||||
url_launcher: ^6.1.10
|
||||
#蓝牙
|
||||
# flutter_reactive_ble: ^5.1.1
|
||||
# flutter_reactive_ble: ^5.1.1
|
||||
flutter_blue_plus: ^1.31.16
|
||||
#
|
||||
event_bus: ^2.0.0
|
||||
@ -123,7 +123,7 @@ dependencies:
|
||||
|
||||
# 谷歌地图
|
||||
google_maps_flutter: ^2.2.5
|
||||
# geocoding: ^2.1.0
|
||||
# geocoding: ^2.1.0
|
||||
|
||||
# 允许App发现网络的相关信息并且进行相应的配置
|
||||
network_info_plus: ^4.0.2
|
||||
@ -144,12 +144,12 @@ dependencies:
|
||||
image_gallery_saver: ^2.0.3
|
||||
convert: ^3.1.1
|
||||
just_audio: ^0.9.36
|
||||
# flutter_sound: ^9.2.13
|
||||
# ffmpeg_kit_flutter: 5.1.0-LTS
|
||||
# flutter_sound: ^9.2.13
|
||||
# ffmpeg_kit_flutter: 5.1.0-LTS
|
||||
fast_gbk: ^1.0.0
|
||||
flutter_pcm_sound: ^1.1.0
|
||||
intl: ^0.18.0
|
||||
# flutter_audio_capture: <1.1.5
|
||||
# flutter_audio_capture: <1.1.5
|
||||
|
||||
flutter_voice_processor: ^1.1.1
|
||||
#监听网络连接状态
|
||||
@ -165,6 +165,7 @@ dependencies:
|
||||
system_settings: ^2.0.0
|
||||
expandable: ^5.0.1
|
||||
colorfilter_generator: ^0.0.8
|
||||
file_picker: ^5.3.1
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user