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