|
|
@ -52,16 +52,18 @@ class PairingController extends GetxController { |
|
|
final _pairedDevices = <BluetoothDevice>[].obs; |
|
|
final _pairedDevices = <BluetoothDevice>[].obs; |
|
|
List<BluetoothDevice> get pairedDevices => _pairedDevices; |
|
|
List<BluetoothDevice> get pairedDevices => _pairedDevices; |
|
|
|
|
|
|
|
|
|
|
|
// 重试计数 |
|
|
|
|
|
int _retryCount = 0; |
|
|
|
|
|
static const int MAX_RETRY_COUNT = 3; |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
void onInit() { |
|
|
void onInit() { |
|
|
super.onInit(); |
|
|
super.onInit(); |
|
|
// 启动搜索动画 |
|
|
// 启动搜索动画 |
|
|
_startSearchingAnimation(); |
|
|
_startSearchingAnimation(); |
|
|
|
|
|
|
|
|
// 延迟初始化蓝牙服务,避免在应用启动时就阻塞主线程 |
|
|
// 初始化蓝牙服务 |
|
|
Future.delayed(const Duration(milliseconds: 800), () { |
|
|
_initBluetoothService(); |
|
|
_initBluetoothService(); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@override |
|
|
@override |
|
|
@ -76,47 +78,72 @@ class PairingController extends GetxController { |
|
|
// 获取蓝牙服务实例 |
|
|
// 获取蓝牙服务实例 |
|
|
if (Get.isRegistered<BluetoothService>()) { |
|
|
if (Get.isRegistered<BluetoothService>()) { |
|
|
_bluetoothService = Get.find<BluetoothService>(); |
|
|
_bluetoothService = Get.find<BluetoothService>(); |
|
|
} else { |
|
|
|
|
|
// 初始化蓝牙服务 |
|
|
|
|
|
_bluetoothService = await Get.put(BluetoothService()).init(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 监听蓝牙状态变化 |
|
|
|
|
|
ever(_bluetoothService.isAvailableObs, (bool available) { |
|
|
|
|
|
_isBluetoothAvailable.value = available; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
ever(_bluetoothService.isOnObs, (bool on) { |
|
|
|
|
|
_isBluetoothOn.value = on; |
|
|
|
|
|
|
|
|
|
|
|
// 如果蓝牙开启,开始查找设备 |
|
|
// 如果蓝牙服务已初始化,直接开始查找设备 |
|
|
if (on) { |
|
|
if (_bluetoothService.isInitialized) { |
|
|
// 延迟开始查找,给权限请求等操作留出时间 |
|
|
_setupBluetoothListeners(); |
|
|
Future.delayed(const Duration(milliseconds: 800), () { |
|
|
|
|
|
_findConnectedDevices(); |
|
|
|
|
|
}); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
_errorMessage.value = '请打开蓝牙以搜索设备'; |
|
|
// 等待蓝牙服务初始化完成 |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
ever(_bluetoothService.isInitializedObs, (bool initialized) { |
|
|
_stopSearchingAnimation(); |
|
|
if (initialized) { |
|
|
|
|
|
_setupBluetoothListeners(); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 如果蓝牙已经开启,直接开始查找 |
|
|
|
|
|
if (_bluetoothService.isOn) { |
|
|
|
|
|
_isBluetoothOn.value = true; |
|
|
|
|
|
// 延迟开始查找 |
|
|
|
|
|
Future.delayed(const Duration(milliseconds: 800), () { |
|
|
|
|
|
_findConnectedDevices(); |
|
|
|
|
|
}); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
_errorMessage.value = '请打开蓝牙以搜索设备'; |
|
|
// 初始化蓝牙服务 |
|
|
|
|
|
_bluetoothService = await Get.put(BluetoothService()).init(); |
|
|
|
|
|
_setupBluetoothListeners(); |
|
|
} |
|
|
} |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
Logger.error('初始化蓝牙服务失败: $e'); |
|
|
Logger.error('初始化蓝牙服务失败: $e'); |
|
|
_errorMessage.value = '初始化蓝牙服务失败'; |
|
|
_errorMessage.value = '初始化蓝牙服务失败'; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_stopSearchingAnimation(); |
|
|
_stopSearchingAnimation(); |
|
|
|
|
|
|
|
|
|
|
|
// 重试初始化 |
|
|
|
|
|
_retryInitialization(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 设置蓝牙监听器 |
|
|
|
|
|
void _setupBluetoothListeners() { |
|
|
|
|
|
// 监听蓝牙状态变化 |
|
|
|
|
|
ever(_bluetoothService.isAvailableObs, (bool available) { |
|
|
|
|
|
_isBluetoothAvailable.value = available; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
ever(_bluetoothService.isOnObs, (bool on) { |
|
|
|
|
|
_isBluetoothOn.value = on; |
|
|
|
|
|
|
|
|
|
|
|
// 如果蓝牙开启,开始查找设备 |
|
|
|
|
|
if (on) { |
|
|
|
|
|
_findConnectedDevices(); |
|
|
|
|
|
} else { |
|
|
|
|
|
_errorMessage.value = '请打开蓝牙以搜索设备'; |
|
|
|
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
|
|
|
_stopSearchingAnimation(); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
// 如果蓝牙已经开启,直接开始查找 |
|
|
|
|
|
if (_bluetoothService.isOn) { |
|
|
|
|
|
_isBluetoothOn.value = true; |
|
|
|
|
|
_findConnectedDevices(); |
|
|
|
|
|
} else { |
|
|
|
|
|
_errorMessage.value = '请打开蓝牙以搜索设备'; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 重试初始化 |
|
|
|
|
|
void _retryInitialization() { |
|
|
|
|
|
if (_retryCount < MAX_RETRY_COUNT) { |
|
|
|
|
|
_retryCount++; |
|
|
|
|
|
Logger.info('重试初始化蓝牙服务 (${_retryCount}/${MAX_RETRY_COUNT})'); |
|
|
|
|
|
|
|
|
|
|
|
Future.delayed(const Duration(seconds: 2), () { |
|
|
|
|
|
_initBluetoothService(); |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -192,12 +219,12 @@ class PairingController extends GetxController { |
|
|
Logger.info('查找系统已连接的设备'); |
|
|
Logger.info('查找系统已连接的设备'); |
|
|
BluetoothDevice? device = await _bluetoothService.findConnectedSystemDevice() |
|
|
BluetoothDevice? device = await _bluetoothService.findConnectedSystemDevice() |
|
|
.timeout(const Duration(seconds: 5), onTimeout: () { |
|
|
.timeout(const Duration(seconds: 5), onTimeout: () { |
|
|
Logger.info('查找系统已连接设备超时'); |
|
|
Logger.error('获取已连接设备超时'); |
|
|
return null; |
|
|
return null; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
if (device != null) { |
|
|
if (device != null) { |
|
|
Logger.info('找到系统已连接设备: ${device.platformName}'); |
|
|
Logger.info('找到系统已连接设备'); |
|
|
_deviceInfo.value = _bluetoothService.getConnectedDeviceInfo(); |
|
|
_deviceInfo.value = _bluetoothService.getConnectedDeviceInfo(); |
|
|
_onDeviceFound(); |
|
|
_onDeviceFound(); |
|
|
return; |
|
|
return; |
|
|
@ -209,7 +236,7 @@ class PairingController extends GetxController { |
|
|
|
|
|
|
|
|
// 如果有已配对的设备,直接尝试连接第一个 |
|
|
// 如果有已配对的设备,直接尝试连接第一个 |
|
|
if (_pairedDevices.isNotEmpty) { |
|
|
if (_pairedDevices.isNotEmpty) { |
|
|
Logger.info('找到${_pairedDevices.length}个已配对设备,尝试连接第一个'); |
|
|
Logger.info('找到已配对设备,尝试连接'); |
|
|
|
|
|
|
|
|
// 尝试连接第一个配对设备 |
|
|
// 尝试连接第一个配对设备 |
|
|
await tryConnectDevice(_pairedDevices.first); |
|
|
await tryConnectDevice(_pairedDevices.first); |
|
|
@ -219,9 +246,24 @@ class PairingController extends GetxController { |
|
|
} |
|
|
} |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
Logger.error('查找设备失败: $e'); |
|
|
Logger.error('查找设备失败: $e'); |
|
|
_errorMessage.value = '查找设备失败: ${e.toString()}'; |
|
|
_errorMessage.value = '查找设备失败'; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_stopSearchingAnimation(); |
|
|
_stopSearchingAnimation(); |
|
|
|
|
|
|
|
|
|
|
|
// 重试查找设备 |
|
|
|
|
|
_retryFindDevices(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 重试查找设备 |
|
|
|
|
|
void _retryFindDevices() { |
|
|
|
|
|
if (_retryCount < MAX_RETRY_COUNT) { |
|
|
|
|
|
_retryCount++; |
|
|
|
|
|
Logger.info('重试查找设备 (${_retryCount}/${MAX_RETRY_COUNT})'); |
|
|
|
|
|
|
|
|
|
|
|
Future.delayed(const Duration(seconds: 2), () { |
|
|
|
|
|
_findConnectedDevices(); |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -255,14 +297,14 @@ class PairingController extends GetxController { |
|
|
if (audioDevices.isNotEmpty) { |
|
|
if (audioDevices.isNotEmpty) { |
|
|
// 按信号强度排序 |
|
|
// 按信号强度排序 |
|
|
audioDevices.sort((a, b) => b.rssi.compareTo(a.rssi)); |
|
|
audioDevices.sort((a, b) => b.rssi.compareTo(a.rssi)); |
|
|
Logger.info('找到可能的音频设备: ${audioDevices.first.device.platformName}'); |
|
|
Logger.info('找到可能的音频设备'); |
|
|
|
|
|
|
|
|
// 直接尝试连接信号最强的音频设备 |
|
|
// 直接尝试连接信号最强的音频设备 |
|
|
await tryConnectDevice(audioDevices.first.device); |
|
|
await tryConnectDevice(audioDevices.first.device); |
|
|
} else if (results.isNotEmpty) { |
|
|
} else if (results.isNotEmpty) { |
|
|
// 如果没有明确的音频设备但有其他设备,尝试连接信号最强的设备 |
|
|
// 如果没有明确的音频设备但有其他设备,尝试连接信号最强的设备 |
|
|
results.sort((a, b) => b.rssi.compareTo(a.rssi)); |
|
|
results.sort((a, b) => b.rssi.compareTo(a.rssi)); |
|
|
Logger.info('未找到明确的音频设备,尝试连接信号最强的设备: ${results.first.device.platformName}'); |
|
|
Logger.info('未找到明确的音频设备,尝试连接信号最强的设备'); |
|
|
|
|
|
|
|
|
await tryConnectDevice(results.first.device); |
|
|
await tryConnectDevice(results.first.device); |
|
|
} else { |
|
|
} else { |
|
|
@ -270,19 +312,37 @@ class PairingController extends GetxController { |
|
|
_errorMessage.value = '未找到蓝牙设备,请确保设备已开启并在附近'; |
|
|
_errorMessage.value = '未找到蓝牙设备,请确保设备已开启并在附近'; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_stopSearchingAnimation(); |
|
|
_stopSearchingAnimation(); |
|
|
|
|
|
|
|
|
|
|
|
// 重试扫描 |
|
|
|
|
|
_retryScan(); |
|
|
} |
|
|
} |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
Logger.error('扫描设备失败: $e'); |
|
|
Logger.error('扫描设备失败: $e'); |
|
|
_errorMessage.value = '扫描设备失败: ${e.toString()}'; |
|
|
_errorMessage.value = '扫描设备失败'; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_stopSearchingAnimation(); |
|
|
_stopSearchingAnimation(); |
|
|
|
|
|
|
|
|
|
|
|
// 重试扫描 |
|
|
|
|
|
_retryScan(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 重试扫描 |
|
|
|
|
|
void _retryScan() { |
|
|
|
|
|
if (_retryCount < MAX_RETRY_COUNT) { |
|
|
|
|
|
_retryCount++; |
|
|
|
|
|
Logger.info('重试扫描设备 (${_retryCount}/${MAX_RETRY_COUNT})'); |
|
|
|
|
|
|
|
|
|
|
|
Future.delayed(const Duration(seconds: 2), () { |
|
|
|
|
|
_scanForDevices(); |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 尝试连接特定设备 |
|
|
// 尝试连接特定设备 |
|
|
Future<void> tryConnectDevice(BluetoothDevice device) async { |
|
|
Future<void> tryConnectDevice(BluetoothDevice device) async { |
|
|
try { |
|
|
try { |
|
|
Logger.info('尝试连接设备: ${device.platformName}'); |
|
|
Logger.info('尝试连接设备'); |
|
|
_searchStatus.value = SearchStatus.searching; |
|
|
_searchStatus.value = SearchStatus.searching; |
|
|
_startSearchingAnimation(); |
|
|
_startSearchingAnimation(); |
|
|
_errorMessage.value = ''; |
|
|
_errorMessage.value = ''; |
|
|
@ -290,11 +350,11 @@ class PairingController extends GetxController { |
|
|
bool connected = await _bluetoothService.connectToDevice(device); |
|
|
bool connected = await _bluetoothService.connectToDevice(device); |
|
|
|
|
|
|
|
|
if (connected) { |
|
|
if (connected) { |
|
|
Logger.info('连接设备成功: ${device.platformName}'); |
|
|
Logger.info('连接设备成功'); |
|
|
_deviceInfo.value = _bluetoothService.getConnectedDeviceInfo(); |
|
|
_deviceInfo.value = _bluetoothService.getConnectedDeviceInfo(); |
|
|
_onDeviceFound(); |
|
|
_onDeviceFound(); |
|
|
} else { |
|
|
} else { |
|
|
Logger.error('连接设备失败: ${device.platformName}'); |
|
|
Logger.error('连接设备失败'); |
|
|
|
|
|
|
|
|
// 检查设备类型 |
|
|
// 检查设备类型 |
|
|
if (_bluetoothService.deviceType == DeviceType.classicAudio) { |
|
|
if (_bluetoothService.deviceType == DeviceType.classicAudio) { |
|
|
@ -307,12 +367,30 @@ class PairingController extends GetxController { |
|
|
_errorMessage.value = '连接设备失败,请重试或检查设备状态'; |
|
|
_errorMessage.value = '连接设备失败,请重试或检查设备状态'; |
|
|
} |
|
|
} |
|
|
_stopSearchingAnimation(); |
|
|
_stopSearchingAnimation(); |
|
|
|
|
|
|
|
|
|
|
|
// 重试连接 |
|
|
|
|
|
_retryConnect(device); |
|
|
} |
|
|
} |
|
|
} catch (e) { |
|
|
} catch (e) { |
|
|
Logger.error('连接设备失败: $e'); |
|
|
Logger.error('连接设备失败: $e'); |
|
|
_errorMessage.value = '连接设备失败: ${e.toString()}'; |
|
|
_errorMessage.value = '连接设备失败'; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_searchStatus.value = SearchStatus.failed; |
|
|
_stopSearchingAnimation(); |
|
|
_stopSearchingAnimation(); |
|
|
|
|
|
|
|
|
|
|
|
// 重试连接 |
|
|
|
|
|
_retryConnect(device); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 重试连接 |
|
|
|
|
|
void _retryConnect(BluetoothDevice device) { |
|
|
|
|
|
if (_retryCount < MAX_RETRY_COUNT) { |
|
|
|
|
|
_retryCount++; |
|
|
|
|
|
Logger.info('重试连接设备 (${_retryCount}/${MAX_RETRY_COUNT})'); |
|
|
|
|
|
|
|
|
|
|
|
Future.delayed(const Duration(seconds: 2), () { |
|
|
|
|
|
tryConnectDevice(device); |
|
|
|
|
|
}); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -333,6 +411,9 @@ class PairingController extends GetxController { |
|
|
// 停止当前扫描(如果有) |
|
|
// 停止当前扫描(如果有) |
|
|
_bluetoothService.stopScan(); |
|
|
_bluetoothService.stopScan(); |
|
|
|
|
|
|
|
|
|
|
|
// 重置重试计数 |
|
|
|
|
|
_retryCount = 0; |
|
|
|
|
|
|
|
|
// 更新UI状态 |
|
|
// 更新UI状态 |
|
|
_startSearchingAnimation(); |
|
|
_startSearchingAnimation(); |
|
|
_searchStatus.value = SearchStatus.searching; |
|
|
_searchStatus.value = SearchStatus.searching; |
|
|
|