添加高德地图、调试蓝牙协议、添加添加锁逻辑

This commit is contained in:
魏少阳 2023-08-24 14:25:55 +08:00
parent 1a659b5579
commit 10c8357fba
38 changed files with 1395 additions and 122 deletions

View File

@ -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>

View File

@ -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",

View File

@ -191,6 +191,7 @@
"lanChinese":"lanChinese",
"multilingual":"multilingual",
"addLock":"addLock",
"lockAddress":"lockAddress",
"selectLockType":"selectLockType",
"videoIntercomDoorLock":"videoIntercomDoorLock",
"NFCPassiveLock":"NFCPassiveLock",

View File

@ -191,6 +191,7 @@
"lanChinese":"中文",
"multilingual":"多语言",
"addLock":"添加锁",
"lockAddress":"锁地址",
"selectLockType":"选择锁类型",
"videoIntercomDoorLock":"可视对讲门锁",
"NFCPassiveLock":"NFC无源锁",

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -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

View File

@ -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;

View File

@ -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>

View 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>

View File

@ -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){

View 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");
// KeyIDauthUserIDmd5加密之后就是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;
}
}

View 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");
// KeyIDauthUserIDmd5加密之后就是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;
}
}

View File

@ -7,6 +7,8 @@ const saveBluePublicKey = "BluePublicKey";
const saveBluePrivateKey = "BluePrivateKey";
const saveBlueSignKey = "BlueSignKey";
const saveBlueToken = "BlueGetToken";
const currentConnectionLockId = "CurrentConnectionLockId";
const currentConnectionMacAddress = "CurrentConnectionMacAddress";
class IoManager {

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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),

View File

@ -1,6 +1,5 @@
import 'package:get/get.dart';
import 'lockMain_logic.dart';
class LockMainBinding extends Bindings {

View File

@ -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("地图界面销毁了");
}
}

View File

@ -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();
}
}

View File

@ -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()");
}
}

View File

@ -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("当前路由的下个路由出栈,且当前页面显示");
}
}

View File

@ -0,0 +1,5 @@
class LockAddressState {
}

View File

@ -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

View File

@ -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;
}
}

View 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();
}
}

View File

@ -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: '请填写信息',

View 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();
}
}

View File

@ -17,4 +17,7 @@ abstract class Api {
final String keyOperationRecordURL = '/lockRecords/list'; //
final String uploadElectricQuantityURL =
'/room/uploadElectricQuantity'; //
final String bindingBlueAdminURL =
'/lock/bindAdmin'; //
}

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -49,6 +49,7 @@ class LoginInput extends StatelessWidget {
controller: controller,
onChanged: onchangeAction,
autofocus: false,
inputFormatters:inputFormatters,
decoration: InputDecoration(
//
contentPadding: const EdgeInsets.only(

View File

@ -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;

View File

@ -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

View File

@ -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"));
}

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
aj_captcha_flutter
file_selector_windows
permission_handler_windows
url_launcher_windows
)