|
|
|
@ -10,13 +10,16 @@ import 'package:classic_bluetooth/classic_bluetooth.dart' show BluetoothDevice; |
|
|
|
import '../../../data/services/ble_manager.dart'; |
|
|
|
import 'package:agent_service/agent_service.dart'; |
|
|
|
import 'package:ble_service/ble_service.dart'; |
|
|
|
|
|
|
|
/// 配对控制器,负责检查蓝牙权限、状态,并处理配对流程 |
|
|
|
class PairingController extends GetxController { |
|
|
|
static PairingController get to => Get.find(); |
|
|
|
|
|
|
|
//是否需要连接耳机 |
|
|
|
final isneedearphone = false; |
|
|
|
// 状态标志 |
|
|
|
final isLoading = false.obs; |
|
|
|
|
|
|
|
|
|
|
|
// 权限是否已授予 |
|
|
|
final _hasPermissions = false.obs; |
|
|
|
bool get hasPermissions => _hasPermissions.value; |
|
|
|
@ -25,22 +28,22 @@ class PairingController extends GetxController { |
|
|
|
final _bluetoothState = 'unknown'.obs; |
|
|
|
String get bluetoothState => _bluetoothState.value; |
|
|
|
bool get isBluetoothOn => _bluetoothState.value == 'on'; |
|
|
|
|
|
|
|
|
|
|
|
// 状态描述(用于UI显示) |
|
|
|
final statusDescription = 'initializing'.tr.obs; |
|
|
|
|
|
|
|
// 是否正在跳转到主页 |
|
|
|
bool _isNavigatingToHome = false; |
|
|
|
|
|
|
|
|
|
|
|
// 是否正在执行Companion关联流程 |
|
|
|
bool _isAssociating = false; |
|
|
|
|
|
|
|
// 当前连接设备信息 |
|
|
|
BluetoothDevice? get currentDevice => _bluetoothService.currentDevice; |
|
|
|
|
|
|
|
|
|
|
|
// 是否已连接设备 |
|
|
|
bool get isDeviceConnected => currentDevice != null; |
|
|
|
|
|
|
|
|
|
|
|
// 是否已完成Companion关联 |
|
|
|
final _companionAssociated = false.obs; |
|
|
|
bool get isCompanionAssociated => _companionAssociated.value; |
|
|
|
@ -48,10 +51,10 @@ class PairingController extends GetxController { |
|
|
|
// 服务状态监听 |
|
|
|
Worker? _bluetoothStateWorker; |
|
|
|
Worker? _deviceWorker; |
|
|
|
|
|
|
|
|
|
|
|
// 蓝牙服务 |
|
|
|
final _bluetoothService = Get.find<BluetoothManager>(); |
|
|
|
|
|
|
|
|
|
|
|
// BLE服务 |
|
|
|
final _bleService = BleService(); |
|
|
|
|
|
|
|
@ -96,7 +99,7 @@ class PairingController extends GetxController { |
|
|
|
// 刷新已连接设备 |
|
|
|
statusDescription.value = 'searchingDevice'.tr; |
|
|
|
await refreshConnectedDevices(); |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已存在Companion设备关联,但不要重复调用关联流程 |
|
|
|
await _checkExistingCompanionAssociation(); |
|
|
|
} catch (e) { |
|
|
|
@ -107,16 +110,16 @@ class PairingController extends GetxController { |
|
|
|
_updateStatusDescription(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 检查是否已存在Companion设备关联 |
|
|
|
Future<void> _checkExistingCompanionAssociation() async { |
|
|
|
// 只在Android平台执行 |
|
|
|
if (!Platform.isAndroid) return; |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
final isSupported = await _bleService.isCompanionSupported(); |
|
|
|
if (!isSupported) return; |
|
|
|
|
|
|
|
|
|
|
|
final pairedMac = await _bleService.getPairedMacAddress(); |
|
|
|
if (pairedMac != null) { |
|
|
|
Logger.info('发现已关联的Companion设备: $pairedMac'); |
|
|
|
@ -156,18 +159,18 @@ class PairingController extends GetxController { |
|
|
|
Logger.warning('权限 ${permission.toString()} 未被授予: $status'); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
_hasPermissions.value = allGranted; |
|
|
|
return allGranted; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 辅助方法获取Android SDK版本 |
|
|
|
Future<int> _getAndroidSdkVersion() async { |
|
|
|
if (Platform.isAndroid) { |
|
|
|
// 这里需要原生代码支持来获取确切的SDK版本, |
|
|
|
// 或者使用 device_info_plus 插件 |
|
|
|
// 暂时返回一个较高值以触发新权限请求 |
|
|
|
return 31; // 假设运行在需要新权限的设备上 |
|
|
|
// 这里需要原生代码支持来获取确切的SDK版本, |
|
|
|
// 或者使用 device_info_plus 插件 |
|
|
|
// 暂时返回一个较高值以触发新权限请求 |
|
|
|
return 31; // 假设运行在需要新权限的设备上 |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
@ -175,38 +178,40 @@ class PairingController extends GetxController { |
|
|
|
/// 设置服务状态监听 |
|
|
|
void _setupServiceStateListeners() { |
|
|
|
// 监听蓝牙服务的蓝牙状态变化 |
|
|
|
_bluetoothStateWorker = ever(_bluetoothService.bluetoothState.obs, (String state) { |
|
|
|
_bluetoothStateWorker = |
|
|
|
ever(_bluetoothService.bluetoothState.obs, (String state) { |
|
|
|
_bluetoothState.value = state; |
|
|
|
_updateStatusDescription(); |
|
|
|
|
|
|
|
|
|
|
|
// 如果蓝牙关闭,可能需要更新UI或提示用户 |
|
|
|
if (state == 'off') { |
|
|
|
Logger.info('蓝牙已关闭'); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 监听当前设备变化 - 使用公开的currentDeviceRx字段 |
|
|
|
_deviceWorker = ever(_bluetoothService.currentDeviceRx, (BluetoothDevice? device) { |
|
|
|
_deviceWorker = |
|
|
|
ever(_bluetoothService.currentDeviceRx, (BluetoothDevice? device) { |
|
|
|
if (device != null && !_isNavigatingToHome) { |
|
|
|
Logger.info('配对页面发现设备已连接: ${device.name}'); |
|
|
|
|
|
|
|
// 当经典蓝牙设备连接成功,尝试进行Companion关联 |
|
|
|
_handleDeviceConnected(); |
|
|
|
} |
|
|
|
_updateStatusDescription(); |
|
|
|
}); |
|
|
|
if (!isneedearphone) { |
|
|
|
//不需要耳机 |
|
|
|
_handleDeviceConnected(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 处理设备连接成功事件 |
|
|
|
Future<void> _handleDeviceConnected() async { |
|
|
|
if (!isDeviceConnected || _isNavigatingToHome) return; |
|
|
|
|
|
|
|
if ((!isDeviceConnected && isneedearphone) || _isNavigatingToHome) return; |
|
|
|
// 如果已经完成关联,直接跳转 |
|
|
|
if (_companionAssociated.value) { |
|
|
|
if (isneedearphone && _companionAssociated.value) { |
|
|
|
_autoNavigateToHome(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 启动关联流程 |
|
|
|
_startCompanionAssociation(); |
|
|
|
} |
|
|
|
@ -217,7 +222,7 @@ class PairingController extends GetxController { |
|
|
|
statusDescription.value = 'permissionDenied'.tr; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (bluetoothState == 'off') { |
|
|
|
statusDescription.value = 'bluetoothTurnedOff'.tr; |
|
|
|
return; |
|
|
|
@ -225,11 +230,14 @@ class PairingController extends GetxController { |
|
|
|
|
|
|
|
if (isDeviceConnected) { |
|
|
|
if (Platform.isAndroid && !isCompanionAssociated && _isAssociating) { |
|
|
|
statusDescription.value = '${'associatingDevice'.tr} ${currentDevice!.name}'; |
|
|
|
statusDescription.value = |
|
|
|
'${'associatingDevice'.tr} ${currentDevice!.name}'; |
|
|
|
} else if (isCompanionAssociated) { |
|
|
|
statusDescription.value = '${'connectedDevice'.tr} ${currentDevice!.name}'; |
|
|
|
statusDescription.value = |
|
|
|
'${'connectedDevice'.tr} ${currentDevice!.name}'; |
|
|
|
} else { |
|
|
|
statusDescription.value = '${'connectedDevice'.tr} ${currentDevice!.name}'; |
|
|
|
statusDescription.value = |
|
|
|
'${'connectedDevice'.tr} ${currentDevice!.name}'; |
|
|
|
} |
|
|
|
return; |
|
|
|
} |
|
|
|
@ -248,18 +256,18 @@ class PairingController extends GetxController { |
|
|
|
statusDescription.value = 'permissionDenied'.tr; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
isLoading.value = true; |
|
|
|
statusDescription.value = 'searchingDevice'.tr; |
|
|
|
|
|
|
|
|
|
|
|
// 使用蓝牙服务刷新连接 |
|
|
|
await _bluetoothService.refreshDeviceConnection(); |
|
|
|
|
|
|
|
|
|
|
|
// 检查连接状态 |
|
|
|
if (isDeviceConnected) { |
|
|
|
Logger.info('刷新发现设备已连接: ${currentDevice!.name}'); |
|
|
|
|
|
|
|
|
|
|
|
// 当发现设备已连接,统一由_handleDeviceConnected处理 |
|
|
|
_handleDeviceConnected(); |
|
|
|
} else { |
|
|
|
@ -273,18 +281,20 @@ class PairingController extends GetxController { |
|
|
|
_updateStatusDescription(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 启动Companion设备关联流程 |
|
|
|
Future<void> _startCompanionAssociation() async { |
|
|
|
// 如果不是Android平台,已经跳转到首页,已经完成关联或正在进行关联,直接返回 |
|
|
|
if (!Platform.isAndroid || _isNavigatingToHome || _companionAssociated.value || _isAssociating) { |
|
|
|
if (!Platform.isAndroid || |
|
|
|
_isNavigatingToHome || |
|
|
|
_companionAssociated.value || |
|
|
|
_isAssociating) { |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 设置关联状态标志 |
|
|
|
_isAssociating = true; |
|
|
|
_updateStatusDescription(); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
// 检查是否支持Companion Device功能 |
|
|
|
final isSupported = await _bleService.isCompanionSupported(); |
|
|
|
@ -294,7 +304,6 @@ class PairingController extends GetxController { |
|
|
|
_autoNavigateToHome(); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
// 检查是否已有配对的MAC地址 |
|
|
|
final pairedMac = await _bleService.getPairedMacAddress(); |
|
|
|
if (pairedMac != null) { |
|
|
|
@ -303,34 +312,32 @@ class PairingController extends GetxController { |
|
|
|
Logger.info('已关联的Companion设备与当前连接的设备一致'); |
|
|
|
_companionAssociated.value = true; |
|
|
|
await _bleService.registerBackgroundScan(); |
|
|
|
_autoNavigateToHome(); |
|
|
|
return; |
|
|
|
// _autoNavigateToHome(); |
|
|
|
// return; |
|
|
|
} else { |
|
|
|
// 不一致,清除旧关联 |
|
|
|
Logger.info('已关联的Companion设备与当前连接的设备不一致,清除旧关联'); |
|
|
|
await _bleService.clearAssociations(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 开始关联流程 |
|
|
|
if (currentDevice != null) { |
|
|
|
Logger.info('开始Companion设备关联流程, 设备MAC: ${currentDevice!.address}'); |
|
|
|
|
|
|
|
final success = await _bleService.startDeviceAssociation( |
|
|
|
|
|
|
|
var success = await _bleService.startDeviceAssociation( |
|
|
|
deviceNamePattern: currentDevice!.name, |
|
|
|
macAddress: currentDevice!.address, |
|
|
|
); |
|
|
|
|
|
|
|
if (success) { |
|
|
|
Logger.info('Companion设备关联成功'); |
|
|
|
_companionAssociated.value = true; |
|
|
|
|
|
|
|
|
|
|
|
// 注册后台扫描,确保应用被杀死后仍能被唤醒 |
|
|
|
await _bleService.registerBackgroundScan(macAddress: currentDevice!.address); |
|
|
|
|
|
|
|
await _bleService.registerBackgroundScan( |
|
|
|
macAddress: currentDevice!.address); |
|
|
|
// 启动BLE后台服务(可选) |
|
|
|
await _startAgentService(); |
|
|
|
|
|
|
|
|
|
|
|
// 关联和后台扫描都成功后,再跳转 |
|
|
|
_autoNavigateToHome(); |
|
|
|
} else { |
|
|
|
@ -338,6 +345,12 @@ class PairingController extends GetxController { |
|
|
|
// 关联失败,但仍然可以跳转到主页(用户体验考虑) |
|
|
|
_autoNavigateToHome(); |
|
|
|
} |
|
|
|
} else if (!isneedearphone) { |
|
|
|
// 启动BLE后台服务(可选) |
|
|
|
await _startAgentService(); |
|
|
|
|
|
|
|
// 关联和后台扫描都成功后,再跳转 |
|
|
|
_autoNavigateToHome(); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
Logger.error('Companion设备关联过程发生错误: $e'); |
|
|
|
@ -353,10 +366,10 @@ class PairingController extends GetxController { |
|
|
|
/// 自动跳转到主页 |
|
|
|
Future<void> _autoNavigateToHome() async { |
|
|
|
if (_isNavigatingToHome) return; |
|
|
|
|
|
|
|
|
|
|
|
// 如果没有连接,不进行跳转 |
|
|
|
if (!isDeviceConnected) return; |
|
|
|
|
|
|
|
|
|
|
|
// 在Android平台上,如果支持Companion且仍在关联中,不跳转 |
|
|
|
if (Platform.isAndroid) { |
|
|
|
final isSupported = await _bleService.isCompanionSupported(); |
|
|
|
@ -365,25 +378,24 @@ class PairingController extends GetxController { |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
_isNavigatingToHome = true; |
|
|
|
|
|
|
|
|
|
|
|
Logger.info('已找到连接的设备 ${currentDevice!.name},自动跳转到主页'); |
|
|
|
|
|
|
|
|
|
|
|
Future.delayed(const Duration(milliseconds: 500), () { |
|
|
|
Get.offAllNamed(Routes.home); |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 启动BLE后台服务 |
|
|
|
Future<void> _startAgentService() async { |
|
|
|
try { |
|
|
|
if (!isDeviceConnected) return; |
|
|
|
|
|
|
|
if (isneedearphone && !isDeviceConnected) return; |
|
|
|
|
|
|
|
// 启动BLE服务,无需传递配置参数,将从.env读取 |
|
|
|
final result = await BleManager.to.startAgentService(); |
|
|
|
|
|
|
|
|
|
|
|
if (result) { |
|
|
|
Logger.info('BLE后台服务启动成功'); |
|
|
|
} else { |
|
|
|
@ -393,12 +405,12 @@ class PairingController extends GetxController { |
|
|
|
Logger.error('启动BLE后台服务发生错误: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 停止BLE后台服务 |
|
|
|
Future<void> _stopAgentService() async { |
|
|
|
try { |
|
|
|
final result = await BleManager.to.stopAgentService(); |
|
|
|
|
|
|
|
|
|
|
|
if (result) { |
|
|
|
Logger.info('BLE后台服务停止成功'); |
|
|
|
} else { |
|
|
|
@ -425,7 +437,7 @@ class PairingController extends GetxController { |
|
|
|
Logger.error('打开设置失败: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// 打开应用设置 |
|
|
|
Future<void> openAppSettings() async { |
|
|
|
await AppSettings.openAppSettings(); |
|
|
|
|