import 'package:app_settings/app_settings.dart'; import 'package:voitrans/data/models/appconfig_model.dart'; import '/data/models/appconfig.dart'; import '/data/models/user_Info.dart'; import '/data/services/network/api.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.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 '../../../data/services/ble_manager.dart'; import '../../../core/utils/permission_util.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 _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; String? _verifiedDeviceName; String? _verifiedDeviceAddress; TextEditingController codeInputController = TextEditingController(); // Public getter for view access BluetoothDevice? get currentDevice => _currentClassicDevice; @override void onInit() { super.onInit(); Logger.i(_tag, '配对控制器初始化'); // 注册应用生命周期监听器 Logger.i(_tag, '正在注册应用生命周期监听器'); WidgetsBinding.instance.addObserver(this); Logger.i(_tag, '应用生命周期监听器注册完成'); // 确保服务已初始化 _bluetoothManager = Get.find(); _bleManager = Get.find(); // 集中设置所有监听器 _setupAllListeners(); // 开始初始状态检查 // 延迟稍长时间,确保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'; } /// 检查权限 Future _checkPermissions() async { // 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, ); 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) { //验证失败 进入手动授权 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连接状态'); final currentBleState = await _bleManager.getConnectionState(); Logger.i(_tag, '验证时BLE状态: $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'); // 调用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设备关联失败 } } 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), () { 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) { final success = await _bleManager.registerBackgroundScan( macAddress: _verifiedDeviceAddress); 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 == device.name, ); 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 == device.name && d.devicemac == device.address, orElse: () => UserDevice( id: -1, uid: '', devicetype: -1, devicename: '', devicemac: '', license: ''), ); if (existingDevice.id != -1) { // 已经绑定 return 9; } } else { //未绑定设备 Logger.i(_tag, '验证时BLE状态: $currentBleState'); if (currentBleState == 2) { //已连接 清理 // BleConnectionState.connected Logger.i(_tag, 'BLE已连接,断开并清理缓存'); _bleManager.clearPairedDevices(); _bleManager.disconnect(); } } if (Platform.isAndroid) { // 检查是否已有BLE绑定的设备 final existingDevice = User.instance.devices.firstWhere( (d) => d.devicetype == 2 && d.devicename == device.name && d.devicemac == device.address, orElse: () => UserDevice( id: -1, uid: '', devicetype: -1, devicename: '', devicemac: '', license: ''), ); if (existingDevice.id != -1) { _verifiedDeviceName = device.name; _verifiedDeviceAddress = device.address; // 已经绑定 return 10; } } print( '获取到 deviceName: $deviceName address: ${device.address} uuids:$uuids'); if (names.contains(deviceName)) { 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); 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 == 2 && 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); 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 == 2 && 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; } } } } } await Future.delayed(Duration(seconds: 1)); } _bleManager.stopScan(); if (product != null && product.devicetype == 2) { //ble设备 必须要扫描到结果 return 0; } else { return 1; } } 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 = []; 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++) { // 每个字节异或0x5A int decodedByte = bytes[i] ^ 0x5A; macBytes.add(decodedByte); } } // 将MAC字节转换为MAC地址字符串格式 String extractedMac = macBytes .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'); // 对比MAC地址 if (formattedDeviceMac == formattedExtractedMac) { print('MAC地址匹配成功!'); return extractedMac; } else { print('MAC地址不匹配'); return ""; } } catch (e) { print('提取MAC地址时出错: $e'); return ""; } } //确认绑定设备 void confirmBindDevice() async { final response = await Api.binddevice({ "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!); } 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(); } /// 用户点击授权码输入框 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服务'); await _bleManager.startAgentService(); } catch (e) { Logger.e(_tag, '启动AgentService失败: $e'); } 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() async { Logger.i(_tag, '用户选择跳过配对'); // 启动AgentService服务 try { Logger.i(_tag, '启动AgentService服务'); await _bleManager.startAgentService(); } catch (e) { Logger.e(_tag, '启动AgentService失败: $e'); } Get.offAllNamed(Routes.home); } /// 打开蓝牙设置 void openBluetoothSettings() { _openBluetoothSettings(); } /// 打开蓝牙设置 - 简化版本 void _openBluetoothSettings() async { if (Platform.isIOS) { // iOS平台:直接显示用户指导对话框 _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); } }