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'; /// 设备类型枚举 enum DeviceType { unknown, // 未知设备类型 classicAudio, // 经典蓝牙音频设备(耳机等) ble, // BLE设备 dual // 双模设备(同时支持经典蓝牙和BLE) } /// 蓝牙设备服务,用于发现和管理蓝牙设备 class BluetoothService extends GetxService { static BluetoothService get to => Get.find(); // 单例实例 static final BluetoothService _instance = BluetoothService._internal(); factory BluetoothService() => _instance; BluetoothService._internal(); // 设备状态 final _isAvailable = false.obs; final _isOn = false.obs; // 已连接的设备 final _connectedDevices = [].obs; final _systemPairedDevices = [].obs; // 扫描状态 final _isScanning = false.obs; // 扫描结果 final _scanResults = [].obs; // 当前选中的设备 final _selectedDevice = Rx(null); final _deviceType = Rx(DeviceType.unknown); // 连接状态 final _connectionState = Rx(BluetoothConnectionState.disconnected); // 存储最后连接的设备信息,供其他控制器使用 final _lastConnectedDeviceInfo = Rx>({}); // 订阅 StreamSubscription? _stateSubscription; StreamSubscription? _scanSubscription; StreamSubscription? _connectionSubscription; // 连接锁,防止并发操作 bool _isConnecting = false; // 记录连接尝试次数 int _connectionAttempts = 0; static const int MAX_CONNECTION_ATTEMPTS = 2; // 权限状态 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 get connectedDevices => _connectedDevices; List get systemPairedDevices => _systemPairedDevices; List get scanResults => _scanResults; BluetoothDevice? get selectedDevice => _selectedDevice.value; DeviceType get deviceType => _deviceType.value; BluetoothConnectionState get connectionState => _connectionState.value; Map get lastConnectedDeviceInfo => _lastConnectedDeviceInfo.value; // Observable getters (for reactive programming) RxBool get isAvailableObs => _isAvailable; RxBool get isOnObs => _isOn; RxList get connectedDevicesObs => _connectedDevices; RxList get scanResultsObs => _scanResults; Rx get selectedDeviceObs => _selectedDevice; Rx get deviceTypeObs => _deviceType; Rx get connectionStateObs => _connectionState; Rx> get lastConnectedDeviceInfoObs => _lastConnectedDeviceInfo; // 电池服务UUID static const String BATTERY_SERVICE_UUID = "0000180f-0000-1000-8000-00805f9b34fb"; // 电池电量特征UUID static const String BATTERY_CHARACTERISTIC_UUID = "00002a19-0000-1000-8000-00805f9b34fb"; /// 初始化蓝牙服务 Future init() async { try { // 确保权限检查在后台线程执行,避免主线程阻塞 Future.microtask(() async { // 仅在Android上请求权限 if (Platform.isAndroid) { await _checkAndRequestPermissions(); } }); // 在后台线程初始化蓝牙状态监听 Future.microtask(() { // 监听蓝牙状态 _stateSubscription = FlutterBluePlus.adapterState.listen((state) { _isOn.value = state == BluetoothAdapterState.on; _isAvailable.value = state != BluetoothAdapterState.unavailable; if (state == BluetoothAdapterState.on) { // 蓝牙打开时,获取已连接和已配对设备 _refreshSystemDevices(); } else if (state == BluetoothAdapterState.off) { // 蓝牙关闭时,清空设备列表 _connectedDevices.clear(); _systemPairedDevices.clear(); _scanResults.clear(); _selectedDevice.value = null; _lastConnectedDeviceInfo.value = {}; _deviceType.value = DeviceType.unknown; } }); }); // 延迟检查蓝牙状态,避免启动时卡顿 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) { // 在后台刷新设备状态 _refreshSystemDevices(); } } catch (e) { Logger.error('延迟检查蓝牙状态失败: $e'); } }); return this; } catch (e) { Logger.error('初始化蓝牙服务失败: $e'); return this; } } /// 检查并请求蓝牙所需权限(Android 12+) Future _checkAndRequestPermissions() async { try { if (Platform.isAndroid) { // 对于Android 12+,需要BLUETOOTH_SCAN和BLUETOOTH_CONNECT权限 Map statuses = await [ Permission.bluetoothScan, Permission.bluetoothConnect, Permission.location, ].request(); bool allGranted = statuses.values.every((status) => status.isGranted); _permissionsGranted.value = allGranted; if (!allGranted) { Logger.warning('蓝牙权限未完全授予: $statuses'); } return allGranted; } // iOS不需要显式请求蓝牙权限 _permissionsGranted.value = true; return true; } catch (e) { Logger.error('检查蓝牙权限失败: $e'); _permissionsGranted.value = false; return false; } } /// 再次请求权限 Future requestPermissions() async { return await _checkAndRequestPermissions(); } /// 刷新系统设备状态(已连接和已配对设备) Future _refreshSystemDevices() async { try { // 避免重复刷新,使用标志位 bool _isRefreshing = false; if (_isRefreshing) return; _isRefreshing = true; // 获取系统已连接设备 try { List devices = await FlutterBluePlus.connectedSystemDevices .timeout(const Duration(seconds: 3), onTimeout: () { Logger.error('获取已连接设备超时'); return []; }); _connectedDevices.value = devices; Logger.info('已连接系统设备数量: ${_connectedDevices.length}'); // 如果有当前选中设备,更新其状态 if (_selectedDevice.value != null) { // 检查选中设备是否仍然在已连接列表中 bool stillConnected = _connectedDevices.any( (d) => d.remoteId.str == _selectedDevice.value!.remoteId.str ); if (stillConnected) { _connectionState.value = BluetoothConnectionState.connected; _updateLastConnectedDeviceInfo(); } else { _connectionState.value = BluetoothConnectionState.disconnected; } } } catch (e) { Logger.error('获取已连接设备失败: $e'); } // 获取已配对设备 try { List pairedDevices = await FlutterBluePlus.bondedDevices .timeout(const Duration(seconds: 3), onTimeout: () { Logger.error('获取已配对设备超时'); return []; }); _systemPairedDevices.value = pairedDevices; Logger.info('系统已配对设备数量: ${_systemPairedDevices.length}'); } catch (e) { Logger.error('获取已配对设备失败: $e'); } // 如果有已连接的设备但没有选中设备,自动选择第一个 if (_connectedDevices.isNotEmpty && _selectedDevice.value == null) { Logger.info('自动选择第一个已连接设备: ${_connectedDevices[0].platformName}'); _selectedDevice.value = _connectedDevices[0]; _determineDeviceType(_selectedDevice.value!); _connectionState.value = BluetoothConnectionState.connected; _updateLastConnectedDeviceInfo(); } _isRefreshing = false; } catch (e) { Logger.error('刷新系统设备状态失败: $e'); } } /// 确定设备类型(经典蓝牙/BLE/双模) void _determineDeviceType(BluetoothDevice device) { try { // 默认设为未知类型 _deviceType.value = DeviceType.unknown; // 设备名称包含耳机/headphone/earphone/earbuds等关键词可能是音频设备 final String deviceName = device.platformName.toLowerCase(); final List audioKeywords = [ 'headphone', 'earphone', 'earbuds', 'headset', 'speaker', 'audio', '耳机', '音箱', '音响' ]; bool hasAudioKeyword = audioKeywords.any((keyword) => deviceName.contains(keyword)); // 如果在已连接设备列表中,很可能是已经通过系统连接的经典蓝牙 bool inConnectedList = _connectedDevices.any((d) => d.remoteId.str == device.remoteId.str); if (hasAudioKeyword || inConnectedList) { _deviceType.value = DeviceType.classicAudio; Logger.info('设备${device.platformName}被判定为经典蓝牙音频设备'); } else { // 不确定的情况,先假设是BLE设备,连接后可能会更新 _deviceType.value = DeviceType.ble; Logger.info('设备${device.platformName}被判定为BLE设备'); } } catch (e) { Logger.error('确定设备类型失败: $e'); _deviceType.value = DeviceType.unknown; } } /// 开始扫描附近的蓝牙设备 Future> startScan({Duration? timeout}) async { if (_isScanning.value) { await stopScan(); } // 清空旧的扫描结果 _scanResults.clear(); try { // 确保拥有扫描权限 if (Platform.isAndroid && !await Permission.bluetoothScan.isGranted) { Logger.warning('没有蓝牙扫描权限,尝试请求权限'); await _checkAndRequestPermissions(); } // 设置扫描监听 _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} 个设备'); return _scanResults; } catch (e) { _isScanning.value = false; Logger.error('蓝牙扫描失败: $e'); return []; } } /// 停止扫描 Future stopScan() async { if (!_isScanning.value) return; try { await FlutterBluePlus.stopScan(); _isScanning.value = false; } catch (e) { Logger.error('停止蓝牙扫描失败: $e'); } } /// 连接到指定的蓝牙设备 /// 针对不同类型设备使用不同的连接策略 Future connectToDevice(BluetoothDevice device) async { // 防止并发连接操作 if (_isConnecting) { Logger.warning('已有正在进行的连接操作,请等待完成'); return false; } _isConnecting = true; _connectionAttempts = 0; try { Logger.info('尝试连接设备: ${device.platformName} (${device.remoteId.str})'); // 确定设备类型 _determineDeviceType(device); // 检查设备是否已在系统连接列表中 bool alreadyConnected = _connectedDevices.any((d) => d.remoteId.str == device.remoteId.str); // 如果是当前已选择且已连接的设备,直接返回成功 if (_selectedDevice.value == device && alreadyConnected) { Logger.info('设备已连接,无需重新连接'); _connectionState.value = BluetoothConnectionState.connected; _updateLastConnectedDeviceInfo(); _isConnecting = false; return true; } // 如果有其他已选择的设备,先取消监听并清除 if (_selectedDevice.value != null && _selectedDevice.value != device) { _connectionSubscription?.cancel(); _connectionSubscription = null; } // 更新选中的设备 _selectedDevice.value = device; // 对于经典蓝牙音频设备,不尝试BLE连接,直接检查系统连接状态 if (_deviceType.value == DeviceType.classicAudio) { Logger.info('经典蓝牙音频设备,检查系统连接状态'); // 刷新系统连接设备列表 await _refreshSystemDevices(); // 再次检查设备是否在已连接列表中 alreadyConnected = _connectedDevices.any((d) => d.remoteId.str == device.remoteId.str); if (alreadyConnected) { Logger.info('设备已在系统连接列表中,视为已连接'); _connectionState.value = BluetoothConnectionState.connected; _monitorSystemConnectionState(device); _updateLastConnectedDeviceInfo(); _isConnecting = false; return true; } else { Logger.info('经典蓝牙设备未在系统连接列表中,需要在系统设置中配对和连接'); _connectionState.value = BluetoothConnectionState.disconnected; _isConnecting = false; return false; } } // 对于BLE或双模设备,尝试进行BLE连接 Logger.info('尝试进行BLE连接'); return await _attemptBleConnection(device); } catch (e) { Logger.error('连接设备 ${device.platformName} 失败: $e'); _connectionState.value = BluetoothConnectionState.disconnected; _isConnecting = false; return false; } } /// 尝试进行BLE连接 Future _attemptBleConnection(BluetoothDevice device) async { try { _connectionState.value = BluetoothConnectionState.connecting; // 增加连接尝试次数 _connectionAttempts++; // 不使用autoConnect=true来避免与mtu参数冲突 // 根据错误日志,mtu和autoConnect是不兼容的 bool autoConnect = false; // 始终使用false避免兼容性问题 Logger.info('BLE连接尝试 #$_connectionAttempts,autoConnect=$autoConnect'); // 开始监听连接状态 _monitorConnectionState(device); // 尝试连接,不同的尝试使用不同的超时时间 if (_connectionAttempts == 1) { // 第一次尝试:短超时 Logger.info('第一次尝试使用短超时(4秒)'); await device.connect( autoConnect: autoConnect, timeout: const Duration(seconds: 4) ); } else { // 第二次尝试:长超时 Logger.info('第二次尝试使用长超时(8秒)'); await device.connect( autoConnect: autoConnect, timeout: const Duration(seconds: 8) ); } // 如果连接成功,更新状态 _connectionState.value = BluetoothConnectionState.connected; _updateLastConnectedDeviceInfo(); Logger.info('设备 ${device.platformName} 连接成功'); _isConnecting = false; return true; } catch (e) { // 连接失败,检查是否需要重试 Logger.error('BLE连接尝试 #$_connectionAttempts 失败: $e'); if (_connectionAttempts < MAX_CONNECTION_ATTEMPTS) { Logger.info('尝试使用不同参数重新连接'); // 断开连接并等待一段时间 try { await device.disconnect(); } catch (disconnectError) { // 忽略断开连接的错误 Logger.error('断开连接时出错,继续尝试: $disconnectError'); } // 等待时间更长,确保设备和系统状态重置 await Future.delayed(const Duration(milliseconds: 2000)); // 重试连接 return await _attemptBleConnection(device); } else { // 连接失败且达到最大尝试次数 _connectionState.value = BluetoothConnectionState.disconnected; _isConnecting = false; return false; } } } /// 断开与当前设备的连接 Future disconnectFromDevice() async { if (_selectedDevice.value == null) { Logger.info('没有当前选中的设备,无需断开连接'); return true; } // 取消设备监听 _connectionSubscription?.cancel(); _connectionSubscription = null; try { // 对于经典蓝牙设备,不调用disconnect if (_deviceType.value == DeviceType.classicAudio) { Logger.info('经典蓝牙设备,仅清除选择状态,不调用disconnect'); _selectedDevice.value = null; _connectionState.value = BluetoothConnectionState.disconnected; return true; } // 对于BLE设备,调用disconnect Logger.info('正在断开设备 ${_selectedDevice.value!.platformName} 的连接'); await _selectedDevice.value!.disconnect(); _selectedDevice.value = null; _connectionState.value = BluetoothConnectionState.disconnected; return true; } catch (e) { Logger.error('断开蓝牙设备连接失败: $e'); // 即使失败也清除状态 _selectedDevice.value = null; _connectionState.value = BluetoothConnectionState.disconnected; return false; } } /// 监控BLE连接状态 void _monitorConnectionState(BluetoothDevice device) { Logger.info('设置设备 ${device.platformName} 的BLE连接状态监听'); // 取消之前的监听 _connectionSubscription?.cancel(); // 设置新的监听 _connectionSubscription = device.connectionState.listen((state) { Logger.info('设备 ${device.platformName} BLE连接状态变更为: $state'); _connectionState.value = state; if (state == BluetoothConnectionState.disconnected) { Logger.info('设备 ${device.platformName} BLE连接已断开'); // 设备断开连接时,不清除设备信息,以便下次可以重新连接 } else if (state == BluetoothConnectionState.connected) { Logger.info('设备 ${device.platformName} BLE连接已成功'); // 设备连接成功时,更新最后连接的设备信息 _updateLastConnectedDeviceInfo(); } }); } /// 监控系统连接状态(针对经典蓝牙设备) void _monitorSystemConnectionState(BluetoothDevice device) { Logger.info('设置设备 ${device.platformName} 的系统连接状态监听'); // 使用定时器定期检查系统连接状态 Timer.periodic(const Duration(seconds: 5), (timer) async { // 如果设备已变更或服务关闭,停止监控 if (_selectedDevice.value == null || _selectedDevice.value!.remoteId.str != device.remoteId.str) { timer.cancel(); return; } try { await _refreshSystemDevices(); // 检查设备是否仍在系统连接列表中 bool stillConnected = _connectedDevices.any( (d) => d.remoteId.str == device.remoteId.str ); if (stillConnected && _connectionState.value != BluetoothConnectionState.connected) { Logger.info('设备 ${device.platformName} 在系统连接列表中,更新为已连接状态'); _connectionState.value = BluetoothConnectionState.connected; _updateLastConnectedDeviceInfo(); } else if (!stillConnected && _connectionState.value == BluetoothConnectionState.connected) { Logger.info('设备 ${device.platformName} 不在系统连接列表中,更新为断开状态'); _connectionState.value = BluetoothConnectionState.disconnected; } } catch (e) { Logger.error('监控系统连接状态失败: $e'); } }); } /// 获取已连接设备的信息 Map getConnectedDeviceInfo() { if (_selectedDevice.value == null) { return { 'connected': false, 'device': null, 'deviceType': _deviceType.value.toString().split('.').last }; } 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 }, 'deviceType': _deviceType.value.toString().split('.').last }; // 更新最后连接的设备信息 _lastConnectedDeviceInfo.value = deviceInfo; return deviceInfo; } /// 更新最后连接的设备信息 void _updateLastConnectedDeviceInfo() { if (_selectedDevice.value != null) { _lastConnectedDeviceInfo.value = getConnectedDeviceInfo(); } } /// 一个综合方法,查找且尝试使用系统已连接的设备 /// 针对经典蓝牙耳机优化,避免使用BLE连接 Future findConnectedSystemDevice() async { try { // 先刷新系统设备列表 await _refreshSystemDevices(); // 1. 检查当前是否有已选择且已连接的设备 if (_selectedDevice.value != null && _connectionState.value == BluetoothConnectionState.connected) { Logger.info('使用当前已连接设备: ${_selectedDevice.value!.platformName}'); return _selectedDevice.value; } // 2. 检查系统已连接设备列表 if (_connectedDevices.isNotEmpty) { // 优先选择可能是音频设备的 BluetoothDevice audioDevice = _connectedDevices.firstWhere( (device) { final name = device.platformName.toLowerCase(); return name.contains('headphone') || name.contains('earphone') || name.contains('earbuds') || name.contains('headset') || name.contains('speaker') || name.contains('耳机') || name.contains('音箱'); }, orElse: () => _connectedDevices.first ); Logger.info('在系统已连接设备中找到设备: ${audioDevice.platformName}'); // 设置为当前设备并更新状态 _selectedDevice.value = audioDevice; _determineDeviceType(audioDevice); _connectionState.value = BluetoothConnectionState.connected; _monitorSystemConnectionState(audioDevice); _updateLastConnectedDeviceInfo(); return audioDevice; } // 3. 如果没有已连接设备,检查已配对设备 return null; } catch (e) { Logger.error('查找系统已连接设备失败: $e'); return null; } } /// 获取设备电量 Future getBatteryLevel() async { if (_selectedDevice.value == null || _connectionState.value != BluetoothConnectionState.connected) { return null; } try { // 对于BLE设备,尝试读取电池服务 if (_deviceType.value == DeviceType.ble || _deviceType.value == DeviceType.dual) { // 发现设备服务 List services = await _selectedDevice.value!.discoverServices(); // 查找电池服务 for (var service in services) { if (service.uuid.toString().toLowerCase() == BATTERY_SERVICE_UUID) { // 查找电池特征 for (var characteristic in service.characteristics) { if (characteristic.uuid.toString().toLowerCase() == BATTERY_CHARACTERISTIC_UUID) { // 读取电池电量 List value = await characteristic.read(); if (value.isNotEmpty) { return value[0]; // 电量百分比 } } } } } } // 对于经典蓝牙设备,可能需要平台特定的方法 if (_deviceType.value == DeviceType.classicAudio) { // 这里需要使用平台通道或其他插件获取经典蓝牙设备电量 // 目前根据设备名称特征尝试估计电量 // 部分设备会在名称后附加电量信息,如"XXX耳机(80%)" if (_selectedDevice.value != null) { final deviceName = _selectedDevice.value!.platformName; final percentRegex = RegExp(r'(\d+)%'); final match = percentRegex.firstMatch(deviceName); if (match != null && match.groupCount >= 1) { final percentStr = match.group(1); if (percentStr != null) { final percent = int.tryParse(percentStr); if (percent != null && percent >= 0 && percent <= 100) { return percent; } } } } Logger.info('无法从设备名称中提取电量信息'); } // 如果以上方法都无法获取电量,返回null return null; } catch (e) { Logger.error('获取设备电量失败: $e'); return null; } } @override void onClose() { _stateSubscription?.cancel(); _scanSubscription?.cancel(); _connectionSubscription?.cancel(); disconnectFromDevice(); super.onClose(); } }