import 'dart:io'; import 'dart:async'; import 'package:app_settings/app_settings.dart'; import '/data/models/appconfig_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:get_storage/get_storage.dart'; import '../../../routes/app_routes.dart'; import '../../../core/utils/logger.dart'; import '/data/models/appconfig.dart'; import '/data/models/user_Info.dart'; import '/data/services/network/api.dart'; import '../../../data/services/bluetooth_manager.dart'; import '../../../data/services/ble_manager.dart'; import '../../../core/utils/permission_util.dart'; import '../../../data/services/version_update_service.dart'; /// 配对状态枚举 - 简化版本 enum PairingState { idle, // 空闲/初始状态 checking, // 检查中(蓝牙、权限等) waitingClassic, // 等待经典蓝牙连接 verifying, // 验证设备 binding, //确认绑定设备 manualbinding, //手动绑定设备 associating, // 正在进行BLE设备关联 waitingBle, //等待BLE连接 completed, //配对完成 error, // 错误状态 } /// 错误类型枚举 enum ErrorType { none, bluetoothOff, // 蓝牙关闭 noPermission, // 无权限 noClassicDevice, // 无经典蓝牙设备 deviceNotMatch, // 设备不匹配 deviceBound, // 设备已被绑定 associationFailed, // 关联失败 bleTimeout, // BLE连接超时 authnFailed, // 授权失败 networkError, // 网络错误 } /// 配对控制器 - 基于简化状态机的实现 class PairingController extends GetxController with WidgetsBindingObserver { static const String _tag = 'PairingCtrl'; static PairingController get to => Get.find(); final _storage = GetStorage(); // ========== 状态管理 ========== final _currentState = PairingState.idle.obs; final _errorType = ErrorType.none.obs; final _errorMessage = ''.obs; PairingState get currentState => _currentState.value; ErrorType get errorType => _errorType.value; String get errorMessage => _errorMessage.value; // ========== UI状态 ========== final statusText = ''.obs; final isLoading = false.obs; final showConnectButton = false.obs; final showRetryButton = false.obs; final showBindButton = false.obs; final showRetryChectButton = false.obs; final showAutoCodeInput = false.obs; final showSkipButton = false.obs; // 增加临时跳过绑定按钮状态 final showSkipBindingButton = false.obs; // 新增临时跳过绑定按钮 final connectButtonText = 'connectDevice'.tr.obs; //连接设备 final retryButtonText = 'retry'.tr.obs; final deviceCode = ''.obs; bool isShowSkipButton = false; //是否显示跳过按钮 final availableDevices = [].obs; // 可用设备列表 final selectedDevice = Rx(null); // 用户选中的设备 // ========== 监听器管理 ========== final List _workers = []; Timer? _bleTimeoutTimer; // ========== 依赖服务 ========== late final BluetoothManager _bluetoothManager; late final BleManager _bleManager; // ========== 当前设备信息 ========== BluetoothDevice? _currentClassicDevice; int? _verifiedDevicePid; String? _verifiedDeviceName; String? _verifiedDeviceAddress; TextEditingController codeInputController = TextEditingController(); // Public getter for view access BluetoothDevice? get currentDevice => _currentClassicDevice; //华为设备权限检查标记 bool isHuaweiHasChecked = false; // 缓存的设备品牌信息 final versionService = Get.find(); bool isHuaweiDevice = false; @override void onInit() { super.onInit(); Logger.i(_tag, '配对控制器初始化'); // 注册应用生命周期监听器 Logger.i(_tag, '正在注册应用生命周期监听器'); WidgetsBinding.instance.addObserver(this); Logger.i(_tag, '应用生命周期监听器注册完成'); isHuaweiDevice = _isHuaweiDevice(); // 确保服务已初始化 _bluetoothManager = Get.find(); _bleManager = Get.find(); // 集中设置所有监听器 _setupAllListeners(); if (isHuaweiDevice) { //检查华为设备是否检查权限检查过 isHuaweiHasChecked = _storage.read('isHuaweiHasChecked') ?? false; } // 开始初始状态检查 // 延迟稍长时间,确保BluetoothManager有足够时间获取已连接设备 Future.delayed(const Duration(milliseconds: 300), () { _startInitialCheck(); }); final app_authcode_jump = AppConfig.env('APP_AUTHCODE_JUMP') ?? ""; //print('app_authcode_jump: $app_authcode_jump'); if (app_authcode_jump == "true") { isShowSkipButton = true; // 启用跳过按钮 } } @override void onClose() { Logger.i(_tag, '配对控制器销毁'); // 移除应用生命周期监听器 WidgetsBinding.instance.removeObserver(this); // 清理所有Worker for (var worker in _workers) { worker.dispose(); } _workers.clear(); // 清理定时器 _bleTimeoutTimer?.cancel(); super.onClose(); } /// 应用生命周期状态变化回调 @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); // 使用多种日志级别确保输出 Logger.i(_tag, '=== 应用生命周期状态变化: $state ==='); print('PairingCtrl: 应用生命周期状态变化: $state'); // 直接使用print确保输出 switch (state) { case AppLifecycleState.resumed: // 应用从后台切回前台 Logger.i(_tag, '=== 应用从后台切回前台 ==='); print('PairingCtrl: 应用从后台切回前台'); _onAppResumed(); break; case AppLifecycleState.paused: // 应用切到后台 Logger.i(_tag, '应用切到后台'); print('PairingCtrl: 应用切到后台'); _onAppPaused(); break; case AppLifecycleState.inactive: // 应用处于非活跃状态(如来电话时) Logger.i(_tag, '应用处于非活跃状态'); print('PairingCtrl: 应用处于非活跃状态'); break; case AppLifecycleState.detached: // 应用即将被销毁 Logger.i(_tag, '应用即将被销毁'); print('PairingCtrl: 应用即将被销毁'); break; case AppLifecycleState.hidden: // 应用被隐藏(iOS 13+) Logger.i(_tag, '应用被隐藏'); print('PairingCtrl: 应用被隐藏'); break; } } /// 应用从后台切回前台时的处理逻辑 void _onAppResumed() { Logger.i(_tag, '处理应用从后台切回前台事件'); // 刷新蓝牙连接状态 _bluetoothManager.refreshDeviceConnection(); // 根据当前配对状态执行相应操作 switch (_currentState.value) { case PairingState.waitingClassic: // 如果在等待经典蓝牙连接,重新检查连接状态 Logger.i(_tag, '重新检查经典蓝牙连接状态'); _checkCurrentStatus(); break; case PairingState.waitingBle: // 如果在等待BLE连接,重新检查BLE状态 Logger.i(_tag, '重新检查BLE连接状态'); _checkBleConnectionAfterResume(); break; case PairingState.error: // 如果在错误状态,根据错误类型决定是否自动重试 if (_errorType.value == ErrorType.bluetoothOff) { Logger.i(_tag, '检查蓝牙是否已重新开启'); _checkCurrentStatus(); } break; default: // 其他状态暂不处理 break; } } /// 应用切到后台时的处理逻辑 void _onAppPaused() { Logger.i(_tag, '处理应用切到后台事件'); // 可以在这里暂停一些不必要的操作,如蓝牙扫描等 if (_currentState.value == PairingState.associating) { Logger.i(_tag, '应用切到后台,暂停BLE扫描'); _bleManager.stopScan(); } } /// 应用恢复后检查BLE连接状态 Future _checkBleConnectionAfterResume() async { try { final currentBleState = await _bleManager.getConnectionState(); Logger.i(_tag, '应用恢复后BLE连接状态: $currentBleState'); if (currentBleState == 2) { // BLE已连接,直接完成配对 Logger.i(_tag, '检测到BLE已连接,完成配对'); _bleTimeoutTimer?.cancel(); _transition(PairingState.completed); } else { // BLE未连接,重新启动连接流程 Logger.i(_tag, '重新启动BLE连接流程'); _startBleConnection(); } } catch (e) { Logger.e(_tag, '检查BLE连接状态失败: $e'); } } // ==================== 监听器设置 ==================== /// 集中设置所有监听器 void _setupAllListeners() { // 1. 监听蓝牙开关状态 _setupBluetoothStateListener(); // 2. 监听经典蓝牙连接状态 _setupClassicConnectionListener(); // 3. 监听BLE连接状态 _setupBleConnectionListener(); } /// 监听蓝牙开关状态 void _setupBluetoothStateListener() { _workers.add(ever(_bluetoothManager.bluetoothStateRx, (String state) { Logger.d(_tag, '蓝牙状态变化: $state'); _handleBluetoothStateChange(state); })); } /// 监听经典蓝牙连接状态 void _setupClassicConnectionListener() { _workers .add(ever(_bluetoothManager.currentDeviceRx, (BluetoothDevice? device) { Logger.d(_tag, '经典蓝牙设备变化: ${device?.name}'); _handleClassicDeviceChange(device); })); } /// 监听BLE连接状态 void _setupBleConnectionListener() { _workers.add(ever(_bleManager.connectionStateRx, (int state) { Logger.d(_tag, 'BLE连接状态变化: $state'); _handleBleStateChange(state); })); } // ==================== 状态处理 ==================== /// 处理蓝牙开关状态变化 void _handleBluetoothStateChange(String state) { if (state == 'off') { _setError( ErrorType.bluetoothOff, 'connectDeepSoundViaSystemBluetooth'.tr); } else if (state == 'on' && _errorType.value == ErrorType.bluetoothOff) { // 蓝牙重新开启,恢复流程 Logger.i(_tag, '检测到蓝牙已开启,自动恢复配对流程'); _clearError(); // 延迟一下确保蓝牙服务完全就绪 Future.delayed(const Duration(milliseconds: 500), () { _checkCurrentStatus(); }); } } /// 处理经典蓝牙设备变化 void _handleClassicDeviceChange(BluetoothDevice? device) { _currentClassicDevice = device; switch (_currentState.value) { case PairingState.waitingClassic: if (device != null) { // 有设备连接,进入验证阶段 Logger.d(_tag, '检测到经典蓝牙设备连接,开始验证'); _transition(PairingState.verifying); _verifyDevice(device); } break; case PairingState.error: // 如果在错误状态下检测到设备连接,且错误是无设备连接,则自动恢复 if (device != null && _errorType.value == ErrorType.noClassicDevice) { Logger.i(_tag, '检测到设备重新连接,自动恢复配对流程'); _clearError(); _transition(PairingState.verifying); _verifyDevice(device); } break; case PairingState.verifying: case PairingState.waitingBle: case PairingState.completed: if (device == null) { // 设备断开,返回等待连接状态 _setError(ErrorType.noClassicDevice, 'deviceDisconnected'.tr); //设备已断开 } break; default: break; } } /// 处理BLE状态变化 void _handleBleStateChange(int state) { if (_currentState.value == PairingState.waitingBle) { if (state == 2) { // BLE已连接 _bleTimeoutTimer?.cancel(); _transition(PairingState.completed); } } // 如果在完成状态下BLE断开,显示警告但不改变状态 if (_currentState.value == PairingState.completed && state != 2) { Logger.w(_tag, 'BLE连接已断开,但配对流程已完成'); } } // ==================== 状态转换 ==================== /// 状态转换 void _transition(PairingState newState) { final oldState = _currentState.value; _currentState.value = newState; Logger.i(_tag, '状态转换: $oldState -> $newState'); // 根据新状态执行相应操作 _onStateChanged(newState); } /// 状态变化处理 void _onStateChanged(PairingState state) { // 重置UI状态 isLoading.value = false; showConnectButton.value = false; showRetryButton.value = false; showSkipBindingButton.value = false; // 重置临时跳过绑定按钮 showSkipButton.value = false; showAutoCodeInput.value = false; showBindButton.value = false; showRetryChectButton.value = false; switch (state) { case PairingState.idle: statusText.value = 'readyToStartPairing'.tr; break; case PairingState.checking: statusText.value = 'checkingEnvironment'.tr; isLoading.value = true; break; case PairingState.waitingClassic: statusText.value = 'ensureHeadsetOnAndPairingMode'.tr; showConnectButton.value = true; showSkipButton.value = isShowSkipButton; connectButtonText.value = 'goToBluetoothSettings'.tr; break; case PairingState.verifying: statusText.value = 'verifyingDevice'.tr; isLoading.value = true; break; case PairingState.binding: statusText.value = 'confirmBinding'.tr; isLoading.value = true; showBindButton.value = true; showRetryChectButton.value = true; break; case PairingState.associating: statusText.value = 'associatingDevice'.tr; isLoading.value = true; // 延迟执行关联,确保状态已更新 Future.delayed(const Duration(milliseconds: 200), () { _startDeviceAssociation(); }); break; case PairingState.waitingBle: statusText.value = 'establishingSecureConnection'.tr; isLoading.value = true; // 延迟一下再调用,给BLE管理器时间更新状态 Future.delayed(const Duration(milliseconds: 200), () { _startBleConnection(); }); break; case PairingState.manualbinding: statusText.value = 'needManualBindingAuthCode'.tr; isLoading.value = false; showAutoCodeInput.value = true; // showSkipButton.value = isShowSkipButton; showSkipBindingButton.value = true; // 显示临时跳过绑定按钮 break; case PairingState.completed: statusText.value = 'pairingSuccessful'.tr; isLoading.value = false; _navigateToHome(); break; case PairingState.error: statusText.value = _errorMessage.value; isLoading.value = false; showSkipButton.value = isShowSkipButton; // 根据错误类型决定显示哪个按钮和按钮文本 switch (_errorType.value) { case ErrorType.bluetoothOff: showConnectButton.value = true; connectButtonText.value = 'goToBluetoothSettings'.tr; //开启蓝牙 break; case ErrorType.noClassicDevice: showConnectButton.value = true; connectButtonText.value = 'goToBluetoothSettings'.tr; //前往蓝牙设备 break; case ErrorType.noPermission: showRetryButton.value = true; retryButtonText.value = 'grantPermissions'.tr; //授予权限 break; case ErrorType.associationFailed: showRetryButton.value = true; retryButtonText.value = 'retryAssociation'.tr; //重新关联 break; case ErrorType.authnFailed: showRetryButton.value = true; retryButtonText.value = 'retryAuthorization'.tr; //重新授权 break; default: showRetryButton.value = true; retryButtonText.value = 'retry'.tr; //重试 break; } break; } } // ==================== 错误处理 ==================== /// 设置错误状态 void _setError(ErrorType type, String message) { _errorType.value = type; _errorMessage.value = message; _transition(PairingState.error); } /// 清除错误状态 void _clearError() { _errorType.value = ErrorType.none; _errorMessage.value = ''; } // ==================== 核心流程 ==================== /// 开始初始检查 void _startInitialCheck() { // _transition(PairingState.checking); _checkCurrentStatus(); } /// 检查当前状态并决定下一步 void _checkCurrentStatus() async { try { // 1. 检查蓝牙状态 final results = await Future.wait([ _checkBluetoothState(), // 检查蓝牙状态 _checkPermissions(), // 检查权限 _bluetoothManager.refreshDeviceConnection(), // 刷新设备连接 ]); final isBluetoothOk = results[0] as bool; final arePermissionsOk = results[1] as bool; if (!isBluetoothOk) { _setError( ErrorType.bluetoothOff, 'connectDeepSoundViaSystemBluetooth'.tr); return; } // 2. 检查权限 if (!arePermissionsOk) { _setError(ErrorType.noPermission, 'pleaseGrantNecessaryPermissions'.tr); return; } // 3. 先刷新设备连接状态,确保获取最新的连接信息 await _bluetoothManager.refreshDeviceConnection(); // 4. 检查经典蓝牙连接 final classicDevice = _bluetoothManager.currentDevice; if (classicDevice == null) { _transition(PairingState.waitingClassic); return; } // 5. 如果有设备,进行验证 _currentClassicDevice = classicDevice; _transition(PairingState.verifying); await _verifyDevice(classicDevice); } catch (e) { Logger.e(_tag, '状态检查失败: $e'); _setError(ErrorType.networkError, 'checkFailedRetry'.tr); } } /// 新增一个辅助方法来检查蓝牙状态 Future _checkBluetoothState() async { return _bluetoothManager.bluetoothState != 'off'; } /// 检查是否为华为设备 bool _isHuaweiDevice() { final deviceBrand = versionService.cachedDeviceBrand; return deviceBrand.isNotEmpty && (deviceBrand.contains('huawei') || deviceBrand.contains('华为')); } /// 检查权限 Future _checkPermissions() async { //如果是华为设备,且已经检查过,直接返回权限状态 if (isHuaweiDevice && isHuaweiHasChecked) { final bluetoothScanStatus = await Permission.bluetoothScan.status; final bluetoothConnectStatus = await Permission.bluetoothConnect.status; final locationStatus = await Permission.locationWhenInUse.status; return bluetoothScanStatus.isGranted && bluetoothConnectStatus.isGranted && locationStatus.isGranted; } // Android权限检查 if (Platform.isAndroid) { Logger.i(_tag, '开始检查Android权限'); // 检查蓝牙相关权限 final bluetoothScanGranted = await PermissionUtil.instance.requestPermission( permissionType: Permission.bluetoothScan, permissionName: 'bluetoothScan'.tr, explanationText: 'bluetoothScanExplanation'.tr, permanentDenialText: 'bluetoothScanPermanentDenial'.tr, ); final bluetoothConnectGranted = await PermissionUtil.instance.requestPermission( permissionType: Permission.bluetoothConnect, permissionName: 'bluetoothConnect'.tr, explanationText: 'bluetoothConnectExplanation'.tr, permanentDenialText: 'bluetoothConnectPermanentDenial'.tr, ); final locationGranted = await PermissionUtil.instance.requestPermission( permissionType: Permission.locationWhenInUse, permissionName: 'locationInfo'.tr, explanationText: 'locationForBluetoothExplanation'.tr, permanentDenialText: 'locationPermanentDenial'.tr, ); if (isHuaweiDevice) { _storage.write('isHuaweiHasChecked', true); } return bluetoothScanGranted && bluetoothConnectGranted && locationGranted; } return true; } /// 验证设备 Future _verifyDevice(BluetoothDevice device) async { try { Logger.i(_tag, '开始验证设备: ${device.name} (${device.address})'); final result = await authbindingDevice(device); if (result == 10) { //验证成功 直接连接ble await connectble(device); } else if (result == 9) { Logger.i(_tag, 'BLE已连接,直接完成配对'); _transition(PairingState.completed); } else if (result == 1) { //跳转绑定界面 //验证失败 进入手动授权 if (currentDevice != null) { _transition(PairingState.binding); } else { _transition(PairingState.checking); _checkCurrentStatus(); } } else { final authcode_open = AppConfig.env("APP_AUTHCODE_OPEN") ?? ""; if (authcode_open == "true") { Logger.i(_tag, '进入手动验证流: ${device.name} (${device.address})'); //验证失败 进入手动授权 _transition(PairingState.manualbinding); } else { Logger.i(_tag, '设备不支持: ${device.name} (${device.address})'); _setError(ErrorType.deviceNotMatch, 'pleaseConnectDeepSoundDevice'.tr); //请连接DeepSound设备 } } } catch (e) { Logger.e(_tag, '设备验证异常: $e'); _setError(ErrorType.networkError, 'verificationFailedRetry'.tr); //验证失败请重试 } } //连接ble Future connectble(BluetoothDevice device) async { Logger.i(_tag, '设备验证通过'); // _verifiedDeviceAddress = device.address; // 检查是否已有BLE关联 final pairedMacAddress = await _bleManager.getPairedMacAddress(); Logger.i(_tag, '已关联的MAC地址: $pairedMacAddress'); if (pairedMacAddress != null && pairedMacAddress.toUpperCase() == _verifiedDeviceAddress?.toUpperCase()) { // 已有关联,检查BLE连接状态 Logger.i(_tag, '设备已关联,检查BLE连接状态'); print('fdp--connectble--pairedMacAddress: $pairedMacAddress'); final currentBleState = await _bleManager.getConnectionState(); Logger.i(_tag, '验证时BLE状态: $currentBleState'); print('fdp--connectble--currentBleState: $currentBleState'); if (currentBleState == 2) { // BleConnectionState.connected Logger.i(_tag, 'BLE已连接,直接完成配对'); _transition(PairingState.completed); } else { Logger.i(_tag, 'BLE未连接,等待BLE连接'); _transition(PairingState.waitingBle); } } else { // 没有关联或关联的是其他设备,需要进行关联 Logger.i(_tag, '需要进行BLE设备关联'); _transition(PairingState.associating); } return; } /// 开始设备关联 void _startDeviceAssociation() async { try { if (_verifiedDeviceAddress == null) { _setError( ErrorType.associationFailed, 'invalidDeviceAddress'.tr); //无效的设备地址 return; } // Logger.i(_tag, '开始BLE设备关联: $_verifiedDeviceName:$_verifiedDeviceAddress'); if (Platform.isIOS) { // 调用BLE管理器的关联方法 final success = await _bleManager.startDeviceAssociation( deviceNamePattern: _verifiedDeviceName!, macAddress: _verifiedDeviceAddress!, ); if (success) { Logger.i(_tag, 'BLE设备关联成功'); //关联成功后,转到等待BLE连接状态 _transition(PairingState.waitingBle); } else { _setError(ErrorType.associationFailed, 'bleDeviceAssociationFailed'.tr); //BLE设备关联失败 } } else { _transition(PairingState.waitingBle); } } catch (e) { Logger.e(_tag, 'BLE设备关联异常: $e'); _setError(ErrorType.associationFailed, 'deviceAssociationFailedRetry'.tr); //设备关联失败,请重试 } } /// 开始BLE连接 void _startBleConnection() async { try { // 设置超时定时器 _bleTimeoutTimer?.cancel(); _bleTimeoutTimer = Timer(const Duration(seconds: 20), () async { final currentBleState = await _bleManager.getConnectionState(); if (currentBleState == 2) { _bleTimeoutTimer?.cancel(); _transition(PairingState.completed); return; } if (_currentState.value == PairingState.waitingBle) { _setError(ErrorType.bleTimeout, 'bleConnectionTimeoutRetry'.tr); //BLE连接超时,请重启耳机后再试 } }); // 检查是否已连接 - 直接从原生层获取最新状态 final currentBleState = await _bleManager.getConnectionState(); Logger.i(_tag, 'BLE当前连接状态: $currentBleState'); if (currentBleState == 2) { // BleConnectionState.connected Logger.i(_tag, 'BLE已经连接,直接完成配对'); _bleTimeoutTimer?.cancel(); _transition(PairingState.completed); return; } // 注册后台扫描以开始BLE配对 if (_verifiedDeviceAddress != null) { // 先注销后台扫描,确保重新开始 await _bleManager.unregisterBackgroundScan(); final success = await _bleManager.registerBackgroundScan( macAddress: _verifiedDeviceAddress, uuids: AppConfig.allproductUuids(), ); if (!success && _currentState.value == PairingState.waitingBle) { _setError( ErrorType.bleTimeout, 'blePairingStartupFailed'.tr); //BLE配对启动失败 } } } catch (e) { Logger.e(_tag, 'BLE连接失败: $e'); _setError(ErrorType.bleTimeout, 'bleConnectionFailed'.tr); //BLE连接失败 } } //自动绑定设备 0 未合作商 1 合作商 9 经典蓝牙已绑定 10,ble蓝牙已绑定 Future authbindingDevice(BluetoothDevice device) async { // 检查设备名称是否包含 DeepSound 或 DeapSound final deviceName = device.name; DBProduct? product; // 检查是否已有BLE绑定的设备 // 检查是否已有BLE绑定的设备 if (AppConfig.config.products.isNotEmpty) { final match = AppConfig.config.products.where( (d) => d.devicename.contains(deviceName), ); product = match.isNotEmpty ? match.first : null; } final currentBleState = await _bleManager.getConnectionState(); final names = AppConfig.allproductNames(); final uuids = AppConfig.allproductUuids(); // 检查是否已有绑定的设备 print("device.address${device.address}"); if (User.instance.devices.isNotEmpty) { final existingDevice = User.instance.devices.firstWhere( (d) => d.devicetype == 1 && d.devicename.contains(deviceName) && d.devicemac == device.address, orElse: () => UserDevice( id: -1, uid: '', devicetype: -1, devicename: '', devicemac: '', license: ''), ); if (existingDevice.id != -1) { // 设备是经典蓝牙,且已绑定 return 9; } } else { //未绑定设备 _bleManager.clearPairedDevices(); Logger.i(_tag, '验证时BLE状态: $currentBleState'); if (currentBleState == 2) { //已连接 清理 // BleConnectionState.connected Logger.i(_tag, 'BLE已连接,断开并清理缓存'); _bleManager.disconnect(); } } // 检查是否已有BLE绑定的设备 if (Platform.isAndroid) { final existingDevice = User.instance.devices.firstWhere( (d) => d.devicetype != 1 && d.devicename.contains(deviceName) && d.devicemac == device.address, orElse: () => UserDevice( id: -1, uid: '', devicetype: -1, devicename: '', devicemac: '', license: ''), ); if (existingDevice.id != -1) { _verifiedDeviceName = device.name; _verifiedDeviceAddress = device.address; // 设备时ble 蓝牙 且已绑定 return 10; } } print( '获取到 deviceName: $deviceName address: ${device.address} uuids:$uuids'); if (product != null && product.devicetype != 1) { if (currentBleState == 2) { //已连接直接返回 return 9; } await _bleManager.startScan(uuids); await Future.delayed(const Duration(seconds: 1)); // 尝试最多读取 3 次设备信息,每次间隔 1 秒 List>? deviceinfos; for (int i = 0; i < 15; i++) { // 使用设备名称获取设备列表 deviceinfos = await _bleManager.getDeviceList(deviceName); print('获取到 deviceinfos: $deviceinfos'); if (deviceinfos != null && deviceinfos.isNotEmpty) { // 循环读取每个设备的hex数据 for (var deviceInfo in deviceinfos) { String? hexData = deviceInfo["hex"]; if (hexData != null && hexData.length >= 28) { // 确保hex数据长度足够(14字节 = 28个字符) // 读取9-14字节的MAC地址 String macFromHex = extractMacFromHex(hexData, device.address); if (macFromHex.isNotEmpty) { String code = ""; // 找到匹配的设备,提取授权码 if (Platform.isIOS) { // iOS设备,提取13-22字节的授权码 code = extractAndReverseBytes(hexData, 13, 22); _verifiedDevicePid = extractAndReverseBytesToInt(hexData, 4, 5); print('找到匹配设备,获取到 code: $code'); if (code != "") { _bleManager.stopScan(); deviceCode.value = code; String? uuids = deviceInfo["id"]; _verifiedDeviceName = device.name; _verifiedDeviceAddress = uuids; print('找到匹配设备,获取到 uuids: $uuids'); //检查是否已经绑定 final existingDevice = User.instance.devices.firstWhere( (d) => d.devicetype != 1 && d.license != "" && d.devicemac == device.address, orElse: () => UserDevice( id: -1, uid: '', devicetype: -1, devicename: '', devicemac: '', license: ''), ); if (existingDevice.id != -1) { _bleManager.stopScan(); // 已经绑定 return 10; } else { _bleManager.stopScan(); return 1; } } } else if (Platform.isAndroid) { // Android设备,提取15-24字节的授权码 code = extractAndReverseBytes(hexData, 15, 24); _verifiedDevicePid = extractAndReverseBytesToInt(hexData, 6, 7); print('找到匹配设备,获取到 code: $code'); if (code != "") { _bleManager.stopScan(); deviceCode.value = code; _verifiedDeviceName = device.name; _verifiedDeviceAddress = device.address; //检查是否已经绑定 final existingDevice = User.instance.devices.firstWhere( (d) => d.devicetype != 1 && d.license != "" && d.devicemac == device.address, orElse: () => UserDevice( id: -1, uid: '', devicetype: -1, devicename: '', devicemac: '', license: ''), ); if (existingDevice.id != -1) { _bleManager.stopScan(); // 已经绑定 return 10; } else { _bleManager.stopScan(); return 1; } } } else { break; } } } } } final currentBleState = await _bleManager.getConnectionState(); if (currentBleState == 2) { _bleManager.clearPairedDevices(); _bleManager.disconnect(); } await Future.delayed(Duration(seconds: 1)); } _bleManager.stopScan(); // if (product != null && product.devicetype != 1) { // //ble设备 必须要扫描到结果 // return 0; // } } return 0; //可以跳转1 } // 新增方法:从hex数据中提取MAC地址并与当前设备MAC对比 String extractMacFromHex(String hexData, String deviceMac) { try { // 将hex字符串转换为字节数组 List bytes = []; for (int i = 0; i < hexData.length; i += 2) { bytes.add(int.parse(hexData.substring(i, i + 2), radix: 16)); } // 读取9-14字节(索引8-13)的MAC地址 if (bytes.length < 14) { return ""; } List macBytes = []; List tempBytes = []; if (Platform.isIOS) { for (int i = 7; i <= 12; i++) { // 每个字节异或0x5A int decodedByte = bytes[i] ^ 0x5A; macBytes.add(decodedByte); } } else if (Platform.isAndroid) { for (int i = 9; i <= 14; i++) { tempBytes.add(bytes[i]); // 每个字节异或0x5A int decodedByte = bytes[i] ^ 0x5A; macBytes.add(decodedByte); } } // 将MAC字节转换为MAC地址字符串格式 String extractedMac = macBytes .map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()) .join(':'); String tempMac = tempBytes .map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()) .join(':'); // 格式化当前设备MAC地址(确保格式一致) String formattedDeviceMac = deviceMac.replaceAll(':', '').toUpperCase(); String formattedExtractedMac = extractedMac.replaceAll(':', '').toUpperCase(); print('设备MAC: $deviceMac, 提取的MAC: $extractedMac tempMac: $tempMac'); // 对比MAC地址 if (formattedDeviceMac == formattedExtractedMac) { print('MAC地址匹配成功!'); return extractedMac; } else { print('MAC地址不匹配'); return ""; } } catch (e) { print('提取MAC地址时出错: $e'); return ""; } } //确认绑定设备 void confirmBindDevice() async { if (currentDevice == null) { Logger.e(_tag, '当前设备为空!'); _transition(PairingState.verifying); return; } final response = await Api.binddevice({ "pid": _verifiedDevicePid, "code": deviceCode.value, "devicename": currentDevice?.name, "devicemac": currentDevice?.address, // 使用 address 替代 deviceId }); Logger.i(_tag, '手动授权结果 ${response}'); if (response != null) { Logger.i(_tag, '绑定设备成功 $response'); if (response['device'] != '') { // 根据API设计调整 final device = UserDevice.fromJson(response['device']); User.instance.addUserDevice(device); _transition(PairingState.verifying); _verifyDevice(_currentClassicDevice!); } /* message UserBindDeviceResp { DBUserDivice device = 1; //绑定的耳机信息 bool isgiveaway = 2; //@go_tags(`gorm:"isgiveaway" json:"isgiveaway"`) 是否是第一次绑定 int32 viplv = 3; //@go_tags(`gorm:"viplv:50" json:"viplv"`) viplv int64 vipexptime = 4; //@go_tags(`gorm:"vipexptime" json:"vipexptime"`) 会员过期时间 int64 aichatintegral = 5; //@go_tags(`gorm:"aichatintegral" json:"aichatintegral"`) ai聊天积分 int64 aichattotalintegral = 6; //@go_tags(`gorm:"aichattotalintegral" json:"aichattotalintegral"`) ai聊天总积分 int64 tradeintegral = 7; //@go_tags(`gorm:"tradeintegral" json:"tradeintegral"`) 翻译积分 int64 tradetotalintegral = 8; //@go_tags(`gorm:"tradetotalintegral" json:"tradetotalintegral"`) 翻译总积分 int64 meetintegral = 9; //@go_tags(`gorm:"meettotalintegral" json:"meettotalintegral"`) 会议积分 int64 meettotalintegral = 10; //@go_tags(`gorm:"meettotalintegral" json:"meettotalintegral"`) 会议总积分 } */ // 需要读取返回的数据判断 isgiveaway 是否 为 true,是的话 需要读取 后续的数据 更新到用户数据上面去 if (response['isgiveaway'] == true) { User.instance.viplv = response['viplv'] ?? 0; User.instance.vipexptime = response['vipexptime'] ?? 0; User.instance.aichatintegral = response['aichatintegral'] ?? 0; User.instance.aichattotalintegral = response['aichattotalintegral'] ?? 0; User.instance.tradeintegral = response['tradeintegral'] ?? 0; User.instance.tradetotalintegral = response['tradetotalintegral'] ?? 0; User.instance.meetintegral = response['meetintegral'] ?? 0; User.instance.meettotalintegral = response['meettotalintegral'] ?? 0; final lv = User.instance.viplv; final vipexptime = User.instance.vipexptime; DateTime? expiry; if (vipexptime > 0) { expiry = DateTime.fromMillisecondsSinceEpoch(vipexptime * 1000); } final y = expiry?.year.toString().padLeft(4, '0') ?? ''; final m = expiry?.month.toString().padLeft(2, '0') ?? ''; final d = expiry?.day.toString().padLeft(2, '0') ?? ''; final expiryText = expiry != null ? '$y-$m-$d' : 'N/A'; Get.dialog( AlertDialog( title: Text('firstBindRewardTitle'.tr), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('firstBindRewardDesc'.tr), SizedBox(height: 8.h), Text('${'vipLevelLabel'.tr} Vip $lv'), Text('${'expiryLabel'.tr} $expiryText'), SizedBox(height: 8.h), Text( '${'aiChatCreditsLabel'.tr} ${User.instance.aichatintegral}'), Text( '${'translationCreditsLabel'.tr} ${User.instance.tradeintegral}'), Text( '${'meetingCreditsLabel'.tr} ${User.instance.meetintegral}'), ], ), actions: [ TextButton( onPressed: () => Get.back(), child: Text('ok'.tr), ), ], ), barrierDismissible: true, ); } return; } else { Logger.e(_tag, '绑定设备失败!'); return; } } int reverseBits(int byte) { // 这里是 nibble swap 还是 bit 反转?看你需求,先保持 nibble swap return ((byte & 0x0F) << 4) | ((byte & 0xF0) >> 4); } String extractAndReverseBytes(String hex, int start, int end) { List bytes = []; for (int i = 0; i < hex.length; i += 2) { bytes.add(int.parse(hex.substring(i, i + 2), radix: 16)); } List slice = bytes.sublist(start, end + 1); List reversed = slice.reversed.toList(); return reversed .map((b) => b.toRadixString(16).padLeft(2, '0')) .join() .toUpperCase(); } int extractAndReverseBytesToInt(String hex, int start, int end) { List bytes = []; // 将十六进制字符串解析为字节列表 for (int i = 0; i < hex.length; i += 2) { bytes.add(int.parse(hex.substring(i, i + 2), radix: 16)); } // 截取指定范围的字节(包含end索引) List slice = bytes.sublist(start, end + 1); // 反转字节顺序 List reversed = slice.toList(); String pid = reversed .map((b) => b.toRadixString(16).padLeft(2, '0')) .join() .toUpperCase(); Logger.i(_tag, 'liwei-------------- 解析道Pid $pid'); // 将反转后的字节列表转换为整数 int result = 0; for (int b in reversed) { result = (result << 8) | (b & 0xFF); // 按字节拼接成整数 } return result; } /// 用户点击授权码输入框 void onAutoCodeInputTap() async { // 调用BLE管理器的自动绑定方法 final response = await Api.bindauthcode({ "code": codeInputController.text.trim(), "earphonname": currentDevice?.name, "earphonemac": currentDevice?.address, // 使用 address 替代 deviceId }); Logger.i(_tag, '手动授权结果 ${response}'); if (response != null) { // User.instance.earphonemac = currentDevice?.address ?? ''; // 使用 address // User.instance.earphonename = currentDevice?.name ?? ''; // User.instance.earphoneauthcode = codeInputController.text.trim(); _transition(PairingState.verifying); _verifyDevice(_currentClassicDevice!); } else { Logger.e(_tag, '手动绑定失败!'); _setError(ErrorType.authnFailed, 'deviceAuthorizationFailedCheckCode'.tr); //设备授权失败,请检查授权码 } } /// 导航到主页 void _navigateToHome() { // Future.delayed(const Duration(milliseconds: 500), () async { // 启动AgentService服务 try { Logger.i(_tag, '启动AgentService服务'); _bleManager.startAgentService(); // _bleManager.registerBackgroundScan(macAddress: _verifiedDeviceAddress); } catch (e) { Logger.e(_tag, '启动AgentService失败: $e'); } //print('lxm-上一个路由: ${Get.previousRoute.toString()}'); if (Get.previousRoute == Routes.home) { // 如果是从home页过来的,则直接返回 Get.back(); } else { // 否则,跳转到home页并清空之前的路由栈 Get.offAllNamed(Routes.home); } // }); } // ==================== 用户操作 ==================== /// 用户点击连接按钮 void onConnectTap() { Logger.i(_tag, '用户点击连接按钮'); // 根据当前状态或错误类型决定行为 if (_currentState.value == PairingState.error) { switch (_errorType.value) { case ErrorType.bluetoothOff: // 引导用户去开启蓝牙 Logger.i(_tag, '引导用户开启蓝牙'); _openBluetoothSettings(); break; case ErrorType.noClassicDevice: // 引导用户去蓝牙设置连接设备 Logger.i(_tag, '引导用户去蓝牙设置'); _openBluetoothSettings(); break; default: // 其他错误情况,刷新并重试 _bluetoothManager.refreshDeviceConnection(); _checkCurrentStatus(); break; } } else if (_currentState.value == PairingState.waitingClassic) { // 等待经典蓝牙连接状态,引导去设置 Logger.i(_tag, '等待经典蓝牙连接,引导用户去蓝牙设置'); _openBluetoothSettings(); } else { // 其他情况,刷新设备连接 _bluetoothManager.refreshDeviceConnection(); _checkCurrentStatus(); } } /// 用户点击重试按钮 void onRetryTap() { Logger.i(_tag, '用户点击重试按钮'); // 如果是权限问题,引导去设置 if (_errorType.value == ErrorType.noPermission) { Logger.i(_tag, '引导用户去应用设置授予权限'); AppSettings.openAppSettings(); } else { // 其他情况,清除错误并重试 _clearError(); _startInitialCheck(); } } /// 用户点击跳过绑定按钮 void onSkipBindingTap() { Logger.i(_tag, '用户选择临时跳过手动绑定'); User.instance.addUserDevice( UserDevice( id: 0, // 临时设备ID uid: User.instance.uid, devicetype: 1, devicemac: _currentClassicDevice?.address ?? '', devicename: _currentClassicDevice?.name ?? 'Unknown Device', license: "", // 临时授权码 ), ); _transition(PairingState.verifying); _verifyDevice(_currentClassicDevice!); } /// 用户点击跳过按钮 void onSkipTap() { Logger.i(_tag, '用户选择跳过配对'); // 启动AgentService服务 try { Logger.i(_tag, '启动AgentService服务'); _bleManager.startAgentService(); } catch (e) { Logger.e(_tag, '启动AgentService失败: $e'); } Get.offAllNamed(Routes.home); } /// 打开蓝牙设置 void openBluetoothSettings() { _openBluetoothSettings(); } /// 打开蓝牙设置 - 简化版本 void _openBluetoothSettings() async { if (Platform.isIOS) { const url = 'App-Prefs:'; //拉起iOS系统设置app到前台,使用旧接口生效 if (await canLaunch(url)) { await launch(url); } else { // 如果无法直接打开,回退到显示指导对话框 _showBluetoothGuideDialog(); } } else { // Android平台使用原有方式 AppSettings.openAppSettings(type: AppSettingsType.bluetooth); } } /// 显示蓝牙设置指导对话框 void _showBluetoothGuideDialog() { Get.dialog( AlertDialog( title: Text('bluetoothGuideTitle'.tr), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('bluetoothGuideSteps'.tr), SizedBox(height: 16.h), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('1. ', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14.sp)), Expanded( child: Text('bluetoothGuideStep1'.tr, style: TextStyle(fontSize: 14.sp))), ], ), SizedBox(height: 8.h), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('2. ', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14.sp)), Expanded( child: Text('bluetoothGuideStep2'.tr, style: TextStyle(fontSize: 14.sp))), ], ), SizedBox(height: 8.h), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('3. ', style: TextStyle( fontWeight: FontWeight.bold, fontSize: 14.sp)), Expanded( child: Text('bluetoothGuideStep3'.tr, style: TextStyle(fontSize: 14.sp))), ], ), SizedBox(height: 16.h), Container( padding: EdgeInsets.all(12.w), decoration: BoxDecoration( color: Colors.blue.withOpacity(0.1), borderRadius: BorderRadius.circular(8.r), border: Border.all(color: Colors.blue.withOpacity(0.3)), ), child: Row( children: [ Icon(Icons.info_outline, color: Colors.blue, size: 20.sp), SizedBox(width: 8.w), Expanded( child: Text( 'bluetoothGuideTip'.tr, style: TextStyle(fontSize: 12.sp, color: Colors.blue[700]), ), ), ], ), ), ], ), actions: [ TextButton( onPressed: () => Get.back(), child: Text('iKnow'.tr, style: TextStyle(fontSize: 14.sp)), ), ], ), ); } /// 清除设备关联(在需要重新配对时调用) Future clearDeviceAssociation() async { try { Logger.i(_tag, '清除设备关联'); await _bleManager.clearPairedDevices(); } catch (e) { Logger.e(_tag, '清除设备关联失败: $e'); } } // 用户选择设备后调用 void onDeviceSelected(BluetoothDevice device) { Logger.i(_tag, '用户选择了设备: ${device.name} (${device.address})'); selectedDevice.value = device; _currentClassicDevice = device; _transition(PairingState.verifying); _verifyDevice(device); } }