You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

470 lines
16 KiB

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import '../../core/utils/logger.dart';
import 'dart:io' show Platform;
import 'package:permission_handler/permission_handler.dart';
/// 蓝牙设备服务,用于发现和管理蓝牙设备
class BluetoothService extends GetxService {
static BluetoothService get to => Get.find<BluetoothService>();
// 单例实例
static final BluetoothService _instance = BluetoothService._internal();
factory BluetoothService() => _instance;
BluetoothService._internal();
// 设备状态
final _isAvailable = false.obs;
final _isOn = false.obs;
// 已连接的设备
final _connectedDevices = <BluetoothDevice>[].obs;
// 扫描状态
final _isScanning = false.obs;
// 扫描结果
final _scanResults = <ScanResult>[].obs;
// 当前选中的设备
final _selectedDevice = Rx<BluetoothDevice?>(null);
// 连接状态
final _connectionState = Rx<BluetoothConnectionState>(BluetoothConnectionState.disconnected);
// 存储最后连接的设备信息,供其他控制器使用
final _lastConnectedDeviceInfo = Rx<Map<String, dynamic>>({});
// 订阅
StreamSubscription? _stateSubscription;
StreamSubscription? _scanSubscription;
StreamSubscription? _connectionSubscription;
// 权限状态
final _permissionsGranted = false.obs;
bool get permissionsGranted => _permissionsGranted.value;
// Getters
bool get isAvailable => _isAvailable.value;
bool get isOn => _isOn.value;
bool get isScanning => _isScanning.value;
List<BluetoothDevice> get connectedDevices => _connectedDevices;
List<ScanResult> get scanResults => _scanResults;
BluetoothDevice? get selectedDevice => _selectedDevice.value;
BluetoothConnectionState get connectionState => _connectionState.value;
Map<String, dynamic> get lastConnectedDeviceInfo => _lastConnectedDeviceInfo.value;
// Observable getters (for reactive programming)
RxBool get isAvailableObs => _isAvailable;
RxBool get isOnObs => _isOn;
RxList<BluetoothDevice> get connectedDevicesObs => _connectedDevices;
RxList<ScanResult> get scanResultsObs => _scanResults;
Rx<BluetoothDevice?> get selectedDeviceObs => _selectedDevice;
Rx<BluetoothConnectionState> get connectionStateObs => _connectionState;
Rx<Map<String, dynamic>> get lastConnectedDeviceInfoObs => _lastConnectedDeviceInfo;
/// 初始化蓝牙服务
Future<BluetoothService> init() async {
try {
// 不在初始化时检查权限,改为在需要时才检查
// await _checkAndRequestPermissions();
// 在后台线程初始化蓝牙状态监听,避免主线程阻塞
Future.microtask(() {
// 监听蓝牙状态
_stateSubscription = FlutterBluePlus.adapterState.listen((state) {
_isOn.value = state == BluetoothAdapterState.on;
_isAvailable.value = state != BluetoothAdapterState.unavailable;
if (state == BluetoothAdapterState.on) {
// 蓝牙打开时,获取已连接设备,但不请求权限
// 只有在用户主动扫描时才请求权限
// 在后台线程执行,避免主线程阻塞
Future.microtask(() => _getConnectedDevices());
} else if (state == BluetoothAdapterState.off) {
// 蓝牙关闭时,清空设备列表
_connectedDevices.clear();
_scanResults.clear();
_selectedDevice.value = null;
_lastConnectedDeviceInfo.value = {};
}
});
});
// 不在初始化时立即检查蓝牙状态,而是延迟到UI渲染完成后
// 这样可以避免启动时卡顿
Future.delayed(const Duration(milliseconds: 800), () async {
try {
// 使用超时机制,避免无限等待蓝牙
bool isOn = await FlutterBluePlus.isOn
.timeout(const Duration(seconds: 3), onTimeout: () {
Logger.error('检查蓝牙状态超时');
return false;
});
_isOn.value = isOn;
_isAvailable.value = isOn;
if (isOn) {
// 在后台线程获取设备,避免主线程阻塞
Future.microtask(() => _getConnectedDevices());
}
} catch (e) {
Logger.error('延迟检查蓝牙状态失败: $e');
}
});
return this;
} catch (e) {
Logger.error('初始化蓝牙服务失败: $e');
return this;
}
}
/// 检查并请求蓝牙所需权限
Future<bool> _checkAndRequestPermissions() async {
// 暂时跳过权限检查,直接返回true
_permissionsGranted.value = true;
return true;
}
/// 再次请求权限
Future<bool> requestPermissions() async {
// 暂时跳过权限检查,直接返回true
_permissionsGranted.value = true;
return true;
}
/// 获取已连接的设备
Future<void> _getConnectedDevices() async {
try {
// 使用超时机制,避免无限等待
List<BluetoothDevice> devices = await FlutterBluePlus.connectedSystemDevices
.timeout(const Duration(seconds: 3), onTimeout: () {
Logger.error('获取已连接设备超时');
return <BluetoothDevice>[];
});
_connectedDevices.value = devices;
// 如果有已连接的设备但没有选中设备,则选中第一个
if (_connectedDevices.isNotEmpty && _selectedDevice.value == null) {
_selectedDevice.value = _connectedDevices[0];
_monitorConnectionState(_selectedDevice.value!);
// 更新最后连接的设备信息
_updateLastConnectedDeviceInfo();
}
Logger.info('已连接设备数量: ${_connectedDevices.length}');
} catch (e) {
Logger.error('获取已连接设备失败: $e');
}
}
/// 获取系统中已配对的设备
Future<List<BluetoothDevice>> getPairedDevices() async {
try {
// 获取已配对的设备(系统已知设备)
List<BluetoothDevice> systemDevices = await FlutterBluePlus.bondedDevices;
return systemDevices;
} catch (e) {
Logger.error('获取已配对设备失败: $e');
return [];
}
}
/// 开始扫描附近的蓝牙设备并尝试连接最强信号设备
Future<BluetoothDevice?> scanAndConnectToDevice({Duration? timeout}) async {
if (_isScanning.value) {
await stopScan();
}
// 清空旧的扫描结果
_scanResults.clear();
try {
// 设置扫描监听
_scanSubscription?.cancel();
_scanSubscription = FlutterBluePlus.scanResults.listen((results) {
_scanResults.value = results;
});
// 设置扫描中状态
_isScanning.value = true;
// 开始扫描
await FlutterBluePlus.startScan(
timeout: timeout ?? const Duration(seconds: 5),
);
// 扫描完成
_isScanning.value = false;
Logger.info('蓝牙扫描完成,发现 ${_scanResults.length} 个设备');
// 如果找到设备,尝试连接信号最强的
if (_scanResults.isNotEmpty) {
// 按信号强度排序
List<ScanResult> sortedResults = List.from(_scanResults);
sortedResults.sort((a, b) => b.rssi.compareTo(a.rssi));
// 尝试连接信号最强的设备
final topDevice = sortedResults.first.device;
Logger.info('尝试连接信号最强的设备: ${topDevice.platformName}');
bool success = await connectToDevice(topDevice);
if (success) {
return topDevice;
}
}
return null;
} catch (e) {
_isScanning.value = false;
Logger.error('蓝牙扫描或连接失败: $e');
return null;
}
}
/// 停止扫描
Future<void> stopScan() async {
if (!_isScanning.value) return;
try {
await FlutterBluePlus.stopScan();
_isScanning.value = false;
} catch (e) {
Logger.error('停止蓝牙扫描失败: $e');
}
}
/// 连接到指定的蓝牙设备 - 简化版本
Future<bool> connectToDevice(BluetoothDevice device) async {
Logger.info('尝试连接设备: ${device.platformName} (${device.remoteId.str})');
try {
// 如果是当前已连接设备,直接返回成功
if (_selectedDevice.value == device &&
_connectionState.value == BluetoothConnectionState.connected) {
Logger.info('设备已连接,无需重新连接');
return true;
}
// 断开当前连接
if (_selectedDevice.value != null && _selectedDevice.value != device) {
await disconnectFromDevice();
}
// 直接尝试连接
Logger.info('直接连接设备 ${device.platformName}');
await device.connect();
// 更新设备信息
_selectedDevice.value = device;
_monitorConnectionState(device);
_updateLastConnectedDeviceInfo();
Logger.info('设备 ${device.platformName} 连接成功');
return true;
} catch (e) {
Logger.error('连接设备 ${device.platformName} 失败: $e');
return false;
}
}
/// 断开与当前设备的连接
Future<bool> disconnectFromDevice() async {
if (_selectedDevice.value == null) {
Logger.info('没有当前选中的设备,无需断开连接');
return true;
}
try {
Logger.info('正在断开设备 ${_selectedDevice.value!.platformName} 的连接');
await _selectedDevice.value!.disconnect();
Logger.info('设备连接已断开,取消连接状态监听');
_connectionSubscription?.cancel();
_connectionSubscription = null;
_selectedDevice.value = null;
// 清除最后连接的设备信息
_lastConnectedDeviceInfo.value = {};
return true;
} catch (e) {
Logger.error('断开蓝牙设备连接失败: $e');
return false;
}
}
/// 监控连接状态
void _monitorConnectionState(BluetoothDevice device) {
Logger.info('设置设备 ${device.platformName} 的连接状态监听');
// 取消之前的监听
if (_connectionSubscription != null) {
Logger.info('取消之前的连接状态监听');
_connectionSubscription!.cancel();
_connectionSubscription = null;
}
// 设置新的监听
_connectionSubscription = device.connectionState.listen((state) {
Logger.info('设备 ${device.platformName} 连接状态变更为: $state');
_connectionState.value = state;
if (state == BluetoothConnectionState.disconnected) {
Logger.info('设备 ${device.platformName} 已断开连接');
_selectedDevice.value = null;
// 设备断开连接时,不清除最后连接的设备信息,以便下次可以重新连接
} else if (state == BluetoothConnectionState.connected) {
Logger.info('设备 ${device.platformName} 已成功连接');
// 设备连接成功时,更新最后连接的设备信息
_updateLastConnectedDeviceInfo();
} else if (state == BluetoothConnectionState.connecting) {
Logger.info('设备 ${device.platformName} 正在连接中...');
} else if (state == BluetoothConnectionState.disconnecting) {
Logger.info('设备 ${device.platformName} 正在断开连接...');
}
});
Logger.info('设备 ${device.platformName} 的连接状态监听已设置');
}
/// 获取已连接设备的信息
Map<String, dynamic> getConnectedDeviceInfo() {
if (_selectedDevice.value == null) {
return {
'connected': false,
'device': null,
};
}
final deviceInfo = {
'connected': _connectionState.value == BluetoothConnectionState.connected,
'device': {
'name': _selectedDevice.value!.platformName.isEmpty ?
'未命名设备' : _selectedDevice.value!.platformName,
'id': _selectedDevice.value!.remoteId.str,
'isConnected': _connectionState.value == BluetoothConnectionState.connected,
'rssi': _scanResults
.firstWhereOrNull((r) => r.device.remoteId == _selectedDevice.value!.remoteId)
?.rssi
}
};
// 更新最后连接的设备信息
_lastConnectedDeviceInfo.value = deviceInfo;
return deviceInfo;
}
/// 更新最后连接的设备信息
void _updateLastConnectedDeviceInfo() {
if (_selectedDevice.value != null) {
_lastConnectedDeviceInfo.value = {
'connected': _connectionState.value == BluetoothConnectionState.connected,
'device': {
'name': _selectedDevice.value!.platformName.isEmpty ?
'未命名设备' : _selectedDevice.value!.platformName,
'id': _selectedDevice.value!.remoteId.str,
'isConnected': _connectionState.value == BluetoothConnectionState.connected,
'rssi': _scanResults
.firstWhereOrNull((r) => r.device.remoteId == _selectedDevice.value!.remoteId)
?.rssi
}
};
}
}
/// 一个综合方法,执行自动查找并连接设备的完整流程
Future<BluetoothDevice?> autoConnectDevice() async {
try {
// 1. 先检查当前已连接设备
if (_selectedDevice.value != null &&
_connectionState.value == BluetoothConnectionState.connected) {
Logger.info('使用当前已连接设备: ${_selectedDevice.value!.platformName}');
return _selectedDevice.value;
}
// 2. 检查系统中已连接的设备
try {
List<BluetoothDevice> connectedDevices = await FlutterBluePlus.connectedSystemDevices
.timeout(const Duration(seconds: 3));
if (connectedDevices.isNotEmpty) {
// 有已连接的设备,直接使用第一个
Logger.info('发现系统已连接设备: ${connectedDevices.first.platformName}');
// 连接设备并更新服务状态
await connectToDevice(connectedDevices.first);
return connectedDevices.first;
}
} catch (e) {
Logger.error('检查系统连接设备失败: $e');
}
// 3. 尝试连接之前用过的设备(从已配对设备中寻找)
List<BluetoothDevice> pairedDevices = await FlutterBluePlus.bondedDevices;
// 如果有配对设备,尝试连接第一个
if (pairedDevices.isNotEmpty) {
Logger.info('尝试连接已配对设备: ${pairedDevices.first.platformName}');
bool success = await connectToDevice(pairedDevices.first);
if (success) {
return pairedDevices.first;
}
}
// 4. 没有找到可用设备
return null;
} catch (e) {
Logger.error('自动连接设备流程失败: $e');
return null;
}
}
/// 获取设备连接状态的简化方法 (用于兼容现有代码)
Future<BluetoothConnectionState> getReliableConnectionState(BluetoothDevice device) async {
try {
// 直接获取设备当前状态
BluetoothConnectionState state = await device.connectionState.first
.timeout(const Duration(seconds: 2), onTimeout: () {
Logger.info('获取设备 ${device.platformName} 连接状态超时');
return BluetoothConnectionState.disconnected;
});
// 如果获取到的状态是已连接,直接返回
if (state == BluetoothConnectionState.connected) {
return BluetoothConnectionState.connected;
}
// 作为备用检查,看设备是否在系统已连接列表中
try {
List<BluetoothDevice> connectedDevices = await FlutterBluePlus.connectedSystemDevices
.timeout(const Duration(seconds: 2));
for (var connectedDevice in connectedDevices) {
if (connectedDevice.remoteId.str == device.remoteId.str) {
return BluetoothConnectionState.connected;
}
}
} catch (e) {
// 忽略检查系统设备列表的错误
}
return state;
} catch (e) {
Logger.error('获取设备 ${device.platformName} 连接状态失败: $e');
return BluetoothConnectionState.disconnected;
}
}
@override
void onClose() {
_stateSubscription?.cancel();
_scanSubscription?.cancel();
_connectionSubscription?.cancel();
disconnectFromDevice();
super.onClose();
}
}