import 'dart:async'; import 'package:get/get.dart'; import '../../../core/routes/app_routes.dart'; import '../../../data/services/bluetooth_service.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart' hide BluetoothService; import '../../../core/utils/logger.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:flutter/material.dart'; enum PairingStatus { initial, // 初始状态 requesting, // 请求权限中 scanning, // 扫描设备中 connecting, // 连接设备中 found, // 找到并连接设备 noPermission, // 缺少权限 bluetoothOff, // 蓝牙未开启 needsSystemPairing, // 需要在系统设置中配对 failed // 操作失败 } class PairingController extends GetxController { // 配对状态 final _pairingStatus = PairingStatus.initial.obs; PairingStatus get pairingStatus => _pairingStatus.value; // 状态描述(用于UI显示) final _statusDescription = ''.obs; String get statusDescription => _statusDescription.value; // 加载动画的点 final _animationDots = ''.obs; String get animationDots => _animationDots.value; // 动画定时器 Timer? _animationTimer; // 蓝牙服务 late BluetoothService _bluetoothService; // 设备信息 final _deviceInfo = Rx>({}); Map get deviceInfo => _deviceInfo.value; // 蓝牙状态 final _isBluetoothAvailable = false.obs; final _isBluetoothOn = false.obs; bool get isBluetoothAvailable => _isBluetoothAvailable.value; bool get isBluetoothOn => _isBluetoothOn.value; // 错误消息(包含解决方案提示) final _errorMessage = ''.obs; String get errorMessage => _errorMessage.value; // 扫描到的设备列表 final _scannedDevices = [].obs; List get scannedDevices => _scannedDevices; // 已配对的设备列表 final _pairedDevices = [].obs; List get pairedDevices => _pairedDevices; // 重试计数(分别为不同操作设置) int _initRetryCount = 0; int _scanRetryCount = 0; int _connectRetryCount = 0; static const int MAX_RETRY_COUNT = 3; @override void onInit() { super.onInit(); _initializeProcess(); } @override void onClose() { _stopAnimation(); _bluetoothService.stopScan(); super.onClose(); } // 初始化流程 Future _initializeProcess() async { // 启动动画 _startAnimation(); _updateStatus(PairingStatus.initial, '正在初始化...'); try { // 获取或初始化蓝牙服务 await _getBluetoothService(); // 先检查权限,再处理后续流程 await _checkAndRequestPermissions(); } catch (e) { Logger.error('初始化过程失败: $e'); _updateStatus(PairingStatus.failed, '初始化失败'); _setError('初始化蓝牙服务失败,请重试', '可能是蓝牙服务暂时不可用'); } } // 获取蓝牙服务 Future _getBluetoothService() async { try { // 检查是否已注册 if (Get.isRegistered()) { _bluetoothService = Get.find(); // 如果服务未初始化,等待初始化完成 if (!_bluetoothService.isInitialized) { // 监听初始化状态变化 await _waitForInitialization(); } } else { // 初始化并注册服务 _bluetoothService = await Get.put(BluetoothService()).init(); } // 设置蓝牙状态监听 _setupBluetoothListeners(); } catch (e) { Logger.error('获取蓝牙服务失败: $e'); throw Exception('获取蓝牙服务失败: $e'); } } // 等待蓝牙服务初始化完成 Future _waitForInitialization() async { // 使用 Completer 将事件监听转换为 Future final Completer completer = Completer(); late final Worker worker; // 一次性监听 worker = ever(_bluetoothService.isInitializedObs, (bool initialized) { if (initialized) { completer.complete(); worker.dispose(); // 完成后取消监听 } }); // 如果已经初始化,直接完成 if (_bluetoothService.isInitialized) { completer.complete(); worker.dispose(); } // 设置超时 return completer.future.timeout( const Duration(seconds: 10), onTimeout: () { worker.dispose(); throw TimeoutException('等待蓝牙服务初始化超时'); }, ); } // 设置蓝牙状态监听 void _setupBluetoothListeners() { // 监听蓝牙可用性 _isBluetoothAvailable.value = _bluetoothService.isAvailable; ever(_bluetoothService.isAvailableObs, (bool available) { _isBluetoothAvailable.value = available; if (!available) { _updateStatus(PairingStatus.failed, '蓝牙不可用'); _setError('蓝牙不可用', '请检查设备是否支持蓝牙功能'); } }); // 监听蓝牙开关状态 _isBluetoothOn.value = _bluetoothService.isOn; ever(_bluetoothService.isOnObs, (bool on) { _isBluetoothOn.value = on; // 蓝牙状态改变时处理 if (on) { if (_pairingStatus.value == PairingStatus.bluetoothOff) { // 如果蓝牙刚被打开,继续配对流程 _continueAfterBluetoothOn(); } } else { // 蓝牙关闭,更新状态 _updateStatus(PairingStatus.bluetoothOff, '蓝牙已关闭'); _setError('蓝牙已关闭', '请开启蓝牙后再试'); } }); } // 检查并请求权限 Future _checkAndRequestPermissions() async { _updateStatus(PairingStatus.requesting, '正在请求权限...'); try { bool hasPermissions = await _bluetoothService.requestPermissions(); if (!hasPermissions) { // 权限被拒绝 _handlePermissionDenied(); return; } // 权限已授予,检查蓝牙状态 if (!_bluetoothService.isOn) { _updateStatus(PairingStatus.bluetoothOff, '蓝牙已关闭'); _setError('蓝牙已关闭', '请开启蓝牙后再试'); return; } // 开始查找设备 _startFindingDevices(); } catch (e) { Logger.error('权限请求失败: $e'); _updateStatus(PairingStatus.noPermission, '权限请求失败'); _setError('权限请求失败', '请手动授予蓝牙和位置权限'); } } // 处理权限被拒绝的情况 void _handlePermissionDenied() async { // 检查是否永久拒绝 bool isPermanentlyDenied = false; if (GetPlatform.isAndroid) { PermissionStatus bluetoothScan = await Permission.bluetoothScan.status; PermissionStatus bluetoothConnect = await Permission.bluetoothConnect.status; PermissionStatus location = await Permission.location.status; // 如果任一权限被永久拒绝 isPermanentlyDenied = bluetoothScan.isPermanentlyDenied || bluetoothConnect.isPermanentlyDenied || location.isPermanentlyDenied; } _updateStatus(PairingStatus.noPermission, '缺少必要权限'); if (isPermanentlyDenied) { _setError('缺少必要权限', '您已永久拒绝权限,请前往系统设置中手动开启'); // 显示前往设置的提示 _showGoToSettingsDialog(); } else { _setError('缺少必要权限', '请授予蓝牙和位置权限以继续'); } } // 显示前往设置的对话框 void _showGoToSettingsDialog() { Get.dialog( AlertDialog( title: const Text('需要权限'), content: const Text('蓝牙搜索需要特定权限,请前往系统设置开启'), actions: [ TextButton( onPressed: () => Get.back(), child: const Text('稍后'), ), TextButton( onPressed: () { Get.back(); goToAppSettings(); }, child: const Text('前往设置'), ), ], ), barrierDismissible: false, ); } // 蓝牙开启后继续流程 void _continueAfterBluetoothOn() { if (_bluetoothService.permissionsGranted) { _startFindingDevices(); } else { _checkAndRequestPermissions(); } } // 开始查找设备 Future _startFindingDevices() async { // 先检查上次连接的设备 if (_checkLastConnectedDevice()) { return; } // 查找系统已连接的设备 await _findSystemConnectedDevices(); } // 检查上次连接的设备 bool _checkLastConnectedDevice() { // 检查是否有上次连接的设备信息 if (_bluetoothService.lastConnectedDeviceInfo.isNotEmpty && _bluetoothService.lastConnectedDeviceInfo['connected'] == true) { Logger.info('使用上次连接的设备信息'); _deviceInfo.value = _bluetoothService.lastConnectedDeviceInfo; _onDeviceConnected(); return true; } return false; } // 查找系统已连接的设备 Future _findSystemConnectedDevices() async { _updateStatus(PairingStatus.scanning, '正在查找已连接设备...'); try { // 查找系统已连接的设备 BluetoothDevice? device = await _bluetoothService.findConnectedSystemDevice() .timeout(const Duration(seconds: 10), onTimeout: () => null); if (device != null) { Logger.info('找到系统已连接设备'); _deviceInfo.value = _bluetoothService.getConnectedDeviceInfo(); _onDeviceConnected(); return; } // 如果没有找到已连接设备,检查已配对设备 await _checkPairedDevices(); } catch (e) { Logger.error('查找系统连接设备失败: $e'); // 继续查找已配对设备,不立即失败 await _checkPairedDevices(); } } // 检查已配对设备 Future _checkPairedDevices() async { _updateStatus(PairingStatus.scanning, '正在检查已配对设备...'); // 获取已配对设备列表 _pairedDevices.value = _bluetoothService.systemPairedDevices; // 如果有已配对的设备,尝试连接 if (_pairedDevices.isNotEmpty) { Logger.info('找到${_pairedDevices.length}个已配对设备,尝试连接'); // 根据设备名称过滤可能的音频设备 BluetoothDevice deviceToConnect = _findBestAudioDevice(_pairedDevices) ?? _pairedDevices.first; await _connectToDevice(deviceToConnect); } else { // 如果没有已配对设备,开始扫描附近设备 await _scanForDevices(); } } // 在设备列表中查找最可能的音频设备 BluetoothDevice? _findBestAudioDevice(List devices) { if (devices.isEmpty) return null; for (var device in devices) { String name = device.platformName.toLowerCase(); if (name.contains('headphone') || name.contains('earphone') || name.contains('earbuds') || name.contains('headset') || name.contains('speaker') || name.contains('audio') || name.contains('耳机') || name.contains('音箱')) { return device; } } return null; } // 扫描附近的蓝牙设备 Future _scanForDevices() async { _updateStatus(PairingStatus.scanning, '正在扫描附近设备...'); _scanRetryCount = 0; try { // 确保先停止之前的扫描 await _bluetoothService.stopScan(); // 开始扫描 List results = await _bluetoothService.startScan( timeout: const Duration(seconds: 12) ); _scannedDevices.value = results; if (results.isEmpty) { _handleNoDevicesFound(); return; } // 过滤可能的音频设备 List audioDevices = results.where((result) { String name = result.device.platformName.toLowerCase(); return name.contains('headphone') || name.contains('earphone') || name.contains('earbuds') || name.contains('headset') || name.contains('speaker') || name.contains('audio') || name.contains('耳机') || name.contains('音箱'); }).toList(); // 按信号强度排序 if (audioDevices.isNotEmpty) { audioDevices.sort((a, b) => b.rssi.compareTo(a.rssi)); Logger.info('找到${audioDevices.length}个可能的音频设备'); // 连接信号最强的音频设备 await _connectToDevice(audioDevices.first.device); } else if (results.isNotEmpty) { // 如果没有明确的音频设备但有其他设备,按信号排序 results.sort((a, b) => b.rssi.compareTo(a.rssi)); Logger.info('未找到明确的音频设备,尝试连接信号最强的设备'); await _connectToDevice(results.first.device); } } catch (e) { Logger.error('扫描设备失败: $e'); _updateStatus(PairingStatus.failed, '扫描失败'); _setError('扫描设备失败', '请确保蓝牙已开启并重试'); } } // 处理未找到设备的情况 void _handleNoDevicesFound() { if (_scanRetryCount < MAX_RETRY_COUNT) { _scanRetryCount++; Logger.info('未找到设备,自动重试 (${_scanRetryCount}/${MAX_RETRY_COUNT})'); _updateStatus(PairingStatus.scanning, '未找到设备,重试中...'); // 延迟2秒后重试 Future.delayed(const Duration(seconds: 2), _scanForDevices); } else { _updateStatus(PairingStatus.failed, '未找到设备'); _setError('未找到任何蓝牙设备', '请确保设备已开启并在附近,或点击刷新重试'); } } // 连接到指定设备 Future _connectToDevice(BluetoothDevice device) async { _updateStatus(PairingStatus.connecting, '正在连接到 "${device.platformName}"...'); _connectRetryCount = 0; try { // 停止当前扫描 await _bluetoothService.stopScan(); bool connected = await _bluetoothService.connectToDevice(device); if (connected) { Logger.info('成功连接到设备: ${device.platformName}'); _deviceInfo.value = _bluetoothService.getConnectedDeviceInfo(); _onDeviceConnected(); } else { _handleConnectionFailed(device); } } catch (e) { Logger.error('连接设备失败: $e'); _handleConnectionFailed(device); } } // 处理连接失败 void _handleConnectionFailed(BluetoothDevice device) { // 检查设备类型 if (_bluetoothService.deviceType == DeviceType.classicAudio) { // 经典蓝牙音频设备需要在系统设置中配对 _updateStatus(PairingStatus.needsSystemPairing, '需要系统配对'); _setError('这是音频设备,需要在系统设置中配对', '请前往系统蓝牙设置完成配对'); } else if (_connectRetryCount < MAX_RETRY_COUNT) { // 自动重试连接 _connectRetryCount++; Logger.info('连接失败,自动重试 (${_connectRetryCount}/${MAX_RETRY_COUNT})'); _updateStatus(PairingStatus.connecting, '连接失败,重试中...'); // 延迟2秒后重试 Future.delayed(const Duration(seconds: 2), () => _connectToDevice(device)); } else { // 超过重试次数 _updateStatus(PairingStatus.failed, '连接失败'); _setError('连接设备失败', '请确保设备已开启且处于配对模式,或点击刷新重试'); } } // 设备连接成功 void _onDeviceConnected() { _updateStatus(PairingStatus.found, '设备连接成功'); // 延迟跳转到主页 Timer(const Duration(seconds: 1), () { Get.offAllNamed(Routes.home, arguments: _deviceInfo.value); }); } // 更新状态(内部方法) void _updateStatus(PairingStatus status, String description) { _pairingStatus.value = status; _statusDescription.value = description; // 根据状态自动控制动画 if ([PairingStatus.initial, PairingStatus.requesting, PairingStatus.scanning, PairingStatus.connecting].contains(status)) { _startAnimation(); } else { _stopAnimation(); } } // 设置错误信息 void _setError(String message, String solution) { _errorMessage.value = '$message\n$solution'; } // 动画控制 void _startAnimation() { _stopAnimation(); // 确保先停止已有动画 int count = 0; _animationTimer = Timer.periodic(const Duration(milliseconds: 500), (timer) { count = (count + 1) % 4; _animationDots.value = '.' * count; }); } void _stopAnimation() { _animationTimer?.cancel(); _animationTimer = null; _animationDots.value = ''; } // 公开方法 // 刷新搜索 void refreshSearch() { // 停止当前动画和扫描 _stopAnimation(); _bluetoothService.stopScan(); // 重置重试计数 _scanRetryCount = 0; _connectRetryCount = 0; // 重新开始流程 _initializeProcess(); } // 打开应用设置 void goToAppSettings() async { try { await openAppSettings(); } catch (e) { Logger.error('打开应用设置失败: $e'); Get.snackbar( '提示', '无法自动打开设置,请手动前往系统设置授予权限', snackPosition: SnackPosition.TOP, backgroundColor: Colors.red[100], colorText: Colors.red[800], duration: const Duration(seconds: 3), ); } } // 跳转到系统蓝牙设置 void openSystemBluetoothSettings() async { try { if (GetPlatform.isAndroid) { await openAppSettings(); } else { // iOS不能直接打开蓝牙设置 Get.snackbar( '提示', '请手动打开系统设置并配对您的蓝牙设备', snackPosition: SnackPosition.TOP, backgroundColor: Colors.blue[100], colorText: Colors.blue[800], duration: const Duration(seconds: 3), ); } } catch (e) { Logger.error('打开系统设置失败: $e'); Get.snackbar( '提示', '无法自动打开设置,请手动前往系统蓝牙设置', snackPosition: SnackPosition.TOP, backgroundColor: Colors.red[100], colorText: Colors.red[800], duration: const Duration(seconds: 3), ); } } // 跳过连接 void skipConnecting() { // 停止扫描和动画 _bluetoothService.stopScan(); _stopAnimation(); // 直接跳转到主页 Get.offAllNamed(Routes.home); } // 手动连接特定设备 void connectToDevice(BluetoothDevice device) { _connectToDevice(device); } }