You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
439 lines
14 KiB
439 lines
14 KiB
import 'package:app_settings/app_settings.dart';
|
|
import 'package:get/get.dart';
|
|
import 'dart:async';
|
|
import 'package:permission_handler/permission_handler.dart';
|
|
import '../../../routes/app_routes.dart';
|
|
import '../../../core/utils/logger.dart';
|
|
import 'dart:io';
|
|
import '../../../data/services/bluetooth_manager.dart';
|
|
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 isLoading = false.obs;
|
|
|
|
// 权限是否已授予
|
|
final _hasPermissions = false.obs;
|
|
bool get hasPermissions => _hasPermissions.value;
|
|
|
|
// 蓝牙状态
|
|
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;
|
|
|
|
// 服务状态监听
|
|
Worker? _bluetoothStateWorker;
|
|
Worker? _deviceWorker;
|
|
|
|
// 蓝牙服务
|
|
final _bluetoothService = Get.find<BluetoothManager>();
|
|
|
|
// BLE服务
|
|
final _bleService = BleService();
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
_initialize();
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_bluetoothStateWorker?.dispose();
|
|
_deviceWorker?.dispose();
|
|
super.onClose();
|
|
}
|
|
|
|
/// 初始化流程
|
|
Future<void> _initialize() async {
|
|
try {
|
|
isLoading.value = true;
|
|
statusDescription.value = 'checkingPermissions'.tr;
|
|
|
|
// 检查并请求权限
|
|
if (!await _checkAndRequestPermissions()) {
|
|
statusDescription.value = 'permissionDenied'.tr;
|
|
return;
|
|
}
|
|
|
|
// 设置服务状态监听
|
|
_setupServiceStateListeners();
|
|
|
|
// 检查蓝牙状态
|
|
statusDescription.value = 'checkingBluetoothStatus'.tr;
|
|
final isEnabled = await _bluetoothService.isBluetoothEnabled();
|
|
_bluetoothState.value = isEnabled ? 'on' : 'off';
|
|
|
|
if (!isEnabled) {
|
|
statusDescription.value = 'bluetoothTurnedOff'.tr;
|
|
return;
|
|
}
|
|
|
|
// 刷新已连接设备
|
|
statusDescription.value = 'searchingDevice'.tr;
|
|
await refreshConnectedDevices();
|
|
|
|
// 检查是否已存在Companion设备关联,但不要重复调用关联流程
|
|
await _checkExistingCompanionAssociation();
|
|
} catch (e) {
|
|
Logger.error('初始化配对控制器失败: $e');
|
|
statusDescription.value = 'initializationFailure'.tr;
|
|
} finally {
|
|
isLoading.value = false;
|
|
_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');
|
|
_companionAssociated.value = true;
|
|
await _bleService.registerBackgroundScan();
|
|
}
|
|
} catch (e) {
|
|
Logger.error('检查现有Companion关联失败: $e');
|
|
}
|
|
}
|
|
|
|
/// 检查并请求必要的蓝牙权限
|
|
Future<bool> _checkAndRequestPermissions() async {
|
|
Map<Permission, PermissionStatus> statuses;
|
|
List<Permission> permissionsToRequest = [];
|
|
|
|
if (Platform.isAndroid) {
|
|
// Android 12+ (SDK 31+) 需要 SCAN 和 CONNECT
|
|
// Android 6+ (SDK 23+) 需要 LOCATION
|
|
permissionsToRequest.add(Permission.locationWhenInUse); // 基本定位权限
|
|
permissionsToRequest.add(Permission.microphone);
|
|
// Android 12及以上版本才需要请求蓝牙扫描和连接权限
|
|
if (await _getAndroidSdkVersion() >= 31) {
|
|
permissionsToRequest.add(Permission.bluetoothScan);
|
|
permissionsToRequest.add(Permission.bluetoothConnect);
|
|
}
|
|
} else if (Platform.isIOS) {
|
|
permissionsToRequest.add(Permission.bluetooth);
|
|
}
|
|
|
|
statuses = await permissionsToRequest.request();
|
|
|
|
bool allGranted = true;
|
|
statuses.forEach((permission, status) {
|
|
if (!status.isGranted) {
|
|
allGranted = false;
|
|
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; // 假设运行在需要新权限的设备上
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/// 设置服务状态监听
|
|
void _setupServiceStateListeners() {
|
|
// 监听蓝牙服务的蓝牙状态变化
|
|
_bluetoothStateWorker = ever(_bluetoothService.bluetoothState.obs, (String state) {
|
|
_bluetoothState.value = state;
|
|
_updateStatusDescription();
|
|
|
|
// 如果蓝牙关闭,可能需要更新UI或提示用户
|
|
if (state == 'off') {
|
|
Logger.info('蓝牙已关闭');
|
|
}
|
|
});
|
|
|
|
// 监听当前设备变化 - 使用公开的currentDeviceRx字段
|
|
_deviceWorker = ever(_bluetoothService.currentDeviceRx, (BluetoothDevice? device) {
|
|
if (device != null && !_isNavigatingToHome) {
|
|
Logger.info('配对页面发现设备已连接: ${device.name}');
|
|
|
|
// 当经典蓝牙设备连接成功,尝试进行Companion关联
|
|
_handleDeviceConnected();
|
|
}
|
|
_updateStatusDescription();
|
|
});
|
|
}
|
|
|
|
/// 处理设备连接成功事件
|
|
Future<void> _handleDeviceConnected() async {
|
|
if (!isDeviceConnected || _isNavigatingToHome) return;
|
|
|
|
// 如果已经完成关联,直接跳转
|
|
if (_companionAssociated.value) {
|
|
_autoNavigateToHome();
|
|
return;
|
|
}
|
|
|
|
// 启动关联流程
|
|
_startCompanionAssociation();
|
|
}
|
|
|
|
/// 更新状态描述
|
|
void _updateStatusDescription() {
|
|
if (!hasPermissions) {
|
|
statusDescription.value = 'permissionDenied'.tr;
|
|
return;
|
|
}
|
|
|
|
if (bluetoothState == 'off') {
|
|
statusDescription.value = 'bluetoothTurnedOff'.tr;
|
|
return;
|
|
}
|
|
|
|
if (isDeviceConnected) {
|
|
if (Platform.isAndroid && !isCompanionAssociated && _isAssociating) {
|
|
statusDescription.value = '${'associatingDevice'.tr} ${currentDevice!.name}';
|
|
} else if (isCompanionAssociated) {
|
|
statusDescription.value = '${'connectedDevice'.tr} ${currentDevice!.name}';
|
|
} else {
|
|
statusDescription.value = '${'connectedDevice'.tr} ${currentDevice!.name}';
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (isLoading.value) {
|
|
statusDescription.value = 'searchingDevice'.tr;
|
|
return;
|
|
}
|
|
|
|
statusDescription.value = 'notFound'.tr;
|
|
}
|
|
|
|
/// 刷新已连接设备
|
|
Future<void> refreshConnectedDevices() async {
|
|
if (!hasPermissions) {
|
|
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 {
|
|
Logger.info('刷新未发现已连接设备');
|
|
}
|
|
} catch (e) {
|
|
Logger.error('刷新设备失败: $e');
|
|
statusDescription.value = 'failedRefreshDevice'.tr;
|
|
} finally {
|
|
isLoading.value = false;
|
|
_updateStatusDescription();
|
|
}
|
|
}
|
|
|
|
/// 启动Companion设备关联流程
|
|
Future<void> _startCompanionAssociation() async {
|
|
// 如果不是Android平台,已经跳转到首页,已经完成关联或正在进行关联,直接返回
|
|
if (!Platform.isAndroid || _isNavigatingToHome || _companionAssociated.value || _isAssociating) {
|
|
return;
|
|
}
|
|
|
|
// 设置关联状态标志
|
|
_isAssociating = true;
|
|
_updateStatusDescription();
|
|
|
|
try {
|
|
// 检查是否支持Companion Device功能
|
|
final isSupported = await _bleService.isCompanionSupported();
|
|
if (!isSupported) {
|
|
Logger.info('设备不支持Companion Device功能,跳过关联');
|
|
_companionAssociated.value = true; // 标记为已完成
|
|
_autoNavigateToHome();
|
|
return;
|
|
}
|
|
|
|
// 检查是否已有配对的MAC地址
|
|
final pairedMac = await _bleService.getPairedMacAddress();
|
|
if (pairedMac != null) {
|
|
// 已有关联的设备,检查是否与当前连接的设备一致
|
|
if (currentDevice?.address == pairedMac) {
|
|
Logger.info('已关联的Companion设备与当前连接的设备一致');
|
|
_companionAssociated.value = true;
|
|
await _bleService.registerBackgroundScan();
|
|
_autoNavigateToHome();
|
|
return;
|
|
} else {
|
|
// 不一致,清除旧关联
|
|
Logger.info('已关联的Companion设备与当前连接的设备不一致,清除旧关联');
|
|
await _bleService.clearAssociations();
|
|
}
|
|
}
|
|
|
|
// 开始关联流程
|
|
if (currentDevice != null) {
|
|
Logger.info('开始Companion设备关联流程, 设备MAC: ${currentDevice!.address}');
|
|
|
|
final success = await _bleService.startDeviceAssociation(
|
|
deviceNamePattern: currentDevice!.name,
|
|
macAddress: currentDevice!.address,
|
|
);
|
|
|
|
if (success) {
|
|
Logger.info('Companion设备关联成功');
|
|
_companionAssociated.value = true;
|
|
|
|
// 注册后台扫描,确保应用被杀死后仍能被唤醒
|
|
await _bleService.registerBackgroundScan(macAddress: currentDevice!.address);
|
|
|
|
// 启动BLE后台服务(可选)
|
|
await _startAgentService();
|
|
|
|
// 关联和后台扫描都成功后,再跳转
|
|
_autoNavigateToHome();
|
|
} else {
|
|
Logger.error('Companion设备关联失败');
|
|
// 关联失败,但仍然可以跳转到主页(用户体验考虑)
|
|
_autoNavigateToHome();
|
|
}
|
|
}
|
|
} catch (e) {
|
|
Logger.error('Companion设备关联过程发生错误: $e');
|
|
// 出错时仍可以跳转主页
|
|
_autoNavigateToHome();
|
|
} finally {
|
|
// 无论成功失败,都重置关联状态标志
|
|
_isAssociating = false;
|
|
_updateStatusDescription();
|
|
}
|
|
}
|
|
|
|
/// 自动跳转到主页
|
|
Future<void> _autoNavigateToHome() async {
|
|
if (_isNavigatingToHome) return;
|
|
|
|
// 如果没有连接,不进行跳转
|
|
if (!isDeviceConnected) return;
|
|
|
|
// 在Android平台上,如果支持Companion且仍在关联中,不跳转
|
|
if (Platform.isAndroid) {
|
|
final isSupported = await _bleService.isCompanionSupported();
|
|
if (isSupported && !isCompanionAssociated && _isAssociating) {
|
|
Logger.info('等待Companion设备关联完成后再跳转');
|
|
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;
|
|
|
|
|
|
// 启动BLE服务,无需传递配置参数,将从.env读取
|
|
final result = await BleManager.to.startAgentService();
|
|
|
|
if (result) {
|
|
Logger.info('BLE后台服务启动成功');
|
|
} else {
|
|
Logger.error('BLE后台服务启动失败');
|
|
}
|
|
} catch (e) {
|
|
Logger.error('启动BLE后台服务发生错误: $e');
|
|
}
|
|
}
|
|
|
|
/// 停止BLE后台服务
|
|
Future<void> _stopAgentService() async {
|
|
try {
|
|
final result = await BleManager.to.stopAgentService();
|
|
|
|
if (result) {
|
|
Logger.info('BLE后台服务停止成功');
|
|
} else {
|
|
Logger.error('BLE后台服务停止失败');
|
|
}
|
|
} catch (e) {
|
|
Logger.error('停止BLE后台服务发生错误: $e');
|
|
}
|
|
}
|
|
|
|
/// 打开系统蓝牙设置
|
|
void openBluetoothSettings() {
|
|
try {
|
|
if (!hasPermissions) {
|
|
openAppSettings();
|
|
} else if (Platform.isAndroid && !isBluetoothOn) {
|
|
AppSettings.openAppSettings(type: AppSettingsType.bluetooth);
|
|
} else if (Platform.isIOS) {
|
|
openAppSettings();
|
|
} else {
|
|
AppSettings.openAppSettings(type: AppSettingsType.bluetooth);
|
|
}
|
|
} catch (e) {
|
|
Logger.error('打开设置失败: $e');
|
|
}
|
|
}
|
|
|
|
/// 打开应用设置
|
|
Future<void> openAppSettings() async {
|
|
await AppSettings.openAppSettings();
|
|
}
|
|
|
|
/// 跳过连接
|
|
void skipConnecting() {
|
|
_isNavigatingToHome = true;
|
|
Get.offAllNamed(Routes.home);
|
|
}
|
|
}
|
|
|