150 lines
5.4 KiB
Dart
150 lines
5.4 KiB
Dart
|
|
import 'dart:async';
|
|||
|
|
|
|||
|
|
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
|
|||
|
|
import 'package:starwork_flutter/base/app_logger.dart';
|
|||
|
|
import 'package:starwork_flutter/ble/model/scan_device_info.dart';
|
|||
|
|
import 'package:starwork_flutter/common/constant/device_type.dart';
|
|||
|
|
|
|||
|
|
class BleService {
|
|||
|
|
// 私有构造函数
|
|||
|
|
BleService._() {
|
|||
|
|
// ✅ 这里就是单例初始化的地方
|
|||
|
|
// 只会执行一次(第一次获取实例时)
|
|||
|
|
_initialize();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 静态实例
|
|||
|
|
static final BleService _instance = BleService._();
|
|||
|
|
|
|||
|
|
// 工厂构造函数,提供全局访问点
|
|||
|
|
factory BleService() => _instance;
|
|||
|
|
|
|||
|
|
/// 用来存储搜索到的设备,并用于去重和过滤
|
|||
|
|
final Map<String, ScanResult> _discoveredDevices = {};
|
|||
|
|
|
|||
|
|
/// 用来监听蓝牙适配器状态的订阅流
|
|||
|
|
StreamSubscription<BluetoothAdapterState>? _adapterStateSubscription;
|
|||
|
|
|
|||
|
|
/// 用来监听搜索到的设备的订阅流
|
|||
|
|
StreamSubscription<List<ScanResult>>? _scanResultSubscription;
|
|||
|
|
|
|||
|
|
// 内部维护的蓝牙状态
|
|||
|
|
BluetoothAdapterState _bluetoothAdapterState = BluetoothAdapterState.unknown;
|
|||
|
|
|
|||
|
|
/// 提供外部获取蓝牙适配器方法
|
|||
|
|
BluetoothAdapterState get bluetoothAdapterState => _bluetoothAdapterState;
|
|||
|
|
|
|||
|
|
/// 搜索状态
|
|||
|
|
bool get isScanningNow => FlutterBluePlus.isScanningNow;
|
|||
|
|
|
|||
|
|
/// 初始化服务时执行的
|
|||
|
|
Future<void> _initialize() async {
|
|||
|
|
AppLogger.highlight('🚀 BleService 正在初始化...');
|
|||
|
|
|
|||
|
|
/// 监听蓝牙适配器状态
|
|||
|
|
_adapterStateSubscription = FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
|
|||
|
|
_bluetoothAdapterState = state;
|
|||
|
|
AppLogger.highlight('蓝牙适配器状态发送变化:${state}');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
AppLogger.highlight('✅ BleService 初始化完成');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 开启蓝牙搜索
|
|||
|
|
void enableBluetoothSearch({
|
|||
|
|
DeviceType deviceType = DeviceType.all,
|
|||
|
|
Duration searchTime = const Duration(seconds: 30),
|
|||
|
|
required void Function(ScanDeviceInfo device) onDeviceFound,
|
|||
|
|
}) async {
|
|||
|
|
// 如果正在搜索中,直接返回
|
|||
|
|
var isScanningNow = FlutterBluePlus.isScanningNow;
|
|||
|
|
if (isScanningNow) {
|
|||
|
|
AppLogger.warn('正处于搜索状态,请勿重复搜索');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (_bluetoothAdapterState == BluetoothAdapterState.on) {
|
|||
|
|
FlutterBluePlus.startScan(timeout: searchTime);
|
|||
|
|
|
|||
|
|
/// 取消旧的订阅,防止重复
|
|||
|
|
_scanResultSubscription?.cancel();
|
|||
|
|
_discoveredDevices.clear();
|
|||
|
|
|
|||
|
|
/// 监听搜索到的设备
|
|||
|
|
_scanResultSubscription = FlutterBluePlus.onScanResults.listen(
|
|||
|
|
(List<ScanResult> results) {
|
|||
|
|
for (var result in results) {
|
|||
|
|
var device = result.device;
|
|||
|
|
final deviceId = device.remoteId.toString();
|
|||
|
|
final platformName = device.platformName;
|
|||
|
|
var serviceUuids = result.advertisementData.serviceUuids;
|
|||
|
|
|
|||
|
|
// ✅ 只有新设备才回调
|
|||
|
|
if (!_discoveredDevices.containsKey(deviceId) && platformName.isNotEmpty) {
|
|||
|
|
_discoveredDevices[deviceId] = result;
|
|||
|
|
bool pairStatus = false;
|
|||
|
|
bool hasNewEvent = false;
|
|||
|
|
for (var uuid in serviceUuids) {
|
|||
|
|
String uuidStr = uuid.toString().replaceAll('-', '');
|
|||
|
|
if (uuidStr.length == 8) {
|
|||
|
|
var pairStatusStr = uuidStr.substring(4, 6);
|
|||
|
|
var hasNewEventStr = uuidStr.substring(6, 8);
|
|||
|
|
pairStatus = pairStatusStr == '01';
|
|||
|
|
hasNewEvent = hasNewEventStr == '01';
|
|||
|
|
var scanDeviceInfo = ScanDeviceInfo(
|
|||
|
|
isBinding: pairStatus,
|
|||
|
|
advName: device.advName,
|
|||
|
|
rawDeviceInfo: result,
|
|||
|
|
hasNewEvent: hasNewEvent,
|
|||
|
|
);
|
|||
|
|
onDeviceFound.call(scanDeviceInfo);
|
|||
|
|
} else if (uuidStr.length == 32) {
|
|||
|
|
var pairStatusStr = uuidStr.substring(26, 28);
|
|||
|
|
pairStatus = pairStatusStr == '00'; // 第4、5位(索引3和4)
|
|||
|
|
int statusValue = int.parse(pairStatusStr, radix: 16);
|
|||
|
|
// 提取 byte0(配对状态:第1位)
|
|||
|
|
int byte0 = (statusValue >> 0) & 0x01; // 取最低位
|
|||
|
|
// 提取 byte1(事件状态:第2位)
|
|||
|
|
int byte1 = (statusValue >> 1) & 0x01; // 取次低位
|
|||
|
|
// 判断是否未配对
|
|||
|
|
pairStatus = (byte0 == 1);
|
|||
|
|
// 判断是否有新事件
|
|||
|
|
hasNewEvent = (byte1 == 1);
|
|||
|
|
var scanDeviceInfo = ScanDeviceInfo(
|
|||
|
|
isBinding: pairStatus,
|
|||
|
|
advName: device.advName,
|
|||
|
|
rawDeviceInfo: result,
|
|||
|
|
hasNewEvent: hasNewEvent,
|
|||
|
|
);
|
|||
|
|
onDeviceFound.call(scanDeviceInfo);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
// 可选:更新 RSSI
|
|||
|
|
_discoveredDevices[deviceId] = result;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
onError: (e) => AppLogger.error('搜索设备时遇到错误:' + e),
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// 停止扫描
|
|||
|
|
void stopBluetoothSearch() async {
|
|||
|
|
var isScanningNow = FlutterBluePlus.isScanningNow;
|
|||
|
|
if (isScanningNow) {
|
|||
|
|
FlutterBluePlus.stopScan();
|
|||
|
|
|
|||
|
|
/// 清空搜索到的设备
|
|||
|
|
_discoveredDevices.clear();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void cancel() {
|
|||
|
|
/// 销毁蓝牙适配器监听
|
|||
|
|
_adapterStateSubscription?.cancel();
|
|||
|
|
_scanResultSubscription?.cancel();
|
|||
|
|
_bluetoothAdapterState = BluetoothAdapterState.unknown;
|
|||
|
|
}
|
|||
|
|
}
|