添加高德地图、调试蓝牙协议、添加添加锁逻辑
This commit is contained in:
parent
1a659b5579
commit
10c8357fba
@ -5,11 +5,15 @@
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" android:maxSdkVersion="30" />
|
||||
<!-- <uses-permission android:name="android.permission.BLUETOOTH_SCAN"-->
|
||||
<!-- tools:remove="android:usesPermissionFlags"-->
|
||||
<!-- tools:targetApi="s" />-->
|
||||
|
||||
<application
|
||||
<!--允许访问网络,必选权限-->
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!--允许获取精确位置,精准定位必选-->
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<!--允许获取粗略位置,粗略定位必选-->
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
|
||||
<application
|
||||
android:label="star_lock"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
@ -40,5 +44,9 @@
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
|
||||
<!-- 配置定位Service -->
|
||||
<service android:name="com.amap.api.location.APSService"/>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@ -191,6 +191,7 @@
|
||||
"lanChinese":"Chinese",
|
||||
"multilingual":"Multilingual",
|
||||
"addLock":"Add Lock",
|
||||
"lockAddress":"Lock Address",
|
||||
"selectLockType":"Select lock type",
|
||||
"videoIntercomDoorLock":"Video intercom door lock",
|
||||
"NFCPassiveLock":"NFC Passive Lock",
|
||||
|
||||
@ -191,6 +191,7 @@
|
||||
"lanChinese":"lanChinese",
|
||||
"multilingual":"multilingual",
|
||||
"addLock":"addLock",
|
||||
"lockAddress":"lockAddress",
|
||||
"selectLockType":"selectLockType",
|
||||
"videoIntercomDoorLock":"videoIntercomDoorLock",
|
||||
"NFCPassiveLock":"NFCPassiveLock",
|
||||
|
||||
@ -191,6 +191,7 @@
|
||||
"lanChinese":"中文",
|
||||
"multilingual":"多语言",
|
||||
"addLock":"添加锁",
|
||||
"lockAddress":"锁地址",
|
||||
"selectLockType":"选择锁类型",
|
||||
"videoIntercomDoorLock":"可视对讲门锁",
|
||||
"NFCPassiveLock":"NFC无源锁",
|
||||
|
||||
BIN
star_lock/images/main/icon_addUserAddressShowTime.png
Normal file
BIN
star_lock/images/main/icon_addUserAddressShowTime.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
star_lock/images/main/icon_addUserShowAddress.png
Normal file
BIN
star_lock/images/main/icon_addUserShowAddress.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
@ -1,6 +1,17 @@
|
||||
PODS:
|
||||
- aj_captcha_flutter (0.0.1):
|
||||
- Flutter
|
||||
- AMap3DMap (9.7.0):
|
||||
- AMapFoundation (>= 1.8.0)
|
||||
- amap_flutter_location (0.0.1):
|
||||
- AMapLocation
|
||||
- Flutter
|
||||
- amap_flutter_map (0.0.1):
|
||||
- AMap3DMap
|
||||
- Flutter
|
||||
- AMapFoundation (1.8.2)
|
||||
- AMapLocation (2.10.0):
|
||||
- AMapFoundation (>= 1.8.0)
|
||||
- device_info_plus (0.0.1):
|
||||
- Flutter
|
||||
- Flutter (1.0.0)
|
||||
@ -16,6 +27,8 @@ PODS:
|
||||
- path_provider_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- permission_handler_apple (9.1.1):
|
||||
- Flutter
|
||||
- Protobuf (3.23.4)
|
||||
- reactive_ble_mobile (0.0.1):
|
||||
- Flutter
|
||||
@ -31,6 +44,8 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- aj_captcha_flutter (from `.symlinks/plugins/aj_captcha_flutter/ios`)
|
||||
- amap_flutter_location (from `.symlinks/plugins/amap_flutter_location/ios`)
|
||||
- amap_flutter_map (from `.symlinks/plugins/amap_flutter_map/ios`)
|
||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_native_contact_picker (from `.symlinks/plugins/flutter_native_contact_picker/ios`)
|
||||
@ -38,12 +53,16 @@ DEPENDENCIES:
|
||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- reactive_ble_mobile (from `.symlinks/plugins/reactive_ble_mobile/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- AMap3DMap
|
||||
- AMapFoundation
|
||||
- AMapLocation
|
||||
- Protobuf
|
||||
- SwiftProtobuf
|
||||
- Toast
|
||||
@ -51,6 +70,10 @@ SPEC REPOS:
|
||||
EXTERNAL SOURCES:
|
||||
aj_captcha_flutter:
|
||||
:path: ".symlinks/plugins/aj_captcha_flutter/ios"
|
||||
amap_flutter_location:
|
||||
:path: ".symlinks/plugins/amap_flutter_location/ios"
|
||||
amap_flutter_map:
|
||||
:path: ".symlinks/plugins/amap_flutter_map/ios"
|
||||
device_info_plus:
|
||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||
Flutter:
|
||||
@ -65,6 +88,8 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
reactive_ble_mobile:
|
||||
:path: ".symlinks/plugins/reactive_ble_mobile/ios"
|
||||
shared_preferences_foundation:
|
||||
@ -74,6 +99,11 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
aj_captcha_flutter: dd7af1aa064bdd621ae335b819bab07309c3c023
|
||||
AMap3DMap: dce25dd3e51e6b92109caa7d0c97fc6055830fb3
|
||||
amap_flutter_location: 44ff5beb64f42e0bf5feb402fe299dac0013af6f
|
||||
amap_flutter_map: 979e54d227cedac6c7504a2151bfbf3bcf96760a
|
||||
AMapFoundation: 9885c48fc3a78fdfb84a0299a2293e56ea3c9fec
|
||||
AMapLocation: 5248aec2455ebb5d104b367813c946430a2ee033
|
||||
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
|
||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||
flutter_native_contact_picker: bd430ba0fbf82768bb50c2c52a69a65759a8f907
|
||||
@ -81,6 +111,7 @@ SPEC CHECKSUMS:
|
||||
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
|
||||
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||
Protobuf: c6bc59bbab3d38a71c67f62d7cb7ca8f8ea4eca1
|
||||
reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c
|
||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||
|
||||
@ -34,6 +34,7 @@
|
||||
09D8B2FA2B26BA5BFF31AB2A /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
33BF41252A96174D009D92E2 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
@ -114,6 +115,7 @@
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
33BF41252A96174D009D92E2 /* Runner.entitlements */,
|
||||
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */,
|
||||
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */,
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
@ -149,6 +151,7 @@
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
D9B107A6B141D5F15BC356F2 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -259,6 +262,23 @@
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
D9B107A6B141D5F15BC356F2 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@ -351,6 +371,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 7NLFRKNVY3;
|
||||
ENABLE_BITCODE = NO;
|
||||
@ -478,6 +499,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 7NLFRKNVY3;
|
||||
ENABLE_BITCODE = NO;
|
||||
@ -498,6 +520,7 @@
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = YES;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 7NLFRKNVY3;
|
||||
ENABLE_BITCODE = NO;
|
||||
|
||||
@ -24,6 +24,11 @@
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
@ -38,6 +43,12 @@
|
||||
<string>用于音频插件</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>用于相册</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>应用在前台的时候可以搜到更新的位置信息</string>
|
||||
<key>NSLocationAlwaysUsageDescription</key>
|
||||
<string>应用在后台的时候可以搜到更新的位置信息</string>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>应用在前台和后台的时候可以搜到更新的位置信息</string>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>UIBackgroundModes</key>
|
||||
|
||||
5
star_lock/ios/Runner/Runner.entitlements
Normal file
5
star_lock/ios/Runner/Runner.entitlements
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict/>
|
||||
</plist>
|
||||
@ -95,6 +95,10 @@ class BlueManage{
|
||||
print("connectDeviceId:$connectDeviceId connectDeviceName:$connectDeviceName");
|
||||
|
||||
EasyLoading.show();
|
||||
Future.delayed(const Duration(seconds: 30), () { //asynchronous delay
|
||||
print("30s之后 菊花没有隐藏的话,强制隐藏菊花");
|
||||
EasyLoading.dismiss();
|
||||
});
|
||||
_flutterReactiveBle!.connectToDevice(id: connectDeviceId, connectionTimeout: const Duration(seconds: 15)).listen((connectionStateUpdate) async {
|
||||
// 获取状态
|
||||
deviceConnectionState = connectionStateUpdate.connectionState;
|
||||
@ -174,6 +178,10 @@ class BlueManage{
|
||||
Future<void> judgeReconnect(String deviceMAC, String deviceName, ConnectStateCallBack? connectStateCallBack) async {
|
||||
if(deviceConnectionState == DeviceConnectionState.connected){
|
||||
EasyLoading.show();
|
||||
Future.delayed(const Duration(seconds: 30), () { //asynchronous delay
|
||||
print("30s之后 菊花没有隐藏的话,强制隐藏菊花");
|
||||
EasyLoading.dismiss();
|
||||
});
|
||||
connectStateCallBack!(deviceConnectionState!);
|
||||
}else{
|
||||
connect(deviceMAC, deviceName, connectStateCallBack: (state){
|
||||
|
||||
105
star_lock/lib/blue/io_protocol/io_factoryDataReset.dart
Normal file
105
star_lock/lib/blue/io_protocol/io_factoryDataReset.dart
Normal file
@ -0,0 +1,105 @@
|
||||
|
||||
//TODO:添加用户
|
||||
import 'dart:convert';
|
||||
|
||||
import '../../tools/storage.dart';
|
||||
import '../blue_manage.dart';
|
||||
import '../io_tool/io_manager.dart';
|
||||
import '../io_tool/io_tool.dart';
|
||||
import '../sender_manage.dart';
|
||||
import '../sm4Encipher/sm4.dart';
|
||||
import 'io_reply.dart';
|
||||
import 'io_sender.dart';
|
||||
import 'io_type.dart';
|
||||
import 'package:crypto/crypto.dart' as crypto;
|
||||
|
||||
class FactoryDataResetCommand extends SenderProtocol {
|
||||
|
||||
String? lockID;
|
||||
String? userID;
|
||||
String? keyID;
|
||||
List<int>? publicKey;
|
||||
List<int>? privateKey;
|
||||
List<int>? token;
|
||||
int? needAuthor;
|
||||
FactoryDataResetCommand({
|
||||
this.lockID,
|
||||
this.userID,
|
||||
this.keyID,
|
||||
this.token,
|
||||
this.needAuthor,
|
||||
this.publicKey,
|
||||
this.privateKey,
|
||||
}) : super(CommandType.factoryDataReset);
|
||||
|
||||
@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;
|
||||
// print("${commandType!.typeValue}LockIDLength:$lockIDLength utf8.encode(lockID!)${utf8.encode(lockID!)}");
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//userID 20
|
||||
int userIDLength = utf8.encode(userID!).length;
|
||||
// print("${commandType!.typeValue}IDLength:$authUserIDLength utf8.encode(authUserID!)${utf8.encode(authUserID!)}");
|
||||
data.addAll(utf8.encode(userID!));
|
||||
data = getFixedLengthList(data, 20 - userIDLength);
|
||||
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
print("恢复出厂设置、pubToken:$token");
|
||||
|
||||
if(needAuthor == 0){
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
|
||||
//userID
|
||||
authCodeData.addAll(utf8.encode(lockID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token!);
|
||||
|
||||
authCodeData.addAll(publicKey!);
|
||||
|
||||
print("${commandType!.typeValue}-authCodeData:$authCodeData");
|
||||
|
||||
// 把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);
|
||||
}
|
||||
}
|
||||
print("${commandType!.typeName} SM4Data:$data");
|
||||
// 拿到数据之后通过LockId进行SM4 ECB加密 key:544d485f633335373034383064613864
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
}
|
||||
}
|
||||
|
||||
class FactoryDataResetReply extends Reply {
|
||||
FactoryDataResetReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
}
|
||||
}
|
||||
125
star_lock/lib/blue/io_protocol/io_transferPermissions.dart
Normal file
125
star_lock/lib/blue/io_protocol/io_transferPermissions.dart
Normal file
@ -0,0 +1,125 @@
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
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;
|
||||
|
||||
//TODO:转移权限
|
||||
class TransferPermissionsCommand extends SenderProtocol {
|
||||
|
||||
String? lockID;
|
||||
String? authUserID;
|
||||
String? keyID;
|
||||
String? oldUserID;
|
||||
String? newUserID;
|
||||
int? needAuthor;
|
||||
List<int>? publicKey;
|
||||
List<int>? privateKey;
|
||||
List<int>? token;
|
||||
TransferPermissionsCommand({
|
||||
this.lockID,
|
||||
this.authUserID,
|
||||
this.keyID,
|
||||
this.oldUserID,
|
||||
this.newUserID,
|
||||
this.needAuthor,
|
||||
this.publicKey,
|
||||
this.privateKey,
|
||||
this.token
|
||||
}) : super(CommandType.transferPermissions);
|
||||
|
||||
@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;
|
||||
print("${commandType!.typeValue} lockID:$lockID LockIDLength:$lockIDLength utf8.encode(lockID!)${utf8.encode(lockID!)}");
|
||||
data.addAll(utf8.encode(lockID!));
|
||||
data = getFixedLengthList(data, 40 - lockIDLength);
|
||||
|
||||
//authUserID 20
|
||||
int authUserIDLength = utf8.encode(authUserID!).length;
|
||||
// print("${commandType!.typeValue}IDLength:$authUserIDLength utf8.encode(authUserID!)${utf8.encode(authUserID!)}");
|
||||
data.addAll(utf8.encode(authUserID!));
|
||||
data = getFixedLengthList(data, 20 - authUserIDLength);
|
||||
|
||||
//KeyID 40
|
||||
int keyIDLength = utf8.encode(keyID!).length;
|
||||
// print("${commandType!.typeValue}keyIDLength:$keyIDLength utf8.encode(keyID!)${utf8.encode(keyID!)}");
|
||||
data.addAll(utf8.encode(keyID!));
|
||||
data = getFixedLengthList(data, 40 - keyIDLength);
|
||||
|
||||
//oldUserID 20
|
||||
int oldUserIDLength = utf8.encode(oldUserID!).length;
|
||||
// print("${commandType!.typeValue}userIDLength:$userIDLength utf8.encode(userID!)${utf8.encode(userID!)}");
|
||||
data.addAll(utf8.encode(oldUserID!));
|
||||
data = getFixedLengthList(data, 20 - oldUserIDLength);
|
||||
|
||||
//newUserID 20
|
||||
int newUserIDLength = utf8.encode(newUserID!).length;
|
||||
// print("${commandType!.typeValue}userIDLength:$userIDLength utf8.encode(userID!)${utf8.encode(userID!)}");
|
||||
data.addAll(utf8.encode(newUserID!));
|
||||
data = getFixedLengthList(data, 20 - newUserIDLength);
|
||||
|
||||
// token 长度4 首次请求 Token 填 0,如果锁需要鉴权 操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。 当token失效或者第一次发送的时候token为0
|
||||
data.addAll(token!);
|
||||
print("pubToken:$token");
|
||||
|
||||
if(needAuthor == 0){
|
||||
//AuthCodeLen 1
|
||||
data.add(0);
|
||||
} else {
|
||||
List<int> authCodeData = [];
|
||||
|
||||
//authUserID
|
||||
authCodeData.addAll(utf8.encode(authUserID!));
|
||||
|
||||
//KeyID
|
||||
authCodeData.addAll(utf8.encode(keyID!));
|
||||
|
||||
//token 4 首次请求 Token 填 0,如果锁需要鉴权操作者身份,则会分配动态口令并在应答消息中返回,二次请求时带上。
|
||||
authCodeData.addAll(token!);
|
||||
|
||||
authCodeData.addAll(publicKey!);
|
||||
|
||||
print("${commandType!.typeValue}-authCodeData:$authCodeData");
|
||||
|
||||
// 把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);
|
||||
}
|
||||
}
|
||||
print("${commandType!.typeName} SM4Data:$data");
|
||||
ebcData = SM4.encrypt(data, key: privateKey, mode: SM4CryptoMode.ECB);
|
||||
return ebcData;
|
||||
}
|
||||
}
|
||||
|
||||
class TransferPermissionsReply extends Reply {
|
||||
TransferPermissionsReply.parseData(CommandType commandType, List<int> dataDetail)
|
||||
: super.parseData(commandType, dataDetail) {
|
||||
data = dataDetail;
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,8 @@ const saveBluePublicKey = "BluePublicKey";
|
||||
const saveBluePrivateKey = "BluePrivateKey";
|
||||
const saveBlueSignKey = "BlueSignKey";
|
||||
const saveBlueToken = "BlueGetToken";
|
||||
const currentConnectionLockId = "CurrentConnectionLockId";
|
||||
const currentConnectionMacAddress = "CurrentConnectionMacAddress";
|
||||
|
||||
class IoManager {
|
||||
|
||||
|
||||
@ -6,7 +6,9 @@ import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||||
import 'package:star_lock/blue/blue_manage.dart';
|
||||
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_transferPermissions.dart';
|
||||
|
||||
import '../tools/storage.dart';
|
||||
import 'io_protocol/io_addUser.dart';
|
||||
@ -73,10 +75,9 @@ class CommandReciverManager {
|
||||
// print("getPrivateKeyList$getPrivateKeyList");
|
||||
|
||||
// 解密
|
||||
// String key = SM4.createHexKey(key: radixHex16String(getPrivateKeyList!));
|
||||
oriDataList = SM4.decrypt(getDataList, key: getPrivateKeyList, mode: SM4CryptoMode.ECB);
|
||||
oriDataList = oriDataList.sublist(0, oriLen);
|
||||
// print("SM4 oriDataList:$oriDataList");
|
||||
print("SM4 oriDataList:$oriDataList");
|
||||
break;
|
||||
|
||||
}
|
||||
@ -132,6 +133,16 @@ class CommandReciverManager {
|
||||
reply = EditUserReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.transferPermissions:
|
||||
{
|
||||
reply = TransferPermissionsReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
case CommandType.factoryDataReset:
|
||||
{
|
||||
reply = FactoryDataResetReply.parseData(commandType, data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return reply;
|
||||
}
|
||||
|
||||
@ -4,9 +4,11 @@ import 'package:star_lock/blue/io_protocol/io_getLockStatu.dart';
|
||||
|
||||
import 'io_protocol/io_addUser.dart';
|
||||
import 'io_protocol/io_editUser.dart';
|
||||
import 'io_protocol/io_factoryDataReset.dart';
|
||||
import 'io_protocol/io_getPrivateKey.dart';
|
||||
import 'io_protocol/io_getPublicKey.dart';
|
||||
import 'io_protocol/io_openLock.dart';
|
||||
import 'io_protocol/io_transferPermissions.dart';
|
||||
import 'sender_data.dart';
|
||||
|
||||
class IoSenderManage {
|
||||
@ -170,4 +172,53 @@ class IoSenderManage {
|
||||
privateKey: privateKey,
|
||||
), callBack:callBack);
|
||||
}
|
||||
|
||||
//todo:转移权限
|
||||
static void senderTransferPermissions({
|
||||
String? lockID,
|
||||
String? authUserID,
|
||||
String? keyID,
|
||||
String? oldUserID,
|
||||
String? newUserID,
|
||||
int? needAuthor,
|
||||
List<int>? publicKey,
|
||||
List<int>? privateKey,
|
||||
List<int>? token,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: TransferPermissionsCommand(
|
||||
lockID: lockID,
|
||||
authUserID: authUserID,
|
||||
keyID: keyID,
|
||||
oldUserID: oldUserID,
|
||||
newUserID: newUserID,
|
||||
needAuthor: needAuthor,
|
||||
publicKey: publicKey,
|
||||
privateKey: privateKey,
|
||||
token: token
|
||||
), callBack:callBack);
|
||||
}
|
||||
|
||||
//todo:恢复出厂设置
|
||||
static void senderFactoryDataReset({
|
||||
String? lockID,
|
||||
String? userID,
|
||||
String? keyID,
|
||||
List<int>? publicKey,
|
||||
List<int>? privateKey,
|
||||
List<int>? token,
|
||||
int? needAuthor,
|
||||
CommandSendCallBack? callBack}) {
|
||||
CommandSenderManager().managerSendData(
|
||||
command: FactoryDataResetCommand(
|
||||
lockID: lockID,
|
||||
userID: userID,
|
||||
keyID: keyID,
|
||||
needAuthor: needAuthor,
|
||||
publicKey: publicKey,
|
||||
privateKey: privateKey,
|
||||
token: token
|
||||
), callBack:callBack);
|
||||
}
|
||||
|
||||
}
|
||||
@ -31,7 +31,11 @@ class MyApp extends StatefulWidget {
|
||||
State<MyApp> createState() => _MyAppState();
|
||||
}
|
||||
|
||||
// 注册 RouteObserver 作为 navigation observer.
|
||||
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
|
||||
|
||||
class _MyAppState extends State<MyApp> with WidgetsBindingObserver, BaseWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ScreenUtilInit(
|
||||
@ -41,6 +45,7 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver, BaseWidget {
|
||||
|
||||
GetMaterialApp _initMaterialApp() => GetMaterialApp(
|
||||
title: 'Star Lock',
|
||||
navigatorObservers: [routeObserver],
|
||||
translations: TranslationMessage(),
|
||||
supportedLocales: appDept.deptSupportedLocales,
|
||||
localizationsDelegates: const [
|
||||
@ -134,4 +139,4 @@ Future _setCommonServices() async {
|
||||
await Get.putAsync(() => PlatformInfoService().init());
|
||||
await Get.putAsync(() => DeviceInfoService().init());
|
||||
Get.log(PlatformInfoService.to.info.version);
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:flutter_reactive_ble/flutter_reactive_ble.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_type.dart';
|
||||
|
||||
@ -10,7 +11,6 @@ import '../../../blue/blue_manage.dart';
|
||||
import '../../../blue/io_protocol/io_openLock.dart';
|
||||
import '../../../blue/io_protocol/io_reply.dart';
|
||||
import '../../../blue/io_tool/io_manager.dart';
|
||||
import '../../../blue/io_tool/io_model.dart';
|
||||
import '../../../blue/io_tool/io_tool.dart';
|
||||
import '../../../blue/io_tool/manager_event_bus.dart';
|
||||
import '../../../blue/sender_manage.dart';
|
||||
@ -21,9 +21,11 @@ import 'lockDetail_state.dart';
|
||||
class LockDetailLogic extends BaseGetXController{
|
||||
final LockDetailState state = LockDetailState();
|
||||
|
||||
// 监听设备返回的数据
|
||||
late StreamSubscription<Reply> _replySubscription;
|
||||
void _initReplySubscription() {
|
||||
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((reply) async {
|
||||
// 开门
|
||||
if(reply is OpenDoorReply) {
|
||||
_replyOpenLock(reply);
|
||||
}
|
||||
@ -37,9 +39,15 @@ class LockDetailLogic extends BaseGetXController{
|
||||
if(reply is EditUserReply){
|
||||
_replyEditUserKey(reply);
|
||||
}
|
||||
|
||||
// 恢复出厂设置
|
||||
if(reply is FactoryDataResetReply){
|
||||
_replyFactoryDataResetKey(reply);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 开门数据解析
|
||||
Future<void> _replyOpenLock(Reply reply) async {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
@ -97,6 +105,7 @@ class LockDetailLogic extends BaseGetXController{
|
||||
}
|
||||
}
|
||||
|
||||
// 获取锁状态数据解析
|
||||
Future<void> _replyGetLockStatus(Reply reply) async {
|
||||
int status = reply.data[2];
|
||||
switch(status){
|
||||
@ -169,6 +178,7 @@ class LockDetailLogic extends BaseGetXController{
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑用户数据解析
|
||||
Future<void> _replyEditUserKey(Reply reply) async {
|
||||
var token = reply.data.sublist(2, 6);
|
||||
var saveStrList = changeIntListToStringList(token);
|
||||
@ -217,7 +227,7 @@ class LockDetailLogic extends BaseGetXController{
|
||||
break;
|
||||
case 0x09:
|
||||
// 权限校验错误
|
||||
print("${reply.commandType!.typeValue} 添加用户权限校验错误");
|
||||
print("${reply.commandType!.typeValue} 权限校验错误");
|
||||
|
||||
break;
|
||||
default:
|
||||
@ -228,6 +238,63 @@ class LockDetailLogic extends BaseGetXController{
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复出厂设置数据解析
|
||||
Future<void> _replyFactoryDataResetKey(Reply reply) async {
|
||||
var token = reply.data.sublist(2, 6);
|
||||
var saveStrList = changeIntListToStringList(token);
|
||||
print("_replyFactoryDataResetKeyToken:$token");
|
||||
Storage.setStringList(saveBlueToken, saveStrList);
|
||||
|
||||
int status = reply.data[6];
|
||||
print("status:$status");
|
||||
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
print("${reply.commandType!.typeValue} 数据解析成功");
|
||||
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
print("${reply.commandType!.typeValue} 需要鉴权");
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var publicKey = await Storage.getStringList(saveBluePublicKey);
|
||||
List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
||||
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
|
||||
IoSenderManage.senderFactoryDataReset(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
userID:"100001",
|
||||
keyID:"1",
|
||||
needAuthor:1,
|
||||
publicKey:publicKeyDataList,
|
||||
privateKey:getPrivateKeyList,
|
||||
token: getTokenList
|
||||
);
|
||||
break;
|
||||
case 0x07:
|
||||
//无权限
|
||||
print("${reply.commandType!.typeValue} 用户无权限");
|
||||
|
||||
break;
|
||||
case 0x09:
|
||||
// 权限校验错误
|
||||
print("${reply.commandType!.typeValue} 权限校验错误");
|
||||
|
||||
break;
|
||||
default:
|
||||
//失败
|
||||
print("${reply.commandType!.typeValue} 失败");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 点击开门事件
|
||||
Future<void> openDoorAction() async {
|
||||
BlueManage().judgeReconnect("AD01447A-30B5-A780-E778-DED3BDCB613E", "TMH_c3570480da8d", (DeviceConnectionState state) async {
|
||||
if (state == DeviceConnectionState.connected){
|
||||
@ -255,6 +322,7 @@ class LockDetailLogic extends BaseGetXController{
|
||||
});
|
||||
}
|
||||
|
||||
// 编辑用户事件
|
||||
Future<void> editLockUserAction() async {
|
||||
BlueManage().judgeReconnect("AD01447A-30B5-A780-E778-DED3BDCB613E", "TMH_c3570480da8d", (DeviceConnectionState state) async {
|
||||
if (state == DeviceConnectionState.connected){
|
||||
@ -289,19 +357,75 @@ class LockDetailLogic extends BaseGetXController{
|
||||
});
|
||||
}
|
||||
|
||||
// 转移权限
|
||||
Future<void> transferPermissionsAction() async {
|
||||
BlueManage().judgeReconnect("AD01447A-30B5-A780-E778-DED3BDCB613E", "TMH_c3570480da8d", (DeviceConnectionState state) async {
|
||||
if (state == DeviceConnectionState.connected){
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var publicKey = await Storage.getStringList(saveBluePublicKey);
|
||||
List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
||||
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
print("openDoorTokenPubToken:$getTokenList");
|
||||
|
||||
IoSenderManage.senderTransferPermissions(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
authUserID:"100001",
|
||||
keyID:"1",
|
||||
oldUserID:"100001",
|
||||
newUserID:"100002",
|
||||
needAuthor:1,
|
||||
publicKey:publicKeyDataList,
|
||||
privateKey:getPrivateKeyList,
|
||||
token: getTokenList
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 恢复出厂设置
|
||||
Future<void> factoryDataResetAction() async {
|
||||
BlueManage().judgeReconnect("AD01447A-30B5-A780-E778-DED3BDCB613E", "TMH_c3570480da8d", (DeviceConnectionState state) async {
|
||||
if (state == DeviceConnectionState.connected){
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var publicKey = await Storage.getStringList(saveBluePublicKey);
|
||||
List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
||||
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = changeStringListToIntList(token!);
|
||||
|
||||
IoSenderManage.senderFactoryDataReset(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
userID:"100001",
|
||||
keyID:"1",
|
||||
needAuthor:1,
|
||||
publicKey:publicKeyDataList,
|
||||
privateKey:getPrivateKeyList,
|
||||
token: getTokenList
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 备用逻辑,进入管理钥匙界面默认连接
|
||||
Future<void> connectBlue() async {
|
||||
// 进来之后首先连接
|
||||
// BlueManage().connect("AD01447A-30B5-A780-E778-DED3BDCB613E", "TMH_c3570480da8d", connectStateCallBack: (DeviceConnectionState state) async {
|
||||
// if (state == DeviceConnectionState.connected){
|
||||
// var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
// List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
// IoSenderManage.senderGetLockStatu(
|
||||
// lockID:BlueManage().connectDeviceName,
|
||||
// userID:"100001",
|
||||
// privateKey:getPrivateKeyList,
|
||||
// );
|
||||
// }
|
||||
// });
|
||||
BlueManage().connect("AD01447A-30B5-A780-E778-DED3BDCB613E", "TMH_c3570480da8d", connectStateCallBack: (DeviceConnectionState state) async {
|
||||
if (state == DeviceConnectionState.connected){
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
IoSenderManage.senderGetLockStatu(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
userID:"100001",
|
||||
privateKey:getPrivateKeyList,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -310,6 +434,10 @@ class LockDetailLogic extends BaseGetXController{
|
||||
super.onReady();
|
||||
print("onReady()");
|
||||
_initReplySubscription();
|
||||
|
||||
BlueManage().startScan((v){
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -318,8 +446,11 @@ class LockDetailLogic extends BaseGetXController{
|
||||
super.onInit();
|
||||
print("onInit()");
|
||||
|
||||
BlueManage().connectDeviceName = "TMH_c3570480da8d";
|
||||
BlueManage().connectDeviceId = "AD01447A-30B5-A780-E778-DED3BDCB613E";
|
||||
|
||||
// 进来第一步开始扫描
|
||||
connectBlue();
|
||||
// connectBlue();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -4,6 +4,8 @@ import 'package:get/get.dart';
|
||||
|
||||
import '../../../appRouters.dart';
|
||||
import '../../../app_settings/app_colors.dart';
|
||||
import '../../../blue/io_tool/io_manager.dart';
|
||||
import '../../../tools/storage.dart';
|
||||
import '../../../tools/titleAppBar.dart';
|
||||
import '../../../translations/trans_lib.dart';
|
||||
import 'lockDetail_logic.dart';
|
||||
@ -21,6 +23,7 @@ class _LockDetailPageState extends State<LockDetailPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: TitleAppBar(
|
||||
@ -76,8 +79,10 @@ class _LockDetailPageState extends State<LockDetailPage> {
|
||||
Center(
|
||||
child: GestureDetector(
|
||||
onTap: (){
|
||||
// logic.transferPermissionsAction();
|
||||
// logic.openDoorAction();
|
||||
logic.editLockUserAction();
|
||||
// logic.editLockUserAction();
|
||||
logic.factoryDataResetAction();
|
||||
},
|
||||
child: Image.asset('images/main/icon_main_openLockBtn.png',
|
||||
width: 268.w, height: 268.w),
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import 'lockMain_logic.dart';
|
||||
|
||||
class LockMainBinding extends Bindings {
|
||||
|
||||
@ -0,0 +1,319 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:amap_flutter_location/amap_flutter_location.dart';
|
||||
import 'package:amap_flutter_location/amap_location_option.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:amap_flutter_map/amap_flutter_map.dart';
|
||||
import 'package:amap_flutter_base/amap_flutter_base.dart';
|
||||
|
||||
import '../../../app_settings/app_colors.dart';
|
||||
import '../../../main.dart';
|
||||
|
||||
class LockAddressGaoDePage extends StatefulWidget {
|
||||
const LockAddressGaoDePage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<LockAddressGaoDePage> createState() => _LockAddressGaoDePageState();
|
||||
}
|
||||
|
||||
class _LockAddressGaoDePageState extends State<LockAddressGaoDePage>{
|
||||
// 高德地图
|
||||
Map<String, Object>? _locationResult;
|
||||
StreamSubscription<Map<String, Object>>? _locationListener;
|
||||
final AMapFlutterLocation _locationPlugin = AMapFlutterLocation();
|
||||
late AMapController _mapController;
|
||||
|
||||
static const CameraPosition _kInitialPosition = CameraPosition(
|
||||
target: LatLng(113.919112, 22.653728),
|
||||
zoom: 10.0,
|
||||
);
|
||||
|
||||
List<Widget> get _approvalNumberWidget => <Widget>[];
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
/// 设置是否已经包含高德隐私政策并弹窗展示显示用户查看,如果未包含或者没有弹窗展示,高德定位SDK将不会工作
|
||||
///
|
||||
/// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
|
||||
/// <b>必须保证在调用定位功能之前调用, 建议首次启动App时弹出《隐私政策》并取得用户同意</b>
|
||||
///
|
||||
/// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
|
||||
///
|
||||
/// [hasContains] 隐私声明中是否包含高德隐私政策说明
|
||||
///
|
||||
/// [hasShow] 隐私权政策是否弹窗展示告知用户
|
||||
AMapFlutterLocation.updatePrivacyShow(true, true);
|
||||
|
||||
/// 设置是否已经取得用户同意,如果未取得用户同意,高德定位SDK将不会工作
|
||||
///
|
||||
/// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
|
||||
///
|
||||
/// <b>必须保证在调用定位功能之前调用, 建议首次启动App时弹出《隐私政策》并取得用户同意</b>
|
||||
///
|
||||
/// [hasAgree] 隐私权政策是否已经取得用户同意
|
||||
AMapFlutterLocation.updatePrivacyAgree(true);
|
||||
|
||||
/// 动态申请定位权限
|
||||
requestPermission();
|
||||
|
||||
///设置Android和iOS的apiKey<br>
|
||||
///key的申请请参考高德开放平台官网说明<br>
|
||||
///Android: https://lbs.amap.com/api/android-location-sdk/guide/create-project/get-key
|
||||
///iOS: https://lbs.amap.com/api/ios-location-sdk/guide/create-project/get-key
|
||||
AMapFlutterLocation.setApiKey("1dbf56e2e8a4d0e4cdc2df9efd36bc71", "dfb64c0463cb53927914364b5c09aba0");
|
||||
|
||||
///iOS 获取native精度类型
|
||||
if (Platform.isIOS) {
|
||||
requestAccuracyAuthorization();
|
||||
}
|
||||
|
||||
///注册定位结果监听
|
||||
_locationListener = _locationPlugin.onLocationChanged().listen((Map<String, Object> result) {
|
||||
setState(() {
|
||||
_locationResult = result;
|
||||
if (_locationResult != null) {
|
||||
_locationResult?.forEach((key, value) {
|
||||
print("key:$key value:$value");
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
_startLocation();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
///使用默认属性创建一个地图
|
||||
final AMapWidget map = AMapWidget(
|
||||
apiKey: const AMapApiKey(androidKey: '900f72eeee0f21e435cebb0ef155582a', iosKey: '4dfdec97b7bf0b8c13e94777103015a9'),
|
||||
onMapCreated: onMapCreated,
|
||||
// initialCameraPosition: _kInitialPosition
|
||||
);
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Positioned(
|
||||
left: 10.w, bottom: 30.h,
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: _approvalNumberWidget),
|
||||
)
|
||||
),
|
||||
Positioned(
|
||||
left: 20.w, right: 20.w, bottom: 100.h,
|
||||
child: Container(
|
||||
// height: h(106),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.mainColor,
|
||||
borderRadius: BorderRadius.circular(15.w),
|
||||
),
|
||||
child:Column(
|
||||
children: [
|
||||
Container(
|
||||
// height: h(53),
|
||||
padding: EdgeInsets.only(top: 15.h, bottom: 15, left:15.w, right: 15.w),
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset('images/main/icon_addUserShowAddress.png', width: 30.w, height: 30.w),
|
||||
SizedBox(width: 10.w),
|
||||
Expanded(
|
||||
child: Text("广东省深圳市宏发科技园", style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500, overflow: TextOverflow.clip))
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(height: 1.h, color: const Color(0xFF021732),),
|
||||
Container(
|
||||
// height: h(52),
|
||||
padding: EdgeInsets.only(top: 15.h, bottom: 15, left:15.w, right: 15.w),
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset('images/main/icon_addUserAddressShowTime.png', width: 30.w, height: 30.w),
|
||||
SizedBox(width: 10.w,),
|
||||
Expanded(
|
||||
child: Text("2023.8.22 15.14", style: const TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500),)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
),),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void onMapCreated(AMapController controller) {
|
||||
setState(() {
|
||||
_mapController = controller;
|
||||
getApprovalNumber();
|
||||
});
|
||||
}
|
||||
|
||||
/// 获取审图号
|
||||
void getApprovalNumber() async {
|
||||
//普通地图审图号
|
||||
String? mapContentApprovalNumber =
|
||||
await _mapController.getMapContentApprovalNumber();
|
||||
//卫星地图审图号
|
||||
String? satelliteImageApprovalNumber =
|
||||
await _mapController.getSatelliteImageApprovalNumber();
|
||||
setState(() {
|
||||
if (null != mapContentApprovalNumber) {
|
||||
_approvalNumberWidget.add(Text(mapContentApprovalNumber));
|
||||
}
|
||||
if (null != satelliteImageApprovalNumber) {
|
||||
_approvalNumberWidget.add(Text(satelliteImageApprovalNumber));
|
||||
}
|
||||
});
|
||||
print('地图审图号(普通地图): $mapContentApprovalNumber');
|
||||
print('地图审图号(卫星地图): $satelliteImageApprovalNumber');
|
||||
}
|
||||
|
||||
///设置定位参数
|
||||
void _setLocationOption() {
|
||||
AMapLocationOption locationOption = new AMapLocationOption();
|
||||
|
||||
///是否单次定位
|
||||
locationOption.onceLocation = false;
|
||||
|
||||
///是否需要返回逆地理信息
|
||||
locationOption.needAddress = true;
|
||||
|
||||
///逆地理信息的语言类型
|
||||
locationOption.geoLanguage = GeoLanguage.DEFAULT;
|
||||
|
||||
locationOption.desiredLocationAccuracyAuthorizationMode = AMapLocationAccuracyAuthorizationMode.ReduceAccuracy;
|
||||
|
||||
locationOption.fullAccuracyPurposeKey = "AMapLocationScene";
|
||||
|
||||
///设置Android端连续定位的定位间隔
|
||||
locationOption.locationInterval = 2000;
|
||||
|
||||
///设置Android端的定位模式<br>
|
||||
///可选值:<br>
|
||||
///<li>[AMapLocationMode.Battery_Saving]</li>
|
||||
///<li>[AMapLocationMode.Device_Sensors]</li>
|
||||
///<li>[AMapLocationMode.Hight_Accuracy]</li>
|
||||
locationOption.locationMode = AMapLocationMode.Hight_Accuracy;
|
||||
|
||||
///设置iOS端的定位最小更新距离<br>
|
||||
locationOption.distanceFilter = -1;
|
||||
|
||||
///设置iOS端期望的定位精度
|
||||
/// 可选值:<br>
|
||||
/// <li>[DesiredAccuracy.Best] 最高精度</li>
|
||||
/// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
|
||||
/// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
|
||||
/// <li>[DesiredAccuracy.Kilometer] 1000米</li>
|
||||
/// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
|
||||
locationOption.desiredAccuracy = DesiredAccuracy.Best;
|
||||
|
||||
///设置iOS端是否允许系统暂停定位
|
||||
locationOption.pausesLocationUpdatesAutomatically = false;
|
||||
|
||||
///将定位参数设置给定位插件
|
||||
_locationPlugin.setLocationOption(locationOption);
|
||||
}
|
||||
|
||||
///开始定位
|
||||
void _startLocation() {
|
||||
///开始定位之前设置定位参数
|
||||
_setLocationOption();
|
||||
_locationPlugin.startLocation();
|
||||
}
|
||||
|
||||
///停止定位
|
||||
void _stopLocation() {
|
||||
_locationPlugin.stopLocation();
|
||||
}
|
||||
|
||||
///获取iOS native的accuracyAuthorization类型
|
||||
void requestAccuracyAuthorization() async {
|
||||
AMapAccuracyAuthorization currentAccuracyAuthorization = await _locationPlugin.getSystemAccuracyAuthorization();
|
||||
if (currentAccuracyAuthorization == AMapAccuracyAuthorization.AMapAccuracyAuthorizationFullAccuracy) {
|
||||
print("精确定位类型");
|
||||
} else if (currentAccuracyAuthorization == AMapAccuracyAuthorization.AMapAccuracyAuthorizationReducedAccuracy) {
|
||||
print("模糊定位类型");
|
||||
} else {
|
||||
print("未知定位类型");
|
||||
}
|
||||
}
|
||||
|
||||
/// 动态申请定位权限
|
||||
void requestPermission() async {
|
||||
// 申请权限
|
||||
bool hasLocationPermission = await requestLocationPermission();
|
||||
if (hasLocationPermission) {
|
||||
print("定位权限申请通过");
|
||||
} else {
|
||||
print("定位权限申请不通过");
|
||||
}
|
||||
}
|
||||
|
||||
/// 申请定位权限
|
||||
/// 授予定位权限返回true, 否则返回false
|
||||
Future<bool> requestLocationPermission() async {
|
||||
//获取当前的权限
|
||||
var status = await Permission.location.status;
|
||||
if (status == PermissionStatus.granted) {
|
||||
//已经授权
|
||||
return true;
|
||||
} else {
|
||||
//未授权则发起一次申请
|
||||
status = await Permission.location.request();
|
||||
if (status == PermissionStatus.granted) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// @override
|
||||
// void dispose() {
|
||||
// super.dispose();
|
||||
//
|
||||
// _stopLocation();
|
||||
//
|
||||
// ///移除定位监听
|
||||
// if (null != _locationListener) {
|
||||
// _locationListener?.cancel();
|
||||
// }
|
||||
//
|
||||
// ///销毁定位
|
||||
// _locationPlugin.destroy();
|
||||
//
|
||||
// print("高德地图定位销毁了");
|
||||
// }
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
|
||||
_stopLocation();
|
||||
|
||||
///移除定位监听
|
||||
if (null != _locationListener) {
|
||||
_locationListener?.cancel();
|
||||
}
|
||||
|
||||
///销毁定位
|
||||
_locationPlugin.destroy();
|
||||
|
||||
print("地图界面销毁了");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LockAddressGooglePage extends StatefulWidget {
|
||||
const LockAddressGooglePage({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<LockAddressGooglePage> createState() => _LockAddressGooglePageState();
|
||||
}
|
||||
|
||||
class _LockAddressGooglePageState extends State<LockAddressGooglePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const Placeholder();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
|
||||
import '../../../tools/baseGetXController.dart';
|
||||
import 'lockAddress_state.dart';
|
||||
|
||||
class LockAddressLogic extends BaseGetXController {
|
||||
|
||||
final LockAddressState state = LockAddressState();
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
// TODO: implement onReady
|
||||
super.onReady();
|
||||
print("onReady()");
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
super.onInit();
|
||||
print("onInit()");
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
// TODO: implement onClose
|
||||
super.onClose();
|
||||
print("地图界面onClose()");
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,12 +1,18 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../appRouters.dart';
|
||||
import '../../../app_settings/app_colors.dart';
|
||||
import '../../../main.dart';
|
||||
import '../../../tools/titleAppBar.dart';
|
||||
import '../../../translations/trans_lib.dart';
|
||||
|
||||
import 'lockAddressGaoDe_page.dart';
|
||||
|
||||
class LockAddressPage extends StatefulWidget {
|
||||
const LockAddressPage({Key? key}) : super(key: key);
|
||||
|
||||
@ -14,27 +20,58 @@ class LockAddressPage extends StatefulWidget {
|
||||
State<LockAddressPage> createState() => _LockAddressPageState();
|
||||
}
|
||||
|
||||
class _LockAddressPageState extends State<LockAddressPage> {
|
||||
class _LockAddressPageState extends State<LockAddressPage> with RouteAware{
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.mainBackgroundColor,
|
||||
appBar: TitleAppBar(
|
||||
barTitle: "锁地址",
|
||||
barTitle: TranslationLoader.lanKeys!.lockAddress!.tr,
|
||||
haveBack: true,
|
||||
backgroundColor: AppColors.mainColor,
|
||||
actionsList: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
"保存",
|
||||
TranslationLoader.lanKeys!.next!.tr,
|
||||
style: TextStyle(color: Colors.white, fontSize: 24.sp),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.pushNamed(context, Routers.saveLockPage);
|
||||
Get.toNamed(Routers.saveLockPage)!.then((value) {
|
||||
dispose();
|
||||
});
|
||||
// Navigator.pushNamed(context, Routers.saveLockPage);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Container());
|
||||
body: LockAddressGaoDePage());
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
routeObserver.unsubscribe(this);
|
||||
print("地图界面销毁了");
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
// 订阅 routeObserver,之后就会尝试调用抽象类 RouteAware 的方法
|
||||
routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute);
|
||||
}
|
||||
|
||||
@override
|
||||
void didPush() {
|
||||
// 当前页面入栈
|
||||
print("当前页面入栈");
|
||||
}
|
||||
|
||||
@override
|
||||
void didPopNext() {
|
||||
// 当前路由的下个路由出栈,且当前页面显示
|
||||
print("当前路由的下个路由出栈,且当前页面显示");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
class LockAddressState {
|
||||
|
||||
}
|
||||
@ -1,12 +1,15 @@
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:get_storage/get_storage.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/tools/baseGetXController.dart';
|
||||
|
||||
import '../../../appRouters.dart';
|
||||
import '../../../blue/blue_manage.dart';
|
||||
import '../../../blue/io_protocol/io_addUser.dart';
|
||||
import '../../../blue/io_protocol/io_reply.dart';
|
||||
@ -38,10 +41,6 @@ class NearbyLockLogic extends BaseGetXController{
|
||||
if(reply is GetPrivateKeyReply) {
|
||||
_replyGetPrivateKeyKey(reply);
|
||||
}
|
||||
|
||||
if(reply is AddUserReply) {
|
||||
_replyAddUserKey(reply);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -91,34 +90,7 @@ class NearbyLockLogic extends BaseGetXController{
|
||||
var savePrivateKeyList = changeIntListToStringList(privateKey);
|
||||
Storage.setStringList(saveBluePrivateKey, savePrivateKeyList);
|
||||
|
||||
// signKey
|
||||
List<int> signKey = reply.data.sublist(16);
|
||||
var savesignKeyList = changeIntListToStringList(signKey);
|
||||
Storage.setStringList(saveBlueSignKey, savesignKeyList);
|
||||
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = [0,0,0,0];
|
||||
if(token != null){
|
||||
getTokenList = changeStringListToIntList(token);
|
||||
}
|
||||
|
||||
print("privateKey:$privateKey signKey:$signKey");
|
||||
IoSenderManage.senderAddUser(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
authUserID:"100001",
|
||||
keyID:"1",
|
||||
userID:"100001",
|
||||
openMode:1,
|
||||
keyType:1,
|
||||
startDate:0x11223344,
|
||||
expireDate:0x11223344,
|
||||
role:255,
|
||||
password:"123456",
|
||||
needAuthor:1,
|
||||
publicKey:publicKeyDataList,
|
||||
privateKey:privateKey,
|
||||
token: getTokenList
|
||||
);
|
||||
Get.toNamed(Routers.lockAddressPage);
|
||||
break;
|
||||
case 0x07:
|
||||
//无权限
|
||||
@ -136,68 +108,6 @@ class NearbyLockLogic extends BaseGetXController{
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _replyAddUserKey(Reply reply) async {
|
||||
var lockId = reply.data.sublist(2, 42);
|
||||
print("lockId:$lockId");
|
||||
|
||||
var token = reply.data.sublist(42, 46);
|
||||
List<String> strTokenList = changeIntListToStringList(token);
|
||||
Storage.setStringList(saveBlueToken, strTokenList);
|
||||
print("token:$token");
|
||||
|
||||
int status = reply.data[46];
|
||||
print("status:$status");
|
||||
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
print("添加用户数据解析成功");
|
||||
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
print("需要鉴权");
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var publicKey = await Storage.getStringList(saveBluePublicKey);
|
||||
List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
||||
|
||||
IoSenderManage.senderAddUser(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
authUserID:"100001",
|
||||
keyID:"1",
|
||||
userID:"100001",
|
||||
openMode:1,
|
||||
keyType:1,
|
||||
startDate:0x11223344,
|
||||
expireDate:0x11223344,
|
||||
role:255,
|
||||
password:"123456",
|
||||
needAuthor:1,
|
||||
publicKey:publicKeyDataList,
|
||||
privateKey:getPrivateKeyList,
|
||||
token: token
|
||||
);
|
||||
break;
|
||||
case 0x07:
|
||||
//无权限
|
||||
print("用户无权限");
|
||||
|
||||
break;
|
||||
case 0x09:
|
||||
// 权限校验错误
|
||||
print("添加用户权限校验错误");
|
||||
|
||||
break;
|
||||
default:
|
||||
//失败
|
||||
print("领锁失败");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
// TODO: implement onReady
|
||||
|
||||
@ -0,0 +1,56 @@
|
||||
|
||||
class SaveLockEntity {
|
||||
int? errorCode;
|
||||
String? description;
|
||||
String? errorMsg;
|
||||
SaveLockEntityData? data;
|
||||
|
||||
SaveLockEntity(
|
||||
{this.errorCode, this.description, this.errorMsg, this.data});
|
||||
|
||||
SaveLockEntity.fromJson(Map<String, dynamic> json) {
|
||||
errorCode = json['errorCode'];
|
||||
description = json['description'];
|
||||
errorMsg = json['errorMsg'];
|
||||
data = json['data'] != null
|
||||
? SaveLockEntityData.fromJson(json['data'])
|
||||
: null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['errorCode'] = errorCode;
|
||||
data['description'] = description;
|
||||
data['errorMsg'] = errorMsg;
|
||||
if (this.data != null) {
|
||||
data['data'] = this.data!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class SaveLockEntityData {
|
||||
String? lockId;
|
||||
String? nbRegisterSuccess;
|
||||
String? keyId;
|
||||
|
||||
SaveLockEntityData(
|
||||
{ this.lockId,
|
||||
this.nbRegisterSuccess,
|
||||
this.keyId});
|
||||
|
||||
SaveLockEntityData.fromJson(Map<String, dynamic> json) {
|
||||
lockId = json['lockId'];
|
||||
nbRegisterSuccess = json['nbRegisterSuccess'];
|
||||
keyId = json['keyId'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['lockId'] = lockId;
|
||||
data['nbRegisterSuccess'] = nbRegisterSuccess;
|
||||
data['keyId'] = keyId;
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
281
star_lock/lib/mine/addLock/saveLock/saveLock_logic.dart
Normal file
281
star_lock/lib/mine/addLock/saveLock/saveLock_logic.dart
Normal file
@ -0,0 +1,281 @@
|
||||
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../blue/blue_manage.dart';
|
||||
import '../../../blue/io_protocol/io_addUser.dart';
|
||||
import '../../../blue/io_protocol/io_getLockStatu.dart';
|
||||
import '../../../blue/io_protocol/io_reply.dart';
|
||||
import '../../../blue/io_tool/io_manager.dart';
|
||||
import '../../../blue/io_tool/io_tool.dart';
|
||||
import '../../../blue/io_tool/manager_event_bus.dart';
|
||||
import '../../../blue/sender_manage.dart';
|
||||
import '../../../network/api_repository.dart';
|
||||
import '../../../tools/baseGetXController.dart';
|
||||
import '../../../tools/storage.dart';
|
||||
import 'saveLock_state.dart';
|
||||
|
||||
class SaveLockLogic extends BaseGetXController {
|
||||
|
||||
final SaveLockState state = SaveLockState();
|
||||
|
||||
// 获取解析后的数据
|
||||
late StreamSubscription<Reply> _replySubscription;
|
||||
void _initReplySubscription() {
|
||||
_replySubscription = EventBusManager().eventBus!.on<Reply>().listen((reply) {
|
||||
if(reply is AddUserReply) {
|
||||
_replyAddUserKey(reply);
|
||||
}
|
||||
|
||||
// 获取锁状态
|
||||
if(reply is GetLockStatuReply) {
|
||||
_replyGetLockStatus(reply);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _replyAddUserKey(Reply reply) async {
|
||||
var lockId = reply.data.sublist(2, 42);
|
||||
print("lockId:$lockId");
|
||||
|
||||
var token = reply.data.sublist(42, 46);
|
||||
List<String> strTokenList = changeIntListToStringList(token);
|
||||
Storage.setStringList(saveBlueToken, strTokenList);
|
||||
print("token:$token");
|
||||
|
||||
int status = reply.data[46];
|
||||
print("status:$status");
|
||||
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
print("添加用户数据解析成功");
|
||||
bindBlueAdmin();
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
print("需要鉴权");
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var publicKey = await Storage.getStringList(saveBluePublicKey);
|
||||
List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
||||
|
||||
IoSenderManage.senderAddUser(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
authUserID:"100001",
|
||||
keyID:"1",
|
||||
userID:"100001",
|
||||
openMode:1,
|
||||
keyType:1,
|
||||
startDate:0x11223344,
|
||||
expireDate:0x11223344,
|
||||
role:255,
|
||||
password:"123456",
|
||||
needAuthor:1,
|
||||
publicKey:publicKeyDataList,
|
||||
privateKey:getPrivateKeyList,
|
||||
token: token
|
||||
);
|
||||
break;
|
||||
case 0x07:
|
||||
//无权限
|
||||
print("用户无权限");
|
||||
|
||||
break;
|
||||
case 0x09:
|
||||
// 权限校验错误
|
||||
print("添加用户权限校验错误");
|
||||
|
||||
break;
|
||||
default:
|
||||
//失败
|
||||
print("领锁失败");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 获取锁状态数据解析
|
||||
Future<void> _replyGetLockStatus(Reply reply) async {
|
||||
int status = reply.data[2];
|
||||
switch(status){
|
||||
case 0x00:
|
||||
//成功
|
||||
print("${reply.commandType}数据解析成功");
|
||||
var softVersion = reply.data.sublist(3, 7);
|
||||
print("softVersion:$softVersion");
|
||||
|
||||
var power = reply.data[7];
|
||||
print("power:$power");
|
||||
|
||||
// APP 用户数量
|
||||
var appUserCount = reply.data.sublist(50, 53);
|
||||
print("appUserCount:$appUserCount");
|
||||
|
||||
// 黑名单用户数量
|
||||
var blacklistCount = reply.data[53];
|
||||
print("blacklistCount:$blacklistCount");
|
||||
|
||||
// 蓝牙钥匙数量
|
||||
var bleKeyCount = reply.data[54];
|
||||
print("bleKeyCount:$bleKeyCount");
|
||||
|
||||
// 剩余可添加用户数量
|
||||
var remainCount = reply.data.sublist(54, 56);
|
||||
print("remainCount:$remainCount");
|
||||
|
||||
// 未上传开锁记录数量
|
||||
var notUploadCount = reply.data.sublist(56, 58);
|
||||
print("notUploadCount:$notUploadCount");
|
||||
|
||||
// 已设置开门密码数量
|
||||
var pwdCount = reply.data[58];
|
||||
print("pwdCount:$pwdCount");
|
||||
|
||||
// 已设置开门指纹数量
|
||||
var fingerprintCount = reply.data[59];
|
||||
print("fingerprintCount:$fingerprintCount");
|
||||
|
||||
// 锁当前时间
|
||||
var lockTime = reply.data.sublist(60, 64);
|
||||
print("lockTime:$lockTime");
|
||||
|
||||
// 硬件版本信息,为固件升级提供判断依据
|
||||
var hardVersion = reply.data.sublist(64, 68);
|
||||
print("hardVersion:$hardVersion");
|
||||
|
||||
break;
|
||||
case 0x06:
|
||||
//无权限
|
||||
print("${reply.commandType}需要鉴权");
|
||||
|
||||
break;
|
||||
case 0x07:
|
||||
//无权限
|
||||
print("${reply.commandType}用户无权限");
|
||||
|
||||
break;
|
||||
case 0x09:
|
||||
// 权限校验错误
|
||||
print("${reply.commandType}权限校验错误");
|
||||
|
||||
break;
|
||||
default:
|
||||
//失败
|
||||
print("${reply.commandType}失败");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 保存事件,先调用蓝牙,蓝牙调用成功后再调用后台接口
|
||||
_saveLockAction(){
|
||||
addUserConnectBlue();
|
||||
}
|
||||
|
||||
// 添加用户
|
||||
Future<void> addUserConnectBlue() async {
|
||||
// 进来之后首先连接
|
||||
BlueManage().connect("AD01447A-30B5-A780-E778-DED3BDCB613E", "TMH_c3570480da8d", connectStateCallBack: (DeviceConnectionState state) async {
|
||||
if (state == DeviceConnectionState.connected){
|
||||
// 私钥
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
|
||||
var publicKey = await Storage.getStringList(saveBluePublicKey);
|
||||
List<int> publicKeyDataList = changeStringListToIntList(publicKey!);
|
||||
|
||||
var token = await Storage.getStringList(saveBlueToken);
|
||||
List<int> getTokenList = [0,0,0,0];
|
||||
if(token != null){
|
||||
getTokenList = changeStringListToIntList(token);
|
||||
}
|
||||
|
||||
IoSenderManage.senderAddUser(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
authUserID:"100001",
|
||||
keyID:"1",
|
||||
userID:"100001",
|
||||
openMode:1,
|
||||
keyType:1,
|
||||
startDate:0x11223344,
|
||||
expireDate:0x11223344,
|
||||
role:255,
|
||||
password:"123456",
|
||||
needAuthor:1,
|
||||
publicKey:publicKeyDataList,
|
||||
privateKey:getPrivateKeyList,
|
||||
token: getTokenList
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void bindBlueAdmin() async{
|
||||
var lockData = "";
|
||||
var lockDataMap = {};
|
||||
lockDataMap['lockId'] = BlueManage().connectDeviceName;
|
||||
lockDataMap['lockMac'] = BlueManage().connectDeviceId;
|
||||
lockData = json.encode(lockDataMap);
|
||||
|
||||
var entity = await ApiRepository.to.bindingBlueAdmin(
|
||||
bindingDate:DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
hotelMode:"2",
|
||||
lockAlias:state.aliName.value,
|
||||
lockData:lockData,
|
||||
nbInitSuccess:"0",
|
||||
position:"113.918912, 22.653670",
|
||||
deviceNo:"123456"
|
||||
);
|
||||
if(entity.errorCode!.codeIsSuccessful){
|
||||
Get.close(3);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取锁状态
|
||||
Future<void> _getLockStatus() async {
|
||||
// 进来之后首先连接
|
||||
BlueManage().judgeReconnect("AD01447A-30B5-A780-E778-DED3BDCB613E", "TMH_c3570480da8d", (DeviceConnectionState state) async {
|
||||
if (state == DeviceConnectionState.connected) {
|
||||
var privateKey = await Storage.getStringList(saveBluePrivateKey);
|
||||
List<int> getPrivateKeyList = changeStringListToIntList(privateKey!);
|
||||
IoSenderManage.senderGetLockStatu(
|
||||
lockID:BlueManage().connectDeviceName,
|
||||
userID:"100001",
|
||||
privateKey:getPrivateKeyList,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
// TODO: implement onReady
|
||||
super.onReady();
|
||||
print("onReady()");
|
||||
|
||||
_initReplySubscription();
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
// TODO: implement onInit
|
||||
super.onInit();
|
||||
print("onInit()");
|
||||
|
||||
_getLockStatus();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
// TODO: implement onClose
|
||||
super.onClose();
|
||||
_replySubscription.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@ -6,6 +7,7 @@ import '../../../app_settings/app_colors.dart';
|
||||
import '../../../tools/submitBtn.dart';
|
||||
import '../../../tools/titleAppBar.dart';
|
||||
import '../../../translations/trans_lib.dart';
|
||||
import 'saveLock_logic.dart';
|
||||
|
||||
class SaveLockPage extends StatefulWidget {
|
||||
const SaveLockPage({Key? key}) : super(key: key);
|
||||
@ -15,6 +17,9 @@ class SaveLockPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _SaveLockPageState extends State<SaveLockPage> {
|
||||
final logic = Get.put(SaveLockLogic());
|
||||
final state = Get.find<SaveLockLogic>().state;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@ -37,7 +42,14 @@ class _SaveLockPageState extends State<SaveLockPage> {
|
||||
// color: Colors.red,
|
||||
padding: EdgeInsets.only(left: 50.w, right: 50.w),
|
||||
child: TextField(
|
||||
controller: state.aliNameController,
|
||||
onChanged: (v){
|
||||
state.aliName.value = v;
|
||||
},
|
||||
textAlign:TextAlign.center,
|
||||
inputFormatters: [
|
||||
LengthLimitingTextInputFormatter(32),
|
||||
],
|
||||
// style:TextStyle(height: 1.1, fontSize: 36.sp, fontWeight: FontWeight.w400, color:AppColors.mainColor),
|
||||
decoration: InputDecoration(
|
||||
hintText: '请填写信息',
|
||||
|
||||
21
star_lock/lib/mine/addLock/saveLock/saveLock_state.dart
Normal file
21
star_lock/lib/mine/addLock/saveLock/saveLock_state.dart
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../blue/blue_manage.dart';
|
||||
|
||||
class SaveLockState {
|
||||
|
||||
var aliName = ''.obs;
|
||||
TextEditingController aliNameController = TextEditingController();
|
||||
|
||||
SaveLockState() {
|
||||
aliName.value = BlueManage().connectDeviceName;
|
||||
aliNameController.text = aliName.value;
|
||||
}
|
||||
|
||||
void onClose() {
|
||||
aliNameController.dispose();
|
||||
}
|
||||
}
|
||||
@ -17,4 +17,7 @@ abstract class Api {
|
||||
final String keyOperationRecordURL = '/lockRecords/list'; //电子钥匙操作记录
|
||||
final String uploadElectricQuantityURL =
|
||||
'/room/uploadElectricQuantity'; //锁电量更新
|
||||
|
||||
final String bindingBlueAdminURL =
|
||||
'/lock/bindAdmin'; //绑定蓝牙管理员
|
||||
}
|
||||
|
||||
@ -195,6 +195,27 @@ class ApiProvider extends BaseProvider {
|
||||
'searchStr': searchStr,
|
||||
'timezoneRawOffSet': timezoneRawOffSet
|
||||
}));
|
||||
|
||||
// 绑定蓝牙管理员
|
||||
Future<Response> bindingBlueAdmin(
|
||||
String bindingDate,
|
||||
String hotelMode,
|
||||
String lockAlias,
|
||||
String lockData,
|
||||
String nbInitSuccess,
|
||||
String position,
|
||||
String deviceNo) =>
|
||||
post(
|
||||
bindingBlueAdminURL.toUrl,
|
||||
jsonEncode({
|
||||
'bindingDate': bindingDate,
|
||||
'hotelMode': hotelMode,
|
||||
"lockAlias": lockAlias,
|
||||
'lockData': lockData,
|
||||
"nbInitSuccess": nbInitSuccess,
|
||||
'position': position,
|
||||
'deviceNo': deviceNo
|
||||
}));
|
||||
}
|
||||
|
||||
extension ExtensionString on String {
|
||||
|
||||
@ -5,6 +5,7 @@ import '../common/safetyVerification/entity/CheckSafetyVerificationEntity.dart';
|
||||
import '../common/safetyVerification/entity/SafetyVerificationEntity.dart';
|
||||
import '../login/login/entity/LoginEntity.dart';
|
||||
import '../login/register/entity/SendValidationCodeEntity.dart';
|
||||
import '../mine/addLock/saveLock/entity/SaveLockEntity.dart';
|
||||
import 'api_provider.dart';
|
||||
|
||||
class ApiRepository {
|
||||
@ -168,4 +169,24 @@ class ApiRepository {
|
||||
timezoneRawOffSet);
|
||||
return KeyOperationRecordEntity.fromJson(res.body);
|
||||
}
|
||||
|
||||
// 绑定蓝牙管理员
|
||||
Future<SaveLockEntity> bindingBlueAdmin({
|
||||
required String bindingDate,
|
||||
required String hotelMode,
|
||||
required String lockAlias,
|
||||
required String lockData,
|
||||
required String nbInitSuccess,
|
||||
required String position,
|
||||
required String deviceNo}) async {
|
||||
final res = await apiProvider.bindingBlueAdmin(
|
||||
bindingDate,
|
||||
hotelMode,
|
||||
lockAlias,
|
||||
lockData,
|
||||
nbInitSuccess,
|
||||
position,
|
||||
deviceNo);
|
||||
return SaveLockEntity.fromJson(res.body);
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +49,7 @@ class LoginInput extends StatelessWidget {
|
||||
controller: controller,
|
||||
onChanged: onchangeAction,
|
||||
autofocus: false,
|
||||
inputFormatters:inputFormatters,
|
||||
decoration: InputDecoration(
|
||||
//输入里面输入文字内边距设置
|
||||
contentPadding: const EdgeInsets.only(
|
||||
|
||||
@ -188,6 +188,7 @@ class LanKeyEntity {
|
||||
this.lanChinese,
|
||||
this.multilingual,
|
||||
this.addLock,
|
||||
this.lockAddress,
|
||||
this.selectLockType,
|
||||
this.videoIntercomDoorLock,
|
||||
this.NFCPassiveLock,
|
||||
@ -573,6 +574,7 @@ class LanKeyEntity {
|
||||
lanChinese = json['lanChinese'];
|
||||
multilingual = json['multilingual'];
|
||||
addLock = json['addLock'];
|
||||
lockAddress = json["lockAddress"];
|
||||
selectLockType = json['selectLockType'];
|
||||
videoIntercomDoorLock = json['videoIntercomDoorLock'];
|
||||
NFCPassiveLock = json['NFCPassiveLock'];
|
||||
@ -975,6 +977,7 @@ class LanKeyEntity {
|
||||
String? lanChinese;
|
||||
String? multilingual;
|
||||
String? addLock;
|
||||
String? lockAddress;
|
||||
String? selectLockType;
|
||||
String? videoIntercomDoorLock;
|
||||
String? NFCPassiveLock;
|
||||
@ -1374,6 +1377,7 @@ class LanKeyEntity {
|
||||
map['lanChinese'] = lanChinese;
|
||||
map['multilingual'] = multilingual;
|
||||
map['addLock'] = addLock;
|
||||
map['lockAddress'] = lockAddress;
|
||||
map['selectLockType'] = selectLockType;
|
||||
map['videoIntercomDoorLock'] = videoIntercomDoorLock;
|
||||
map['NFCPassiveLock'] = NFCPassiveLock;
|
||||
|
||||
@ -88,6 +88,13 @@ dependencies:
|
||||
encrypt: ^5.0.1
|
||||
crypto: ^3.0.3
|
||||
|
||||
#高德地图定位
|
||||
amap_flutter_location: ^3.0.0
|
||||
#权限使用
|
||||
permission_handler: ^10.4.3
|
||||
#高德地图地图
|
||||
amap_flutter_map: ^3.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include <aj_captcha_flutter/aj_captcha_flutter_plugin_c_api.h>
|
||||
#include <file_selector_windows/file_selector_windows.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
registry->GetRegistrarForPlugin("AjCaptchaFlutterPluginCApi"));
|
||||
FileSelectorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FileSelectorWindows"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
aj_captcha_flutter
|
||||
file_selector_windows
|
||||
permission_handler_windows
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user