diff --git a/lib/data/services/ble_manager.dart b/lib/data/services/ble_manager.dart index 1bd4b11c5..a855ec38d 100644 --- a/lib/data/services/ble_manager.dart +++ b/lib/data/services/ble_manager.dart @@ -113,7 +113,7 @@ class BleManager extends GetxService { // 经典蓝牙实例 // 当前连接的设备信息 - String? _currentDeviceAddress; + String? currentDeviceAddress; String? _currentDeviceName; // BLE连接状态 @@ -513,7 +513,7 @@ class BleManager extends GetxService { (firmwareVersion != null || batteryLevel != null)) { Logger.info('lxm--设备信息不存在,创建新的设备信息对象'); // 使用保存的设备信息创建新的DeviceInfo对象 - String deviceAddress = _currentDeviceAddress ?? ""; + String deviceAddress = currentDeviceAddress ?? ""; String deviceName = _currentDeviceName ?? ""; Logger.info('lxm--创建新的设备信息对象: address=$deviceAddress, name=$deviceName'); @@ -561,7 +561,7 @@ class BleManager extends GetxService { void clearDeviceInfo() { Logger.info('清除设备信息'); deviceInfo.value = null; - _currentDeviceAddress = null; + currentDeviceAddress = null; _currentDeviceName = null; } @@ -573,7 +573,7 @@ class BleManager extends GetxService { // 确保设备信息对象存在 if (deviceInfo.value == null && _isConnected.value) { // 创建初始设备信息对象 - String deviceAddress = _currentDeviceAddress ?? ""; + String deviceAddress = currentDeviceAddress ?? ""; String deviceName = _currentDeviceName ?? ""; Logger.info('初始化设备信息对象: address=$deviceAddress, name=$deviceName'); @@ -1036,12 +1036,12 @@ class BleManager extends GetxService { try { // 保存设备地址信息 if (macAddress != null) { - _currentDeviceAddress = macAddress; + currentDeviceAddress = macAddress; // 从蓝牙管理器获取设备名称 final bluetoothManager = Get.find(); _currentDeviceName = bluetoothManager.currentDevice?.name ?? ""; Logger.info( - '保存设备信息: address=$_currentDeviceAddress, name=$_currentDeviceName'); + '保存设备信息: address=$currentDeviceAddress, name=$_currentDeviceName'); } return await _bleService.registerBackgroundScan(macAddress: macAddress); diff --git a/lib/data/services/bluetooth_manager.dart b/lib/data/services/bluetooth_manager.dart index 713bcb754..654cfa603 100644 --- a/lib/data/services/bluetooth_manager.dart +++ b/lib/data/services/bluetooth_manager.dart @@ -46,6 +46,7 @@ class BluetoothManager extends GetxService { /// 释放资源 @override void onClose() { + print("蓝牙服务关闭"); _bluetoothSubscription?.cancel(); super.onClose(); } diff --git a/lib/modules/devices/controllers/devices_controller.dart b/lib/modules/devices/controllers/devices_controller.dart index 65d6b24b1..ad2a74a73 100644 --- a/lib/modules/devices/controllers/devices_controller.dart +++ b/lib/modules/devices/controllers/devices_controller.dart @@ -24,29 +24,36 @@ class DevicesController extends GetxController { @override void onInit() { super.onInit(); + print("初始化设备管理1"); _bleManager = Get.find(); - + print("初始化设备管理2"); // 在初始化时加载设备数据 _loadDevices(); } // 加载设备数据 void _loadDevices() async { - devices.clear(); + Logger.info("加载设备"); final response = await Api.getdevices(); if (response != null) { - var devices = (response['devices'] as List) - .map((e) => UserDevice.fromJson(e as Map)) - .toList(); - User.instance.devices = devices; + if (response['devices'] != null) { + var devices = (response['devices'] as List) + .map((e) => UserDevice.fromJson(e as Map)) + .toList(); + User.instance.devices = devices; + } else { + User.instance.devices = []; + } + Logger.info("加载设备 ${User.instance.devices.length}"); } - + devices.clear(); for (var device in User.instance.devices) { if (!devices.containsKey(device.devicetype)) { devices[device.devicetype] = []; } devices[device.devicetype]!.add(device); } + devices.refresh(); } @override @@ -59,12 +66,22 @@ class DevicesController extends GetxController { final response = await Api.unbinddevice({ "id": device.id, }); + Logger.info("解绑设备 $response"); if (response != null) { // 响应式更新 - devices[device.devicetype]?.remove(device); - devices.refresh(); // 触发UI更新 - - if (device.devicemac == _bleManager.deviceInfo.value?.address) { + User.instance.devices.remove(device); + devices.clear(); + for (var device in User.instance.devices) { + if (!devices.containsKey(device.devicetype)) { + devices[device.devicetype] = []; + } + devices[device.devicetype]!.add(device); + } + devices.refresh(); + Logger.info( + "解绑设备 ${device.devicemac} 当前使用设备:${_bleManager.currentDeviceAddress}"); + if (device.devicemac == _bleManager.currentDeviceAddress) { + Logger.info("解绑设备 $device 重新匹配!"); User.instance.removeUserDevice(device.id); _bleManager.clearPairedDevices(); _bleManager.disconnect(); diff --git a/lib/modules/devices/views/devices_view.dart b/lib/modules/devices/views/devices_view.dart index f7ffc67f4..846004a4e 100644 --- a/lib/modules/devices/views/devices_view.dart +++ b/lib/modules/devices/views/devices_view.dart @@ -118,57 +118,51 @@ class DevicesView extends GetView { } Widget _buildDevicesList(bool isDarkMode) { - final devices = User.instance.devices; + return Obx(() { + // 使用控制器的响应式数据,这会触发控制器的实例化 + final groupedDevices = controller.devices; - if (devices.isEmpty) { - return _buildEmptyState(isDarkMode); - } - - // 按设备类型分组 - final Map> groupedDevices = {}; - for (var device in devices) { - final deviceType = DeviceType.fromValue(device.devicetype); - if (!groupedDevices.containsKey(deviceType)) { - groupedDevices[deviceType] = []; + if (groupedDevices.isEmpty) { + return _buildEmptyState(isDarkMode); } - groupedDevices[deviceType]!.add(device); - } - return ListView( - padding: EdgeInsets.all(20.w), - children: [ - // 遍历每个设备类型 - ...groupedDevices.entries.map((entry) { - final deviceType = entry.key; - final deviceList = entry.value; + return ListView( + padding: EdgeInsets.all(20.w), + children: [ + // 遍历每个设备类型 + ...groupedDevices.entries.map((entry) { + final deviceTypeValue = entry.key; + final deviceList = entry.value; + final deviceType = DeviceType.fromValue(deviceTypeValue); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // 设备类型标题 - Padding( - padding: EdgeInsets.only(bottom: 12.h), - child: Text( - deviceType.displayName, - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black87, + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 设备类型标题 + Padding( + padding: EdgeInsets.only(bottom: 12.h), + child: Text( + deviceType.displayName, + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w600, + color: isDarkMode ? Colors.white : Colors.black87, + ), ), ), - ), - // 该类型下的设备列表 - ...deviceList.map((device) => _buildDeviceCard( - device: device, - deviceType: deviceType, - isDarkMode: isDarkMode, - )), - SizedBox(height: 20.h), - ], - ); - }).toList(), - ], - ); + // 该类型下的设备列表 + ...deviceList.map((device) => _buildDeviceCard( + device: device, + deviceType: deviceType, + isDarkMode: isDarkMode, + )), + SizedBox(height: 20.h), + ], + ); + }).toList(), + ], + ); + }); } Widget _buildEmptyState(bool isDarkMode) { diff --git a/lib/modules/home/controllers/home_controller.dart b/lib/modules/home/controllers/home_controller.dart index a031c0b97..8b47ae480 100644 --- a/lib/modules/home/controllers/home_controller.dart +++ b/lib/modules/home/controllers/home_controller.dart @@ -171,7 +171,7 @@ class HomeController extends GetxController { Future _checkConnectionStatus() async { try { final currentBleState = await _bleManager.getConnectionState(); - + print('fdp--_checkConnectionStatus--currentBleState: $currentBleState'); bool hasClassicBluetooth = currentDevice != null; bool hasBleConnection = currentBleState == 2; bool wasConnected = _isFullyConnected.value; diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index df9198b89..99602941d 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -922,6 +922,7 @@ class PairingController extends GetxController with WidgetsBindingObserver { } List macBytes = []; + List tempBytes = []; if (Platform.isIOS) { for (int i = 7; i <= 12; i++) { // 每个字节异或0x5A @@ -930,6 +931,7 @@ class PairingController extends GetxController with WidgetsBindingObserver { } } else if (Platform.isAndroid) { for (int i = 9; i <= 14; i++) { + tempBytes.add(bytes[i]); // 每个字节异或0x5A int decodedByte = bytes[i] ^ 0x5A; macBytes.add(decodedByte); @@ -940,13 +942,15 @@ class PairingController extends GetxController with WidgetsBindingObserver { 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'); + print('设备MAC: $deviceMac, 提取的MAC: $extractedMac tempMac: $tempMac'); // 对比MAC地址 if (formattedDeviceMac == formattedExtractedMac) { diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt index a7e202690..5dddebd68 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/SimpleAudioReceiver.kt @@ -237,8 +237,21 @@ fun startAudioRecord(audioSourceType: AudioSourceType, callback: AudioDataCallba // 设置通话模式 - 这是关键! audioManager?.mode = AudioManager.MODE_IN_COMMUNICATION - // 启用扬声器(如果需要外放) - audioManager?.isSpeakerphoneOn = true + // 检查是否有蓝牙音频设备连接 + val isBluetoothConnected = audioManager?.isBluetoothA2dpOn == true + + // 只有在没有蓝牙设备连接时才启用扬声器 + if (!isBluetoothConnected) { + audioManager?.isSpeakerphoneOn = true + + Log.d("AudioMode", "未检测到蓝牙设备,启用扬声器") + } else { + audioManager?.isSpeakerphoneOn = false + // 启用蓝牙SCO连接 + audioManager?.isBluetoothScoOn = true + audioManager?.startBluetoothSco() + Log.d("AudioMode", "检测到蓝牙设备,使用蓝牙音频") + } // 请求音频焦点 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleConst.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleConst.kt index 5bb24ea8a..71959ff31 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleConst.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleConst.kt @@ -39,11 +39,11 @@ object BleConst { const val FOREGROUND_ID = 0xBEE // ================== 连接状态 ================== - const val STATE_DISCONNECTED = 0 - const val STATE_CONNECTING = 1 - const val STATE_CONNECTED = 2 - const val STATE_DISCONNECTING = 3 - const val STATE_ERROR = 4 + const val STATE_DISCONNECTED = 0//未连接 + const val STATE_CONNECTING = 1//已断开连接 + const val STATE_CONNECTED = 2//已连接 + const val STATE_DISCONNECTING = 3//连接中 + const val STATE_ERROR = 4//连接错误 // ================== 广播厂商信息 ================== /** 厂商ID - 文档中定义为0xABEF */ diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt index ebad04d7e..87355f98c 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt @@ -346,7 +346,7 @@ object BleService { } val filter = ScanFilter.Builder() - //.setServiceUuid(ParcelUuid(uuid)) + .setServiceUuid(ParcelUuid(uuid)) .build() filters.add(filter) Log.d(TAG, "添加扫描过滤器UUID: $uuid") @@ -475,16 +475,7 @@ object BleService { ret.add(info) } } - } else { - // 如果没找到匹配设备名的结果,返回所有扫描到的设备信息 - for (result in scanResults) { - val info = printDeviceInfo(result) - if (info != null) { - ret.add(info) - } - } } - return ret } @@ -595,6 +586,7 @@ object BleService { * 断开当前连接 */ fun disconnect() { + Log.d(TAG, "主动断开当前连接") bluetoothGatt?.disconnect() updateConnectionState(BleConst.STATE_DISCONNECTING) } @@ -625,6 +617,7 @@ object BleService { * 更新连接状态并通知回调 */ private fun updateConnectionState(state: Int) { + Log.d(TAG, "fdp--------- 更新连接状态: $state") connectionState.postValue(state) notifyConnectionStateChanged(state) } @@ -657,17 +650,24 @@ object BleService { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { try { // 首先尝试读取当前PHY状态 - g.readPhy() + val readResult = g.readPhy() + Log.d(TAG, "读取PHY状态请求结果: $readResult") - // 然后请求设置2M PHY - g.setPreferredPhy( - BluetoothDevice.PHY_LE_2M_MASK, // TX PHY: 2M - BluetoothDevice.PHY_LE_2M_MASK, // RX PHY: 2M - BluetoothDevice.PHY_OPTION_NO_PREFERRED - ) - Log.d(TAG, "已请求设置PHY为2M") + // 延迟一段时间后再设置PHY,确保readPhy完成 + Handler(Looper.getMainLooper()).postDelayed({ + try { + val setResult = g.setPreferredPhy( + BluetoothDevice.PHY_LE_2M_MASK, // TX PHY: 2M + BluetoothDevice.PHY_LE_2M_MASK, // RX PHY: 2M + BluetoothDevice.PHY_OPTION_NO_PREFERRED + ) + Log.d(TAG, "设置PHY为2M请求结果: $setResult") + } catch (e: Exception) { + Log.w(TAG, "设置PHY失败: ${e.message}") + } + }, 500) // 延迟500ms } catch (e: Exception) { - Log.w(TAG, "设置PHY失败: ${e.message},将使用默认1M PHY") + Log.w(TAG, "读取PHY失败: ${e.message},将使用默认1M PHY") } } else { Log.w(TAG, "当前Android版本不支持PHY设置(需要API 26+),使用默认1M PHY") @@ -678,11 +678,13 @@ object BleService { newState == BluetoothProfile.STATE_DISCONNECTED -> { updateConnectionState(BleConst.STATE_DISCONNECTED) + Log.d(TAG, "监听到已断开连接") disconnectGatt() } else -> { updateConnectionState(BleConst.STATE_ERROR) + Log.d(TAG, "监听到连接错误") disconnectGatt() } } @@ -708,6 +710,7 @@ object BleService { */ override fun onPhyUpdate(gatt: BluetoothGatt, txPhy: Int, rxPhy: Int, status: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + Log.d(TAG, "PHY更新回调: status=$status, txPhy=$txPhy, rxPhy=$rxPhy") when (status) { BluetoothGatt.GATT_SUCCESS -> { val txPhyStr = getPhyString(txPhy) @@ -721,7 +724,7 @@ object BleService { Log.w(TAG, "PHY更新出现一般性错误,可能是设备兼容性问题") } else -> { - Log.w(TAG, "PHY更新失败: status=$status") + Log.w(TAG, "PHY更新失败: status=$status,设备可能不支持2M PHY") } } } @@ -1506,39 +1509,39 @@ startBytesStatistics() failureReason.append(" - 原因: BluetoothGatt为空") } else { // 检查连接状态 - val connectionState = bluetoothManager.getConnectionState( + val State = bluetoothManager.getConnectionState( bluetoothGatt!!.device, BluetoothProfile.GATT ) - when (connectionState) { + when (State) { BluetoothProfile.STATE_DISCONNECTED -> { - failureReason.append(" - 原因: 设备已断开连接") + failureReason.append(" -发送失败 原因: 设备已断开连接") } BluetoothProfile.STATE_CONNECTING -> { - failureReason.append(" - 原因: 设备正在连接中") + failureReason.append(" -发送失败 原因: 设备正在连接中") } BluetoothProfile.STATE_DISCONNECTING -> { - failureReason.append(" - 原因: 设备正在断开连接") + failureReason.append(" -发送失败 原因: 设备正在断开连接") } BluetoothProfile.STATE_CONNECTED -> { // 连接正常,检查其他原因 if (callWriteChar == null) { - failureReason.append(" - 原因: 写入特征值为空") + failureReason.append(" -发送失败 原因: 写入特征值为空") } else { // 检查特征值属性 val properties = callWriteChar!!.properties if ((properties and BluetoothGattCharacteristic.PROPERTY_WRITE) == 0 && (properties and BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) { - failureReason.append(" - 原因: 特征值不支持写入操作") + failureReason.append(" -发送失败 原因: 特征值不支持写入操作") } else if (chunk.size > 512) { // BLE MTU通常限制 - failureReason.append(" - 原因: 数据块过大 (${chunk.size} > 512字节)") + failureReason.append(" -发送失败 原因: 数据块过大 (${chunk.size} > 512字节)") } else { - failureReason.append(" - 原因: 未知错误,可能是设备忙碌或缓冲区满") + failureReason.append(" -发送失败 原因: 未知错误,可能是设备忙碌或缓冲区满") } } } else -> { - failureReason.append(" - 原因: 未知连接状态($connectionState)") + failureReason.append(" -发送失败 原因: 未知连接状态($connectionState)") } } } diff --git a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift index 87c242ef8..da86e4dca 100644 --- a/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift +++ b/local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift @@ -300,13 +300,13 @@ private var cmdReplyType: UInt8 = 0 } } - // // 开始扫描,使用构建的服务UUID数组进行过滤 - // manager.scanForPeripherals(withServices: serviceUUIDs.isEmpty ? nil : serviceUUIDs, options: [ - // CBCentralManagerScanOptionAllowDuplicatesKey: true // 允许重复以获取更新的广播数据 - // ]) - manager.scanForPeripherals(withServices: nil , options: [ + // 开始扫描,使用构建的服务UUID数组进行过滤 + manager.scanForPeripherals(withServices: serviceUUIDs.isEmpty ? nil : serviceUUIDs, options: [ CBCentralManagerScanOptionAllowDuplicatesKey: true // 允许重复以获取更新的广播数据 ]) + // manager.scanForPeripherals(withServices: nil , options: [ + // CBCentralManagerScanOptionAllowDuplicatesKey: true // 允许重复以获取更新的广播数据 + // ]) let filterInfo = serviceUUIDs.isEmpty ? "无过滤" : "过滤器数量: \(serviceUUIDs.count)" os_log("🔍 开始扫描BLE设备(%{public}@),超时时间: %.1f秒", log: logger, type: .info, filterInfo, timeout) diff --git a/local_plugins/classic_bluetooth/android/build.gradle.kts b/local_plugins/classic_bluetooth/android/build.gradle.kts index 3c6531e8c..ab03eec12 100644 --- a/local_plugins/classic_bluetooth/android/build.gradle.kts +++ b/local_plugins/classic_bluetooth/android/build.gradle.kts @@ -34,4 +34,6 @@ android { dependencies { add("implementation", "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10") + // 添加对 ble_service 模块的依赖 + add("compileOnly", project(":ble_service")) } diff --git a/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt b/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt index 16c4a8279..d2174a772 100644 --- a/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt +++ b/local_plugins/classic_bluetooth/android/src/main/kotlin/com/yunqiinnovation/classic_bluetooth/ClassicBluetoothPlugin.kt @@ -15,6 +15,8 @@ import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.Result +// 添加BLE服务导入 +import com.yunqiinnovation.ble_service.BleService /** ClassicBluetoothPlugin */ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler { @@ -135,7 +137,15 @@ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler { ClassicBluetoothHelper.BluetoothState.TURNING_OFF -> "turningOff" ClassicBluetoothHelper.BluetoothState.UNKNOWN -> "unknown" } - + if(state == ClassicBluetoothHelper.BluetoothState.OFF){ + try { + BleService.disconnect() + Log.d(TAG, "经典蓝牙设备断开,已触发BLE强制断开连接") + } catch (e: Exception) { + Log.e(TAG, "调用BLE强制断开连接失败: ${e.message}", e) + } + } + // 发送状态变化事件 val eventMap = mapOf( "type" to "stateChanged", @@ -156,11 +166,19 @@ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler { ), "timestamp" to System.currentTimeMillis() ) - + Log.d(TAG, "经典蓝牙设备连接") sendEvent(eventMap) } override fun onDeviceDisconnected(device: Map) { + // 经典蓝牙设备断开时,同时断开BLE连接 + try { + BleService.disconnect() + Log.d(TAG, "经典蓝牙设备断开,已触发BLE强制断开连接") + } catch (e: Exception) { + Log.e(TAG, "调用BLE强制断开连接失败: ${e.message}", e) + } + // 发送设备断开事件 val eventMap = mapOf( "type" to "deviceDisconnected", @@ -190,4 +208,4 @@ class ClassicBluetoothPlugin: FlutterPlugin, MethodCallHandler { Log.e(TAG, "事件发送失败", e) } } -} \ No newline at end of file +} \ No newline at end of file diff --git a/local_plugins/classic_bluetooth/ios/classic_bluetooth/Package.swift b/local_plugins/classic_bluetooth/ios/classic_bluetooth/Package.swift index c5a9d1c96..9150e4b8e 100644 --- a/local_plugins/classic_bluetooth/ios/classic_bluetooth/Package.swift +++ b/local_plugins/classic_bluetooth/ios/classic_bluetooth/Package.swift @@ -11,12 +11,16 @@ let package = Package( ) ], dependencies: [ - // 如果需要其他依赖,在这里添加 + // 添加对ble_service的依赖 + .package(path: "../../../ble_service/ios/ble_service") ], targets: [ .target( name: "classic_bluetooth", - dependencies: [], + dependencies: [ + // 添加ble_service产品依赖 + .product(name: "ble-service", package: "ble_service") + ], path: "Sources" ) ] diff --git a/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/ClassicBluetoothHelper.swift b/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/ClassicBluetoothHelper.swift index 7a83661db..6db8ac026 100644 --- a/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/ClassicBluetoothHelper.swift +++ b/local_plugins/classic_bluetooth/ios/classic_bluetooth/Sources/classic_bluetooth/ClassicBluetoothHelper.swift @@ -1,7 +1,7 @@ import Foundation import AVFoundation import CoreBluetooth - +import ble_service /// 蓝牙事件类型 public enum BluetoothEventType { case stateChanged @@ -65,16 +65,35 @@ public class ClassicBluetoothHelper: NSObject, CBCentralManagerDelegate { case .stateChanged: if let state = data["state"] as? String { print("蓝牙状态变化: \(state)") -// configureAudioRouteBasedOnBluetoothState() } case .deviceConnected: print("蓝牙设备已连接") - // 蓝牙设备连接时:末端在手机,输出端在耳机 -// configureAudioForBluetoothConnected() case .deviceDisconnected: print("蓝牙设备已断开") - // 蓝牙设备断开时:末端和输出端都在手机 - /*configureAudioForBluetoothDisconnected*/() + // 蓝牙设备断开时:调用BLE断开连接 + disconnectBleOnClassicBluetoothDisconnected() + } + } + + /** + * 经典蓝牙断开时调用BLE断开连接 + * 当检测到经典蓝牙设备断开时,主动断开BLE连接 + */ + private func disconnectBleOnClassicBluetoothDisconnected() { + // 检查BLE服务是否可用 + if #available(iOS 13.0, *) { + let bleService = BleService.shared + + // 检查BLE是否已连接 + if bleService.isConnected() { + print("检测到经典蓝牙断开,正在断开BLE连接...") + bleService.disconnect() + print("BLE连接已断开") + } else { + print("BLE未连接,无需断开") + } + } else { + print("iOS版本不支持BLE服务") } } @@ -290,6 +309,9 @@ public class ClassicBluetoothHelper: NSObject, CBCentralManagerDelegate { "address": cleanDeviceAddress(output.uid) ] stateCallback?(.deviceDisconnected, ["device": device]) + + // 在这里调用BLE断开连接 + disconnectBleOnClassicBluetoothDisconnected() } // 检查当前是否还有蓝牙设备 diff --git a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt index 4e371876a..5c87e6c94 100644 --- a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt +++ b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt @@ -423,52 +423,83 @@ class QQMusicSingleton private constructor() { action: (QQMusicManager, QQMusicManager.SearchCallback) -> Unit ): (callback: (Result>>) -> Unit) -> Unit { return lambda@{ callback -> - + if (!isQQMusicInstalled()){ callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件"))) return@lambda } - + val currentActivity = context if (currentActivity == null) { callback(Result.failure(Exception("Activity not available"))) return@lambda } - Log.d(TAG, "开始 ${actionName}") - ensureMusicManager(currentActivity,object: QQMusicManager. BindCallback{ - override fun onSuccess(){ - action(musicManager!!, object : QQMusicManager.SearchCallback { - override fun onSuccess(songs: List>) { - Log.d(TAG, "${actionName} 成功") - handler.post { - callback(Result.success(songs)) - } - } - - override fun onError(errorCode: Int, errorMessage: String) { - Log.d(TAG, "失败 ${actionName} 成功") - if (allagain > 0 && curragain < allagain){ //重试机制 - executeSearchbackAction(actionName,curragain+1,allagain,action) - }else{ - handler.post { - callback(Result.failure(Exception("$actionName 失败: $errorMessage"))) - } - } - } - }) + + // 添加登录状态检查 + if (!isLoggedIn()) { + Log.d(TAG, "用户未登录,开始自动登录") + login { loginResult -> + if (loginResult.isSuccess) { + Log.d(TAG, "自动登录成功,继续执行 ${actionName}") + // 登录成功后继续执行原操作 + executeSearchAction(actionName, curragain, allagain, action, callback) + } else { + Log.e(TAG, "自动登录失败: ${loginResult.exceptionOrNull()?.message}") + callback(Result.failure(Exception("用户未登录且自动登录失败: ${loginResult.exceptionOrNull()?.message}"))) + } } - override fun onError(errorCode: Int, errorMessage: String) { - if (allagain > 0 && curragain < allagain){ //重试机制 - executeSearchbackAction(actionName,curragain+1,allagain,action) - }else{ + return@lambda + } + + // 用户已登录,直接执行搜索操作 + executeSearchAction(actionName, curragain, allagain, action, callback) + } + } + + // 提取搜索执行逻辑为独立方法 + private fun executeSearchAction( + actionName: String, + curragain: Int, + allagain: Int, + action: (QQMusicManager, QQMusicManager.SearchCallback) -> Unit, + callback: (Result>>) -> Unit + ) { + Log.d(TAG, "开始 ${actionName}") + ensureMusicManager(context!!, object: QQMusicManager.BindCallback{ + override fun onSuccess(){ + action(musicManager!!, object : QQMusicManager.SearchCallback { + override fun onSuccess(songs: List>) { + Log.d(TAG, "${actionName} 成功") handler.post { - callback(Result.failure(Exception("$actionName 失败: $errorMessage"))) + callback(Result.success(songs)) + } + } + + override fun onError(errorCode: Int, errorMessage: String) { + Log.d(TAG, "失败 ${actionName} errorCode: $errorCode errorMessage:$errorMessage 当前重试${curragain}/${allagain}") + if (allagain > 0 && curragain < allagain){ //重试机制 + Log.d(TAG, "重试 ${actionName} 当前重试${curragain+1}/${allagain}") + executeSearchbackAction(actionName,curragain+1,allagain,action)(callback) + }else{ + handler.post { + callback(Result.failure(Exception("$actionName 失败: $errorMessage"))) + } } } + }) + } + override fun onError(errorCode: Int, errorMessage: String) { + Log.d(TAG, "失败 ${actionName} errorCode: $errorCode errorMessage:$errorMessage 当前重试${curragain}/${allagain}") + if (allagain > 0 && curragain < allagain){ //重试机制 + Log.d(TAG, "重试 ${actionName} 当前重试${curragain+1}/${allagain}") + executeSearchbackAction(actionName,curragain+1,allagain,action)(callback) + }else{ + handler.post { + callback(Result.failure(Exception("$actionName 失败: $errorMessage"))) + } } - }) - - } + } + }) } @@ -491,49 +522,80 @@ class QQMusicSingleton private constructor() { callback(Result.failure(Exception("Activity not available"))) return@lambda } - Log.d(TAG, "开始 ${actionName}") - ensureMusicManager(currentActivity,object: QQMusicManager. BindCallback{ - override fun onSuccess(){ - action(musicManager!!, object : QQMusicManager.PlayCallback { - override fun onSuccess() { - Log.d(TAG, "${actionName}成功") - handler.post { - callback(Result.success(Unit)) - } + + // 添加登录状态检查 + if (!isLoggedIn()) { + Log.d(TAG, "用户未登录,开始自动登录") + login { loginResult -> + if (loginResult.isSuccess) { + Log.d(TAG, "自动登录成功,继续执行 ${actionName}") + // 登录成功后继续执行原操作 + executePlayAction(actionName, curragain, allagain, action, callback) + } else { + Log.e(TAG, "自动登录失败: ${loginResult.exceptionOrNull()?.message}") + callback(Result.failure(Exception("用户未登录且自动登录失败: ${loginResult.exceptionOrNull()?.message}"))) + } + } + return@lambda + } + + // 用户已登录,直接执行搜索操作 + executePlayAction(actionName, curragain, allagain, action, callback) + + } + } + + private fun executePlayAction( + actionName: String, + curragain:Int, + allagain:Int, + action: (QQMusicManager, QQMusicManager.PlayCallback) -> Unit, + callback: (Result) -> Unit + ) { + Log.d(TAG, "开始 ${actionName}") + ensureMusicManager(context!!,object: QQMusicManager. BindCallback{ + override fun onSuccess(){ + action(musicManager!!, object : QQMusicManager.PlayCallback { + override fun onSuccess() { + Log.d(TAG, "${actionName}成功") + handler.post { + callback(Result.success(Unit)) } + } - override fun onError(errorCode: Int, errorMessage: String) { - if (allagain > 0 && curragain < allagain){ //重试机制 - executePlaybackAction(actionName,curragain+1,allagain,action) - }else{ - handler.post { - Log.e(TAG, "${actionName}失败: $errorCode $errorMessage") - if (errorCode == -1){ - musicManager?.bindQQMusicApiService() - callback(Result.failure(Exception("播放失败: $errorMessage"))) - } else if (errorCode == 1030) { - callback(Result.success(Unit)) - }else{ - callback(Result.failure(Exception("播放失败: $errorMessage"))) - } + override fun onError(errorCode: Int, errorMessage: String) { + if (allagain > 0 && curragain < allagain){ //重试机制 + executePlaybackAction(actionName,curragain+1,allagain,action)(callback) + }else{ + handler.post { + Log.e(TAG, "${actionName}失败: $errorCode $errorMessage") + if (errorCode == -1){ + musicManager?.bindQQMusicApiService() + callback(Result.failure(Exception("播放失败: $errorMessage"))) + } else if (errorCode == 1030) { + callback(Result.success(Unit)) + }else{ + callback(Result.failure(Exception("播放失败: $errorMessage"))) } } } - }) - } - override fun onError(errorCode: Int, errorMessage: String) { - Log.e(TAG, "${actionName}失败: $errorCode $errorMessage") - if (allagain > 0 && curragain < allagain){ //重试机制 - executePlaybackAction(actionName,curragain+1,allagain,action) - }else{ - callback(Result.failure(Exception("$actionName 失败: $errorMessage"))) } + }) + } + override fun onError(errorCode: Int, errorMessage: String) { + Log.e(TAG, "${actionName}失败: $errorCode $errorMessage") + if (allagain > 0 && curragain < allagain){ //重试机制 + executePlaybackAction(actionName,curragain+1,allagain,action)(callback) + }else{ + callback(Result.failure(Exception("$actionName 失败: $errorMessage"))) } - }) + } + }) - } } - + + + private fun executeInfoAction( actionName: String, action: (QQMusicManager, QQMusicManager.InfoCallback) -> Unit