import 'dart:async'; 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(); // 内部实例 BluetoothService._internal(); static final BluetoothService _instance = BluetoothService._internal(); factory BluetoothService() => _instance; // ====== 状态管理 ====== // 蓝牙适配器状态 final _isAvailable = false.obs; final _isOn = false.obs; final _isInitialized = false.obs; // 权限状态 final _permissionsGranted = false.obs; // 设备管理 final _connectedDevices = [].obs; final _systemPairedDevices = [].obs; final _selectedDevice = Rx(null); final _deviceType = Rx(DeviceType.unknown); final _connectionState = Rx(BluetoothConnectionState.disconnected); final _lastConnectedDeviceInfo = Rx>({}); // 流订阅 StreamSubscription? _stateSubscription; // 防止重复刷新的标志 bool _isRefreshingDevices = false; // ====== Getters ====== // 基本getter bool get isAvailable => _isAvailable.value; bool get isOn => _isOn.value; bool get isInitialized => _isInitialized.value; bool get permissionsGranted => _permissionsGranted.value; // 设备相关getter List get connectedDevices => _connectedDevices; List get systemPairedDevices => _systemPairedDevices; BluetoothDevice? get selectedDevice => _selectedDevice.value; DeviceType get deviceType => _deviceType.value; BluetoothConnectionState get connectionState => _connectionState.value; Map get lastConnectedDeviceInfo => _lastConnectedDeviceInfo.value; // Observable getters RxBool get isAvailableObs => _isAvailable; RxBool get isOnObs => _isOn; RxBool get isInitializedObs => _isInitialized; RxBool get permissionsGrantedObs => _permissionsGranted; RxList get connectedDevicesObs => _connectedDevices; Rx get selectedDeviceObs => _selectedDevice; Rx get deviceTypeObs => _deviceType; Rx get connectionStateObs => _connectionState; Rx> get lastConnectedDeviceInfoObs => _lastConnectedDeviceInfo; /// 初始化蓝牙服务 Future init() async { if (_isInitialized.value) { Logger.info('蓝牙服务已初始化,无需重复初始化'); return this; } Logger.info('开始初始化蓝牙服务'); try { // 1. 设置蓝牙状态监听 _setupBluetoothListeners(); // 2. 初始检查蓝牙状态 _checkBluetoothState(); // 3. 请求权限 await requestPermissions(); // 4. 刷新系统设备 if (_isOn.value && _permissionsGranted.value) { await _refreshSystemDevices(); } // 5. 标记初始化完成 _isInitialized.value = true; Logger.info('蓝牙服务初始化完成'); return this; } catch (e) { Logger.error('初始化蓝牙服务失败: $e'); return this; } } /// 设置蓝牙状态监听 void _setupBluetoothListeners() { // 取消旧订阅(如果有) _stateSubscription?.cancel(); // 监听蓝牙适配器状态变化 _stateSubscription = FlutterBluePlus.adapterState.listen((state) { _isOn.value = state == BluetoothAdapterState.on; _isAvailable.value = state != BluetoothAdapterState.unavailable; if (state == BluetoothAdapterState.on) { Logger.info('蓝牙已开启'); if (_permissionsGranted.value) { _refreshSystemDevices(); } } else if (state == BluetoothAdapterState.off) { Logger.info('蓝牙已关闭'); _resetDeviceState(); } }); } /// 初始检查蓝牙状态 Future _checkBluetoothState() async { try { bool isOn = await FlutterBluePlus.isOn .timeout(const Duration(seconds: 5), onTimeout: () => false); _isOn.value = isOn; _isAvailable.value = isOn; Logger.info('当前蓝牙是否已开启: $isOn'); } catch (e) { Logger.error('检查蓝牙状态失败: $e'); _isOn.value = false; _isAvailable.value = false; } } /// 重置设备状态 void _resetDeviceState() { _connectedDevices.clear(); _systemPairedDevices.clear(); _selectedDevice.value = null; _lastConnectedDeviceInfo.value = {}; _deviceType.value = DeviceType.unknown; } /// 检查并请求蓝牙权限 Future requestPermissions() async { try { // iOS无需额外权限 if (!Platform.isAndroid) { _permissionsGranted.value = true; return true; } // 请求所有必要权限 final permissions = [ // Permission.bluetoothScan, // Permission.bluetoothConnect, // Permission.location, // Android需要定位权限来扫描BLE设备 Permission.microphone, ]; // 一次性请求所有权限 Map statuses = await permissions.request(); // 检查所有权限是否已授予 bool allGranted = statuses.values.every((status) => status.isGranted); _permissionsGranted.value = allGranted; if (!allGranted) { // 检查哪些权限被拒绝 List deniedPermissions = []; statuses.forEach((permission, status) { if (!status.isGranted) { deniedPermissions.add(permission.toString().split('.').last); } }); Logger.warning('权限被拒绝: ${deniedPermissions.join(", ")}'); } return allGranted; } catch (e) { Logger.error('请求权限失败: $e'); _permissionsGranted.value = false; return false; } } /// 刷新系统蓝牙设备(已连接和已配对) Future _refreshSystemDevices() async { if (!_permissionsGranted.value || !_isOn.value) { Logger.warning('无法刷新系统设备:蓝牙未开启或缺少权限'); return; } // 防止重复刷新 if (_isRefreshingDevices) { return; } _isRefreshingDevices = true; try { // 获取已连接的系统设备 List devices = await FlutterBluePlus.connectedSystemDevices .timeout(const Duration(seconds: 10), onTimeout: () => []); _connectedDevices.value = devices; Logger.info('获取到${devices.length}个系统已连接设备'); // 更新选中设备的连接状态(如果有) if (_selectedDevice.value != null) { bool stillConnected = _connectedDevices.any( (d) => d.remoteId.str == _selectedDevice.value!.remoteId.str ); _connectionState.value = stillConnected ? BluetoothConnectionState.connected : BluetoothConnectionState.disconnected; if (stillConnected) { _updateLastConnectedDeviceInfo(); } } // 获取系统已配对设备 List pairedDevices = await FlutterBluePlus.bondedDevices .timeout(const Duration(seconds: 10), onTimeout: () => []); _systemPairedDevices.value = pairedDevices; Logger.info('获取到${pairedDevices.length}个系统已配对设备'); } catch (e) { Logger.error('刷新系统设备失败: $e'); } finally { _isRefreshingDevices = false; } } /// 查找音频设备 BluetoothDevice? _findAudioDevice(List devices) { if (devices.isEmpty) return null; // 音频设备的可能名称关键词 final List audioKeywords = [ 'headphone', 'earphone', 'earbuds', 'headset', 'speaker', 'audio', '耳机', '音箱', '音响' ]; // 尝试匹配音频设备名称 for (BluetoothDevice device in devices) { String name = device.platformName.toLowerCase(); if (audioKeywords.any((keyword) => name.contains(keyword))) { return device; } } return null; } /// 确定设备类型 void _determineDeviceType(BluetoothDevice device) { 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; } else { _deviceType.value = DeviceType.ble; } } /// 获取已连接设备的信息 Map getConnectedDeviceInfo() { if (_selectedDevice.value == null) { return { 'connected': false, 'device': null, 'deviceType': _deviceType.value.toString().split('.').last }; } // 判断设备是否在已连接列表中 bool isConnected = _connectedDevices.any( (d) => d.remoteId.str == _selectedDevice.value!.remoteId.str ); // 判断设备是否在已配对列表中 bool isPaired = _systemPairedDevices.any( (d) => d.remoteId.str == _selectedDevice.value!.remoteId.str ); final deviceInfo = { 'connected': isConnected, 'paired': isPaired, 'device': { 'name': _selectedDevice.value!.platformName.isEmpty ? '未命名设备' : _selectedDevice.value!.platformName, 'id': _selectedDevice.value!.remoteId.str, 'isConnected': isConnected, 'isPaired': isPaired, }, 'deviceType': _deviceType.value.toString().split('.').last }; return deviceInfo; } /// 获取已配对设备的信息 Map getPairedDeviceInfo(BluetoothDevice device) { if (device == null) { return { 'connected': false, 'paired': false, 'device': null, 'deviceType': DeviceType.unknown.toString().split('.').last }; } // 判断设备是否在已连接列表中 bool isConnected = _connectedDevices.any( (d) => d.remoteId.str == device.remoteId.str ); // 确定设备类型 DeviceType type = DeviceType.unknown; final String deviceName = device.platformName.toLowerCase(); // 音频设备关键词 final List audioKeywords = [ 'headphone', 'earphone', 'earbuds', 'headset', 'speaker', 'audio', '耳机', '音箱', '音响' ]; bool hasAudioKeyword = audioKeywords.any((keyword) => deviceName.contains(keyword)); if (hasAudioKeyword || isConnected) { type = DeviceType.classicAudio; } else { type = DeviceType.ble; } final deviceInfo = { 'connected': isConnected, 'paired': true, 'device': { 'name': device.platformName.isEmpty ? '未命名设备' : device.platformName, 'id': device.remoteId.str, 'isConnected': isConnected, 'isPaired': true, }, 'deviceType': type.toString().split('.').last }; return deviceInfo; } /// 设置选中的设备(不进行连接操作) void setSelectedDevice(BluetoothDevice device) { if (device != null) { _selectedDevice.value = device; _determineDeviceType(device); _updateLastConnectedDeviceInfo(); Logger.info('已设置选中设备: ${device.platformName}'); } } /// 更新最后连接的设备信息 void _updateLastConnectedDeviceInfo() { if (_selectedDevice.value != null) { _lastConnectedDeviceInfo.value = getConnectedDeviceInfo(); } } /// 查找系统已连接设备 Future findConnectedSystemDevice() async { if (!_permissionsGranted.value || !_isOn.value) { Logger.warning('蓝牙未开启或缺少权限,无法查找系统连接设备'); return null; } try { // 刷新系统设备列表(避免重复刷新) if (!_isRefreshingDevices) { await _refreshSystemDevices(); } // 如果没有已连接设备,直接返回null if (_connectedDevices.isEmpty) { Logger.info('未找到已连接的蓝牙设备'); return null; } // 优先找出可能的音频设备 BluetoothDevice? audioDevice = _findAudioDevice(_connectedDevices); BluetoothDevice device = audioDevice ?? _connectedDevices.first; // 自动选择设备 _selectedDevice.value = device; _determineDeviceType(device); _connectionState.value = BluetoothConnectionState.connected; _updateLastConnectedDeviceInfo(); Logger.info('找到已连接的蓝牙设备: ${device.platformName}'); return device; } catch (e) { Logger.error('查找系统已连接设备失败: $e'); return null; } } /// 清理资源 @override void onClose() { // 取消所有订阅 _stateSubscription?.cancel(); super.onClose(); } }