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.

1333 lines
45 KiB

import 'dart:io';
import 'dart:async';
import 'package:app_settings/app_settings.dart';
import 'package:voitrans/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 'package:device_info_plus/device_info_plus.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 = <BluetoothDevice>[].obs; // 可用设备列表
final selectedDevice = Rx<BluetoothDevice?>(null); // 用户选中的设备
// ========== 监听器管理 ==========
final List<Worker> _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<VersionUpdateService>();
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<BluetoothManager>();
_bleManager = Get.find<BleManager>();
// 集中设置所有监听器
_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<void> _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<bool> _checkBluetoothState() async {
return _bluetoothManager.bluetoothState != 'off';
}
/// 检查是否为华为设备
bool _isHuaweiDevice() {
final deviceBrand = versionService.cachedDeviceBrand;
return deviceBrand.isNotEmpty &&
(deviceBrand.contains('huawei') || deviceBrand.contains('华为'));
}
/// 检查权限
Future<bool> _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<void> _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<void> 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) {
// await _bleManager.connect();
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<int> 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.any((name) => name.contains(deviceName))) {
if (currentBleState == 2) {
//已连接直接返回
return 9;
}
await _bleManager.startScan(uuids);
await Future.delayed(const Duration(seconds: 1));
// 尝试最多读取 3 次设备信息,每次间隔 1 秒
List<Map<String, String>>? 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 = "";
_verifiedDevicePid = extractAndReverseBytesToInt(hexData, 6, 7);
// 找到匹配的设备,提取授权码
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 != 1) {
// //ble设备 必须要扫描到结果
// return 0;
// }
}
return 0;
//可以跳转1
}
// 新增方法:从hex数据中提取MAC地址并与当前设备MAC对比
String extractMacFromHex(String hexData, String deviceMac) {
try {
// 将hex字符串转换为字节数组
List<int> 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<int> macBytes = [];
List<int> 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!);
}
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<int> bytes = [];
for (int i = 0; i < hex.length; i += 2) {
bytes.add(int.parse(hex.substring(i, i + 2), radix: 16));
}
List<int> slice = bytes.sublist(start, end + 1);
List<int> 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<int> bytes = [];
// 将十六进制字符串解析为字节列表
for (int i = 0; i < hex.length; i += 2) {
bytes.add(int.parse(hex.substring(i, i + 2), radix: 16));
}
// 截取指定范围的字节(包含end索引)
List<int> slice = bytes.sublist(start, end + 1);
// 反转字节顺序
List<int> 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服务');
await _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() 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) {
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<void> 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);
}
}