starwork_flutter/lib/ble/ble_service.dart
2025-09-06 15:42:26 +08:00

150 lines
5.4 KiB
Dart
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 '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;
}
}