app-starlock/lib/blue/blue_manage.dart

964 lines
40 KiB
Dart
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'dart:io';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:star_lock/app_settings/app_settings.dart';
import 'package:star_lock/flavors.dart';
import 'package:star_lock/tools/bugly/bugly_tool.dart';
import 'package:star_lock/tools/commonDataManage.dart';
import 'io_tool/io_model.dart';
import 'io_tool/io_tool.dart';
import 'io_tool/manager_event_bus.dart';
import 'io_type.dart';
import 'reciver_data.dart';
//连接状态回调
typedef ConnectStateCallBack = Function(
BluetoothConnectionState connectionState);
typedef ScanDevicesCallBack = Function(List<ScanResult>);
class BlueManage {
factory BlueManage() => shareManager()!;
BlueManage._init() {
_initBlue();
}
final List<ScanResult> scanDevices = <ScanResult>[];
// 用来写入的服务id
final Guid _serviceIdConnect = Guid('fff0');
// 用来写入的服务id
final Guid _serviceIdWrite = Guid('0000FFF0-0000-1000-8000-00805F9B34FB');
// 用来订阅的特征id
final Guid _characteristicIdSubscription = Guid('fff1');
// 用来写入的特征id
final Guid _characteristicIdWrite = Guid('fff2');
// 监听发送事件
StreamSubscription<EventSendModel>? _sendStreamSubscription;
StreamSubscription<BluetoothConnectionState>? _connectionStateSubscription;
StreamSubscription<int>? _mtuSubscription;
int? _mtuSize = 20;
// 当前连接设备的名字
String connectDeviceName = '';
// 当前连接设备的mac地址
String connectDeviceMacAddress = '';
// 当前连接的设备
BluetoothDevice? bluetoothConnectDevice;
// 当前扫描到结果要连接设备
ScanResult? scanResult;
// 监听蓝牙连接状态
BluetoothConnectionState? bluetoothConnectionState =
BluetoothConnectionState.disconnected;
BluetoothAdapterState? _adapterState = BluetoothAdapterState.on;
StreamSubscription<BluetoothAdapterState>? _adapterStateStateSubscription;
// 听上报来的数据,参数来自前面扫描到的结果
List<int> allData = <int>[];
// 保存上一次的数据,用来判断是否收到重复的数据
List<int> lastTimeData = <int>[];
int? dataLen;
Timer? scanSingleTimer;
bool needScanSingle = false;
static BlueManage? _manager;
static BlueManage? shareManager() {
_manager ??= BlueManage._init();
// _manager!._initBlue();
return _manager;
}
BlueManage? get manager => shareManager();
void _initBlue() {
FlutterBluePlus.setLogLevel(LogLevel.error, color: true);
_initSendStreamSubscription();
_initAdapterStateStateSubscription();
}
void _initGetMtuSubscription() {
_mtuSubscription ??= bluetoothConnectDevice!.mtu.listen((int value) {
_mtuSize = value - 3;
AppLog.log('_mtuSizeValue:$value mtuSize:$_mtuSize');
});
}
void _initAdapterStateStateSubscription() {
_adapterStateStateSubscription ??=
FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
AppLog.log('蓝牙状态:$state');
_adapterState = state;
});
}
void _initListenConnectionState() {
_connectionStateSubscription?.cancel();
_connectionStateSubscription = null;
_connectionStateSubscription = bluetoothConnectDevice!.connectionState
.listen((BluetoothConnectionState state) async {
bluetoothConnectionState = state;
AppLog.log('蓝牙连接回调状态:$state');
});
}
void _initSendStreamSubscription() {
_sendStreamSubscription ??= EventBusManager()
.eventBus!
.on<EventSendModel>()
.listen((EventSendModel model) {
AppLog.log('eventBus接收发送数据:${model}');
if (model.sendChannel == DataChannel.ble) {
FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) {
if (_adapterState == BluetoothAdapterState.on) {
// 蓝牙已开启,可以进行蓝牙操作
AppLog.log('蓝牙已开启,开始收发送数据:${model.data}');
writeCharacteristicWithResponse(model.data);
} else {
try {
AppLog.log('蓝牙已关闭,停止发送数据:${model.data}');
} catch (e) {
AppLog.log('蓝牙打开失败');
}
}
} else {
AppLog.log('写入数据 蓝牙不可用,不能进行蓝牙操作');
}
});
}
});
}
/// 开始指定设备名称的扫描蓝牙设备
Future<void> startScanSingle(String deviceName, int timeout,
ScanDevicesCallBack scanDevicesCallBack) async {
final DateTime start = DateTime.now();
FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) {
// AppLog.log('startScanSingle 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
if (_adapterState == BluetoothAdapterState.on) {
try {
BuglyTool.uploadException(
message: '开始指定设备名称的扫描蓝牙设备',
detail: '调用方法是:startScanSingle 指定设备名称是:$deviceName',
upload: false);
//android 扫描比较慢,取样只要 3 分之一
final int divisor = Platform.isAndroid ? 3 : 1;
FlutterBluePlus.startScan(
continuousDivisor: divisor,
continuousUpdates: true,
withKeywords: <String>[deviceName],
timeout: Duration(seconds: timeout));
final Completer<dynamic> completer = Completer<dynamic>();
final StreamSubscription<List<ScanResult>> subscription =
FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
final bool isExit = results.any((ScanResult element) =>
(element.device.platformName == deviceName) ||
(element.advertisementData.advName == deviceName));
final int milliseconds = DateTime.now().millisecondsSinceEpoch -
start.millisecondsSinceEpoch;
AppLog.log(
'扫描到的设备数:${results.length} 是否查找到 $isExit 以查找$milliseconds毫秒');
BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 监听扫描结果',
detail:
'startScanSingle$deviceName 监听扫描结果 是否查找到 $isExit 以查找$milliseconds毫秒 扫描到的设备数:${results.length} results:$results',
upload: false);
if (isExit) {
for (final ScanResult scanResult in results) {
if (scanResult.advertisementData.serviceUuids.isNotEmpty) {
// AppLog.log(
// '扫描到的设备:${scanResult.advertisementData.serviceUuids[0].toString()}');
} else {
continue;
}
final isMatch = _isMatch(
scanResult.advertisementData.serviceUuids
.map((e) => e.uuid)
.toList(),
isSingle: true,
);
if (isMatch && (scanResult.rssi >= -100)) {
// 查询id相同的元素
final int knownDeviceIndex = scanDevices.indexWhere(
(ScanResult d) =>
(d.device.platformName ==
scanResult.device.platformName) ||
(d.advertisementData.advName ==
scanResult.advertisementData.advName));
// 不存在的时候返回-1
if (knownDeviceIndex >= 0) {
scanDevices[knownDeviceIndex] = scanResult;
} else {
scanDevices.add(scanResult);
}
BuglyTool.uploadException(
message: '遍历扫描到的结果跟缓存的结果对比,如果有最新的就更新缓存',
detail:
'startScanSingle deviceName:$deviceName 查询到的结果scanResult:$scanResult',
upload: false);
}
}
completer.complete();
}
}, onError: (e) {
BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 监听扫描结果失败',
detail: '打印失败问题 e${e.toString()}',
upload: false);
AppLog.log('扫描失败:$e');
});
FlutterBluePlus.cancelWhenScanComplete(subscription);
await completer.future;
scanDevicesCallBack(scanDevices);
subscription.cancel();
} catch (e) {
BuglyTool.uploadException(
message: '指定设备名称的扫描蓝牙设备 内部逻辑整形失败',
detail: 'tartScanSingle内部逻辑整形失败 e:${e.toString()}',
upload: false);
AppLog.log('扫描失败');
}
} else {
try {
openBlue();
} catch (e) {
AppLog.log('蓝牙打开失败');
}
}
} else {
AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作');
}
});
}
/// 开始扫描蓝牙设备
Future<void> startScan(int timeout, DeviceType deviceType,
ScanDevicesCallBack scanDevicesCallBack,
{List<Guid>? idList}) async {
FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) {
// AppLog.log('startScan 蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
if (_adapterState == BluetoothAdapterState.on) {
try {
FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
final StreamSubscription<List<ScanResult>> subscription =
FlutterBluePlus.scanResults.listen((List<ScanResult> results) {
scanDevices.clear();
for (final ScanResult scanResult in results) {
if (scanResult.advertisementData.serviceUuids.isNotEmpty) {
// AppLog.log(
// '扫描到的设备:${scanResult.advertisementData.serviceUuids[0].toString()}====${scanResult.advertisementData.advName}');
} else {
continue;
}
final isMatch = _isMatch(
scanResult.advertisementData.serviceUuids
.map((e) => e.uuid)
.toList(),
deviceType: deviceType,
isSingle: false,
);
// 判断名字为空的直接剔除
if (isMatch && (scanResult.rssi >= -100)) {
// 查询id相同的元素
final int knownDeviceIndex = scanDevices.indexWhere(
(ScanResult d) =>
(d.device.platformName ==
scanResult.device.platformName) ||
(d.advertisementData.advName ==
scanResult.advertisementData.advName));
// 不存在的时候返回-1
if (knownDeviceIndex >= 0) {
scanDevices[knownDeviceIndex] = scanResult;
} else {
scanDevices.add(scanResult);
}
}
}
scanDevicesCallBack(scanDevices);
}, onError: (e) {
AppLog.log(
'扫描失败:$e',
);
});
FlutterBluePlus.cancelWhenScanComplete(subscription);
} catch (e) {
AppLog.log('扫描失败');
}
} else {
try {
openBlue();
} catch (e) {
AppLog.log('蓝牙打开失败');
}
}
} else {
AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作');
}
});
}
/// 判断是否包含指定的uuid
bool _isMatch(List<String> serviceUuids,
{DeviceType deviceType = DeviceType.blue, required bool isSingle}) {
final List<String> prefixes =
getDeviceType(deviceType).map((e) => e.toLowerCase()).toList();
for (String uuid in serviceUuids) {
final String cleanUuid = uuid.toLowerCase();
if (cleanUuid.length == 8) {
// 8位判断第4、5位
String pairStatus = cleanUuid.substring(4, 6); // 第4、5位索引3和4
for (final prefix in prefixes) {
if (cleanUuid.startsWith(prefix)) {
if (isSingle) {
return true; // isSingle为true前缀匹配即返回true
} else {
// 00=未配对01=已配对
if (pairStatus == '00') {
return true; // 未配对才返回true
}
// 已配对01不返回true继续判断下一个uuid
}
}
}
} else {
// 128位判断前8位的第3、第4位
if (cleanUuid.length >= 32) {
if (deviceType == DeviceType.blue) {
final String thirdAndFourth = cleanUuid.substring(6, 8); // 索引2和3
for (final prefix in prefixes) {
if (thirdAndFourth == prefix) {
if (isSingle) {
return true; // isSingle为true前缀匹配即返回true
} else {
// 判断配对状态带横杠UUID的第31、32位从1开始计数
if (cleanUuid.length >= 32) {
String pairStatus =
cleanUuid.substring(30, 32); // 第31、32位从1开始计数
// 00=未配对01=已配对
if (pairStatus == '00') {
return true; // 未配对才返回true
}
// 已配对01不返回true继续判断下一个uuid
}
}
}
}
} else if (deviceType == DeviceType.gateway) {
final String thirdAndFourth = cleanUuid.substring(6, 8); // 索引2和3
for (final prefix in prefixes) {
if (thirdAndFourth == prefix) {
if (isSingle) {
return true; // isSingle为true前缀匹配即返回true
} else {
// 判断配对状态带横杠UUID的第31、32位从1开始计数
if (cleanUuid.length >= 32) {
String pairStatus =
cleanUuid.substring(30, 32); // 第31、32位从1开始计数
// 00=未配对01=已配对
if (pairStatus == '00') {
return true; // 未配对才返回true
}
// 已配对01不返回true继续判断下一个uuid
}
}
}
}
}
}
}
}
return false;
}
/// 调用发送数据 List senderData,
Future<void> blueSendData(
String deviceName, ConnectStateCallBack stateCallBack,
{bool isAddEquipment = false}) async {
FlutterBluePlus.isSupported.then((bool isAvailable) async {
if (isAvailable) {
// AppLog.log('蓝牙状态 系统蓝牙状态:$_adapterState 蓝牙连接状态:$bluetoothConnectionState');
if (_adapterState == BluetoothAdapterState.on) {
// 蓝牙已开启,可以进行蓝牙操作
if (bluetoothConnectionState != BluetoothConnectionState.connected) {
BuglyTool.uploadException(
message: '点击按钮 蓝牙未连接 下一步扫描连接蓝牙',
detail:
'blueSendData 蓝牙连接状态 bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
upload: false);
_connect(deviceName, (BluetoothConnectionState state) {
stateCallBack(bluetoothConnectionState!);
}, isAddEquipment: isAddEquipment);
} else {
BuglyTool.uploadException(
message: '点击按钮 蓝牙已经连接 下一步扫描连接蓝牙',
detail:
'blueSendData 直接回调状态 蓝牙连接状态bluetoothConnectionState$bluetoothConnectionState deviceName:$deviceName',
upload: false);
stateCallBack(bluetoothConnectionState!);
}
} else {
BuglyTool.uploadException(
message: '点击按钮 蓝牙未打开',
detail:
'blueSendData 蓝牙未打开--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
upload: false);
try {
stateCallBack(BluetoothConnectionState.disconnected);
openBlue();
} catch (e) {
AppLog.log('蓝牙打开失败');
BuglyTool.uploadException(
message: '点击按钮 蓝牙未打开 然后蓝牙打开失败',
detail:
'blueSendData 蓝牙打开失败--_adapterState:${BluetoothAdapterState.on} deviceName:$deviceName',
upload: false);
}
}
} else {
BuglyTool.uploadException(
message: '点击按钮 蓝牙状态不可用',
detail: 'blueSendData 蓝牙状态不可用--isAvailable:$isAvailable',
upload: false);
stateCallBack(BluetoothConnectionState.disconnected);
AppLog.log('开始扫描 蓝牙不可用,不能进行蓝牙操作');
}
});
}
/// 连接
Future<void> _connect(
String deviceName, ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async {
connectDeviceName = deviceName;
// 当前已扫描到的缓存设备
final List<ScanResult> devicesList = scanDevices;
// 是否有缓存设备 true是有缓存设备
final bool isExistDevice = isExistScanDevices(connectDeviceName);
// 是否是当前设备
final bool isCurrentDevice =
CommonDataManage().currentKeyInfo.lockName == deviceName;
// mac地址
final String? mac = CommonDataManage().currentKeyInfo.mac;
AppLog.log('开始连接 是否存在缓存:$isExistDevice 是否是当前设备:$isCurrentDevice mac$mac');
if (GetPlatform.isAndroid &&
!isExistDevice &&
isCurrentDevice &&
mac != null) {
// 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空
BuglyTool.uploadException(
message: '开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect',
detail:
'调用方法_connect deviceName:$deviceName GetPlatform.isAndroid:${GetPlatform.isAndroid} isExistDevice:$isExistDevice mac:$mac needScanSingle$needScanSingle',
upload: false);
// scanSingleTimer?.cancel();
// 兼容android 的低配手机
try {
if (!needScanSingle) {
BuglyTool.uploadException(
message:
'开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect',
detail: '调用方法doNotSearchBLE直接连接,needScanSingle$needScanSingle',
upload: false);
await doNotSearchBLE(mac, connectStateCallBack,
isAddEquipment: isAddEquipment);
} else {
BuglyTool.uploadException(
message:
'开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect',
detail:
'调用方法startScanSingle执行扫描函数,needScanSingle$needScanSingle',
upload: false);
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment);
});
}
} catch (e) {
BuglyTool.uploadException(
message: '开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 上传记录当前方法是_connect',
detail: '调用方法doNotSearchBLE发生异常执行扫描函数 startScanSingle异常信息$e',
upload: false);
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment);
});
}
//
// scanSingleTimer = Timer(3.seconds, () {
// scanSingleTimer?.cancel();
// BuglyTool.uploadException(
// message:
// '开始连接 当是安卓设备 且不存在缓存设备 且是当前设备 且mac地址不为空 3秒以后调用startScanSingle 上传记录当前方法是_connect',
// detail:
// '_connect deviceName:$deviceName scanSingleTimer调用startScanSingle',
// upload: false);
// startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) => null);
// });ƒ
} else if (isAddEquipment == false && isExistDevice == false) {
// 取消缓存直接使用,存在配对场景设备信息会更变
BuglyTool.uploadException(
message:
'取消缓存直接使用,存在配对场景设备信息会更变 然后开始指定设备名称的扫描蓝牙设备 上传记录当前方法是_connect',
detail:
'符合条件(isAddEquipment == false && isExistDevice == false) 下一步调用startScanSingle',
upload: false);
// AppLog.log('无存在设备需要扫描 deviceName:$deviceName isAddEquipment:$isAddEquipment');
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment);
});
} else {
BuglyTool.uploadException(
message: '没有扫描直接调用连接设备 上传记录当前方法是_connect',
detail:
'走这个方法是有缓存或者添加设备的时候以及不符合(GetPlatform.isAndroid && !isExistDevice && isCurrentDevice && mac != null) deviceName:$deviceName 直接调用_connectDevice',
upload: false);
// AppLog.log('安卓或者iOS 存在设备不需要扫描 deviceName:$deviceName isAddEquipment:$isAddEquipment');
_connectDevice(devicesList, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment);
}
}
//查找缓存里面是否有设备
bool isExistScanDevices(String connectDeviceName) {
final bool isExistDevice = scanDevices.any((ScanResult element) =>
element.device.platformName == connectDeviceName ||
element.advertisementData.advName == connectDeviceName);
return isExistDevice;
}
Future<void> _connectDevice(
List<ScanResult> devicesList,
String deviceName,
ConnectStateCallBack connectStateCallBack, {
bool isAddEquipment = false, // 是否是添加设备之前
bool isReconnect = true, // 是否是重连
}) async {
// 判断数组列表里面是否有这个设备
// AppLog.log("devicesList:$devicesList");
final int knownDeviceIndex = devicesList.indexWhere((ScanResult d) =>
(d.device.platformName == deviceName) ||
(d.advertisementData.advName == deviceName));
ScanResult? scanResult; //使用局部变量防止出现缓存
if (knownDeviceIndex >= 0) {
// 存在的时候赋值
connectDeviceMacAddress =
devicesList[knownDeviceIndex].advertisementData.advName.isNotEmpty
? devicesList[knownDeviceIndex].advertisementData.advName
: devicesList[knownDeviceIndex].device.platformName;
bluetoothConnectDevice = devicesList[knownDeviceIndex].device;
scanResult = devicesList[knownDeviceIndex];
// AppLog.log('bluetoothConnectDevice: $bluetoothConnectDevice scanResult:$scanResult');
_initGetMtuSubscription();
_initListenConnectionState();
}
if (scanResult == null || connectDeviceMacAddress.isEmpty) {
BuglyTool.uploadException(
message:
'扫描结果scanResult == null || connectDeviceMacAddress.isEmpty不往下执行 return 上传记录当前方法是_connectDevice',
detail:
'scanResult:$scanResult connectDeviceMacAddress$connectDeviceMacAddress',
upload: false);
return;
}
AppLog.log('调用了停止扫描的方法');
await stopScan();
if (scanResult.advertisementData.serviceUuids[0].toString().length >= 5 &&
(scanResult.advertisementData.serviceUuids[0].toString()[5] == '0') &&
isAddEquipment == false) {
// 添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接
if (isReconnect == true) {
AppLog.log('该锁已被重置, 重新发送扫描命令');
BuglyTool.uploadException(
message: '该锁已被重置, 重新发送扫描命令startScanSingle 上传记录当前方法是_connectDevice',
detail:
'添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接 该锁已被重置, 重新发送扫描命令 serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false);
scanDevices.clear();
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment, isReconnect: false);
});
} else {
connectStateCallBack(BluetoothConnectionState.disconnected);
if (!F.isSKY) {
EasyLoading.showToast('该锁已被重置'.tr, duration: 2000.milliseconds);
}
scanDevices.clear();
BuglyTool.uploadException(
message: '提示该锁已被重置, 回调断开连接, 清除缓存上传记录当前方法是_connectDevice',
detail:
'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false);
}
return;
}
if (scanResult.advertisementData.serviceUuids[0].toString().length >= 30 &&
(scanResult.advertisementData.serviceUuids[0].toString()[31] == '0') &&
isAddEquipment == false) {
// 添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接
if (isReconnect == true) {
AppLog.log('该锁已被重置, 重新发送扫描命令');
BuglyTool.uploadException(
message: '该锁已被重置, 重新发送扫描命令startScanSingle 上传记录当前方法是_connectDevice',
detail:
'添加这个判断是因为有些苹果设备或者安卓等性能比较好的设备时,添加完锁之后,锁板未改变为已添加状态之前,就进行了蓝牙连接,导致添加完锁就失败,这里进行了判断,如果第一次连接失败,就清除缓存重新扫描连接 该锁已被重置, 重新发送扫描命令 serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false);
scanDevices.clear();
startScanSingle(deviceName, 15, (List<ScanResult> scanDevices) {
_connectDevice(scanDevices, deviceName, connectStateCallBack,
isAddEquipment: isAddEquipment, isReconnect: false);
});
} else {
connectStateCallBack(BluetoothConnectionState.disconnected);
if (!F.isSKY) {
EasyLoading.showToast('该锁已被重置'.tr, duration: 2000.milliseconds);
}
scanDevices.clear();
BuglyTool.uploadException(
message: '提示该锁已被重置, 回调断开连接, 清除缓存上传记录当前方法是_connectDevice',
detail:
'isReconnect:$isReconnect serviceUuids:${scanResult.advertisementData.serviceUuids[0].toString()}',
upload: false);
}
return;
}
BuglyTool.uploadException(
message: '从devicesList里面查到了设备 下一步连接设备 上传记录当前方法是_connectDevice',
detail:
'devicesList:$devicesList scanResult:${scanResult.toString()} bluetoothConnectDevice${bluetoothConnectDevice.toString()} connectDeviceMacAddress$connectDeviceMacAddress',
upload: false);
//连接设备
await bluetoothDeviceConnect(bluetoothConnectDevice!, connectStateCallBack);
}
//直接给蓝牙设备写入
Future<void> doNotSearchBLE(
String masAdds, ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async {
await FlutterBluePlus.stopScan();
if (bluetoothConnectDevice == null ||
bluetoothConnectDevice?.remoteId.str != masAdds) {
bluetoothConnectDevice = BluetoothDevice.fromId(masAdds);
_initGetMtuSubscription();
_initListenConnectionState();
BuglyTool.uploadException(
message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE',
detail: '直接给蓝牙设备写入 通过fromId方法创建一个BluetoothDevice masAdds$masAdds',
upload: false);
} else {
BuglyTool.uploadException(
message: '直接给蓝牙设备写入 上传记录当前方法是doNotSearchBLE',
detail:
'直接给蓝牙设备写入 用传入的bluetoothConnectDevice${bluetoothConnectDevice.toString()}连接 masAdds:$masAdds',
upload: false);
}
//尝试连接设备
await bluetoothDeviceConnect(bluetoothConnectDevice!, connectStateCallBack,
isAddEquipment: isAddEquipment);
}
//设备连接
Future<void> bluetoothDeviceConnect(BluetoothDevice bluetoothConnectDevice,
ConnectStateCallBack connectStateCallBack,
{bool isAddEquipment = false}) async {
// 重连三次
const int maxAttempts = 3;
int attempt = 0;
while (attempt < maxAttempts) {
try {
await bluetoothConnectDevice.connect(timeout: 5.seconds);
break; // If the connection is successful, break the loop
} catch (e) {
AppLog.log('连接失败 重连了: $e');
attempt++; // Increase the attempt count
if (attempt < maxAttempts) {
AppLog.log('重新尝试连接...');
}
}
}
if (attempt >= maxAttempts) {
AppLog.log('$maxAttempts次后尝试连接失败');
BuglyTool.uploadException(
message: '连接三次超时断开连接 回调断开连接 上传记录当前方法是bluetoothDeviceConnect',
detail:
'bluetoothDeviceConnect:${bluetoothConnectDevice.toString()} $maxAttempts次后尝试连接失败',
upload: false);
needScanSingle = true;
connectStateCallBack(BluetoothConnectionState.disconnected);
}
if (bluetoothConnectionState == BluetoothConnectionState.connected) {
try {
needScanSingle = false;
final List<BluetoothService> services =
await bluetoothConnectDevice.discoverServices();
//循环判断服务
for (final BluetoothService service in services) {
if (service.uuid == _serviceIdConnect) {
for (final BluetoothCharacteristic characteristic
in service.characteristics) {
if (characteristic.characteristicUuid ==
_characteristicIdSubscription) {
_subScribeToCharacteristic(characteristic);
bluetoothConnectionState = BluetoothConnectionState.connected;
connectStateCallBack(bluetoothConnectionState!);
BuglyTool.uploadException(
message: '订阅成功 上传记录当前方法是bluetoothDeviceConnect',
detail:
'发现服务,连接成功,订阅数据 bluetoothDeviceConnect:${bluetoothConnectDevice.toString()} ',
upload: false);
} else {
BuglyTool.uploadException(
message: '订阅失败 上传记录当前方法是bluetoothDeviceConnect',
detail:
'失败原因: characteristic.characteristicUuid:${characteristic.characteristicUuid} != _characteristicIdSubscription:$_characteristicIdSubscription bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}',
upload: false);
}
}
} else {
BuglyTool.uploadException(
message: '订阅失败 上传记录当前方法是bluetoothDeviceConnect',
detail:
'失败原因: service.uuid:${service.uuid} != _serviceIdConnect:$_serviceIdConnect bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}',
upload: false);
}
}
} on Exception catch (e) {
needScanSingle = true;
bluetoothConnectionState = BluetoothConnectionState.disconnected;
connectStateCallBack(bluetoothConnectionState!);
AppLog.log(
'发现设备时失败 e:$e bluetoothConnectionState:$bluetoothConnectionState');
BuglyTool.uploadException(
message: '发现服务时失败',
detail:
'发现服务时报错原因e$e bluetoothDeviceConnect:${bluetoothConnectDevice.toString()}',
upload: false);
rethrow;
}
}
}
Future<void> _subScribeToCharacteristic(
BluetoothCharacteristic characteristic) async {
final StreamSubscription<List<int>> subscription =
characteristic.onValueReceived.listen((List<int> data) {
AppLog.log('订阅获取的数据: $data ');
if (data == lastTimeData || data.isEmpty) {
return;
} else {
lastTimeData = data;
}
final bool dataHeadCorrect = isDataHeadCorrect(data);
final bool allDataHeadCorrect = isDataHeadCorrect(allData);
if (dataHeadCorrect && allDataHeadCorrect) {
//缓存数据和新数据都有包头,直接放弃缓存数据
allData = <int>[];
}
if (dataHeadCorrect) {
// 当包有头时
// 判断是否需要分包
dataLen = data[8] * 256 + data[9]; // 高16位用来指示后面数据块内容的长度
if (dataLen! + 14 > data.length) {
// 当前包的长度小于实际的包时 分包添加 不解析
allData.addAll(data);
} else {
// 当前包的长度小于实际的包时 不分包 解析
allData.addAll(data);
CommandReciverManager.appDataReceive(allData);
// 发送完解析初始化数组
allData = <int>[];
}
} else if (allDataHeadCorrect) {
// 当包没有头时 是分包的包 直接添加
allData.addAll(data);
if (((dataLen ?? 0) + 14) <= allData.length) {
// 当长度小于等于当前包的数据时 直接解析数据
CommandReciverManager.appDataReceive(allData);
// 发送完解析初始化数组
allData = <int>[];
}
}
});
bluetoothConnectDevice!.cancelWhenDisconnected(subscription);
await characteristic.setNotifyValue(true);
}
//判断数据头是否正确
bool isDataHeadCorrect(List<int> data) {
if (data.length < 4) {
return false;
}
//239, 1, 238, 2, 是数据包头
if ((data[0] == 0xEF) &&
(data[1] == 0x01) &&
(data[2] == 0xEE) &&
(data[3] == 0x02)) {
return true;
} else {
return false;
}
}
/// 写入蓝牙特征值,并等待响应
Future<void> writeCharacteristicWithResponse(List<int> value) async {
final List<BluetoothService> services =
await bluetoothConnectDevice!.discoverServices();
for (final BluetoothService service in services) {
if (service.uuid == _serviceIdConnect) {
for (final BluetoothCharacteristic characteristic
in service.characteristics) {
if (characteristic.characteristicUuid == _characteristicIdWrite) {
try {
// 添加重试机制
int retryCount = 0;
const int maxRetries = 3;
const int retryDelayMs = 500;
final List<int> valueList = value;
final List subData = splitList(valueList, _mtuSize!);
for (int i = 0; i < subData.length; i++) {
// 对每个数据包都应用重试逻辑
bool packetSent = false;
retryCount = 0;
while (!packetSent && retryCount < maxRetries) {
try {
if (characteristic.properties.writeWithoutResponse) {
await characteristic.write(subData[i],
withoutResponse: true);
} else if (characteristic.properties.write) {
await characteristic.write(subData[i]);
} else {
// 特性不支持写入
throw Exception(
'This characteristic does not support writing.');
}
// 如果到这里没有异常,则包发送成功
packetSent = true;
} catch (e) {
if (e.toString().contains('UNKNOWN_GATT_ERROR (133)') &&
retryCount < maxRetries - 1) {
// GATT错误133尝试重试
retryCount++;
AppLog.log(
'蓝牙写入失败(GATT 133),数据包 ${i + 1}/${subData.length} 正在重试 $retryCount/$maxRetries...');
await Future.delayed(
Duration(milliseconds: retryDelayMs));
continue;
} else {
// 其他错误或已达到最大重试次数,抛出异常
AppLog.log('APP写入失败: $e');
throw e;
}
}
}
if (!packetSent) {
throw Exception(
'蓝牙写入失败,数据包 ${i + 1}/${subData.length} 已达到最大重试次数');
}
}
return; // 所有数据包都发送成功
} on Exception catch (e, s) {
AppLog.log('APP写入失败: $e $s');
rethrow;
}
}
}
}
}
// 如果找不到合适的特性用于写入
throw Exception('未找到适合写入的蓝牙特性');
}
// 停止扫描蓝牙设备
Future<void> stopScan() async {
try {
await FlutterBluePlus.stopScan();
AppLog.log('调用停止扫描成功');
} catch (e) {
AppLog.log('停止扫描失败');
}
}
// 断开连接
Future<void> disconnect() async {
try {
connectDeviceMacAddress = '';
if (bluetoothConnectionState == BluetoothConnectionState.connected) {
//加快蓝牙断连
await bluetoothConnectDevice!.disconnect(timeout: 3);
AppLog.log('断开连接成功');
}
} on Exception catch (e, _) {
AppLog.log('断开连接失败: $e');
} finally {
bluetoothConnectionState = BluetoothConnectionState.disconnected;
}
}
Future<void> openBlue() async {
if (Platform.isAndroid) {
await FlutterBluePlus.turnOn();
}
if (Platform.isIOS) {
EasyLoading.showToast('请开启蓝牙'.tr, duration: 2000.milliseconds);
}
}
void disposed() {
_sendStreamSubscription?.cancel();
_mtuSubscription!.cancel();
_adapterStateStateSubscription!.cancel();
_connectionStateSubscription!.cancel();
}
}