Browse Source

Merge commit 'aa6dc6b1201aed677af55613841ba06d3022939d' into new_dev

weicu
lxm 1 year ago
parent
commit
f4411f69c4
  1. 38
      lib/modules/pairing/controllers/pairing_controller.dart
  2. 104
      local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt
  3. 44
      local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift
  4. 3
      local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift
  5. 24
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/ChatApiService.kt

38
lib/modules/pairing/controllers/pairing_controller.dart

@ -1,18 +1,17 @@
import 'dart:io';
import 'dart:async';
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 'package:url_launcher/url_launcher.dart';
import '../../../routes/app_routes.dart';
import '../../../core/utils/logger.dart';
import '/data/models/appconfig_model.dart';
import '/data/models/appconfig.dart';
import '/data/models/user_Info.dart';
import '/data/services/network/api.dart';
import 'dart:io';
import '../../../data/services/bluetooth_manager.dart';
import '../../../data/services/ble_manager.dart';
import '../../../core/utils/permission_util.dart';
@ -348,7 +347,7 @@ class PairingController extends GetxController with WidgetsBindingObserver {
void _handleBleStateChange(int state) {
if (_currentState.value == PairingState.waitingBle) {
if (state == 2) {
// 2代表BLE已连接
// BLE已连接
_bleTimeoutTimer?.cancel();
_transition(PairingState.completed);
}
@ -502,33 +501,32 @@ class PairingController extends GetxController with WidgetsBindingObserver {
/// 检查当前状态并决定下一步
void _checkCurrentStatus() async {
try {
// 1. 并行检查蓝牙状态、权限、设备连接
// 1. 检查蓝牙状态
final results = await Future.wait([
_checkBluetoothState(), // 检查蓝牙是否开启
_checkPermissions(), // 检查蓝牙相关权限
_bluetoothManager.refreshDeviceConnection(), // 刷新设备连接状态
_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;
}
// 2. 先刷新设备连接状态,确保获取最新的连接信息
//await _bluetoothManager.refreshDeviceConnection();
// 3. 先刷新设备连接状态,确保获取最新的连接信息
await _bluetoothManager.refreshDeviceConnection();
// 3. 检查经典蓝牙连接
// 4. 检查经典蓝牙连接
final classicDevice = _bluetoothManager.currentDevice;
if (classicDevice == null) {
_transition(PairingState.waitingClassic);
@ -545,7 +543,7 @@ class PairingController extends GetxController with WidgetsBindingObserver {
}
}
/// 检查蓝牙状态是否开启
/// 新增一个辅助方法来检查蓝牙状态
Future<bool> _checkBluetoothState() async {
return _bluetoothManager.bluetoothState != 'off';
}
@ -729,7 +727,7 @@ class PairingController extends GetxController with WidgetsBindingObserver {
// 检查设备名称是否包含 DeepSound 或 DeapSound
final deviceName = device.name;
DBProduct? product;
// 检查是否已有BLE绑定的设备
/// 检查是否已有BLE绑定的设备
if (AppConfig.config.products.isNotEmpty) {
final match = AppConfig.config.products.where(
@ -898,7 +896,7 @@ class PairingController extends GetxController with WidgetsBindingObserver {
await Future.delayed(Duration(seconds: 1));
}
_bleManager.stopScan();
if (product != null && product.devicetype == 2) {
if (product != null && product.devicetype != 0) {
//ble设备 必须要扫描到结果
return 0;
} else {

104
local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleService.kt

@ -140,6 +140,21 @@ object BleService {
// 初始化状态
private var isInitialized = false
/**
* 检查是否有蓝牙扫描权限
*/
private fun hasBluetoothScanPermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Android 12+ 需要 BLUETOOTH_SCAN 权限
context.checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) ==
android.content.pm.PackageManager.PERMISSION_GRANTED
} else {
// Android 12 以下使用 ACCESS_FINE_LOCATION 权限
context.checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) ==
android.content.pm.PackageManager.PERMISSION_GRANTED
}
}
// 音频数据统计相关变量
private var bytesReceivedInCurrentSecond = 0
@ -280,18 +295,22 @@ object BleService {
/**
* 开始主动扫描BLE设备
* @param uuids 要扫描的服务UUID列表
* @param timeout 扫描超时时间(毫秒)
* @return 是否成功开始扫描
*/
fun startScan(uuids: List<String>, timeout: Long = 15000): Boolean {
// Log.i(TAG, "liwei---------startScan 1 $deviceName")
if (!isInitialized) {
Log.e(TAG, "BLE服务未初始化")
return false
}
// Log.i(TAG, "liwei---------startScan 2")
// 获取一个局部引用,避免并发访问问题
// val scanner = bluetoothLeScanner ?: return false
// 检查蓝牙扫描权限
if (!hasBluetoothScanPermission()) {
Log.e(TAG, "开始扫描失败: 缺少 BLUETOOTH_SCAN 权限")
return false
}
// 💡 每次都重新取最新实例
val scanner = bluetoothLeScanner ?: run {
Log.e(TAG, "bluetoothLeScanner == null,尝试重启蓝牙")
@ -299,58 +318,65 @@ object BleService {
return false
}
// Log.i(TAG, "liwei---------startScan 3")
if (isScanning) return false
// Log.i(TAG, "liwei---------startScan 4")
Log.i(TAG, "开始主动扫描BLE设备...")
scanResults.clear()
// Log.i(TAG, "liwei---------startScan 5")
val filter = ScanFilter.Builder()
// .setServiceUuid(ParcelUuid(BleConst.PRIMARY_SERVICE_UUID))
// .setServiceUuid(ParcelUuid(java.util.UUID.fromString("00000201-0000-1000-8000-00805f9b34fb")))
.build()
// val filters = uuids.mapNotNull { uuidStr ->
// try {
// // 清理UUID字符串,移除非十六进制字符
// val cleanUuidStr = uuidStr.replace("[^0-9A-Fa-f]".toRegex(), "")
//
// // 验证清理后的字符串长度(应该是4位十六进制字符)
// if (cleanUuidStr.length != 4) {
// Log.w(TAG, "无效的UUID格式: $uuidStr,清理后: $cleanUuidStr,长度: ${cleanUuidStr.length}")
// return@mapNotNull null
// }
//
// val fullUuid = "0000$cleanUuidStr-0000-1000-8000-00805f9b34fb"
// Log.d(TAG, "扫描uuid: $fullUuid")
//
// ScanFilter.Builder()
// .setServiceUuid(ParcelUuid(UUID.fromString(fullUuid)))
// .build()
// } catch (e: IllegalArgumentException) {
// Log.e(TAG, "构造UUID失败: $uuidStr", e)
// null
// }
// }
// 构建扫描过滤器 - 参考 registerBackgroundScan 的实现
val filters = mutableListOf<ScanFilter>()
// 如果提供了额外的UUID,也添加到过滤器中
uuids.forEach { uuidStr ->
try {
val uuid = when {
uuidStr.length == 4 -> {
// 短UUID,转换为完整UUID
val fullUuid = "0000$uuidStr-0000-1000-8000-00805f9b34fb"
UUID.fromString(fullUuid)
}
uuidStr.length == 36 -> {
// 完整UUID
UUID.fromString(uuidStr)
}
else -> {
Log.w(TAG, "无效的UUID格式: $uuidStr")
return@forEach
}
}
val filter = ScanFilter.Builder()
//.setServiceUuid(ParcelUuid(uuid))
.build()
filters.add(filter)
Log.d(TAG, "添加扫描过滤器UUID: $uuid")
} catch (e: IllegalArgumentException) {
Log.e(TAG, "构造UUID失败: $uuidStr", e)
}
}
// 扫描设置 - 参考 registerBackgroundScan 的配置
val settings = ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_POWER)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) // 推荐:不会触发权限问题
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.setReportDelay(0)
.build()
// Log.i(TAG, "liwei---------startScan 7")
try {
scanner.startScan(listOf(filter), settings, scanCallback)
// 使用过滤器列表进行扫描
scanner.startScan(filters, settings, scanCallback)
isScanning = true
// Log.i(TAG, "liwei---------startScan 8")
// 设置扫描超时
scanHandler.postDelayed({
Log.d(TAG, "扫描超时,停止扫描")
stopScan()
}, timeout)
// Log.i(TAG, "liwei---------startScan 9")
Log.i(TAG, "已启动BLE扫描,过滤器数量: ${filters.size}")
return true
} catch (e: Exception) {
Log.e(TAG, "启动扫描失败: ${e.message}", e)
// Log.i(TAG, "liwei---------startScan 10")
isScanning = false
return false
}

44
local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleService.swift

@ -249,7 +249,10 @@ private var cmdReplyType: UInt8 = 0
clearPairedMacAddress()
}
/// 开始扫描BLE设备
public func startScan(timeout: TimeInterval = 30.0) -> Bool {
/// @param timeout 扫描超时时间,默认30秒
/// @param uuids 要扫描的服务UUID列表
/// @return 是否成功开始扫描
public func startScan(timeout: TimeInterval = 30.0, uuids: [String]) -> Bool {
if centralManager == nil {
initializeCentralManager()
}
@ -269,16 +272,43 @@ private var cmdReplyType: UInt8 = 0
isScanning = true
// // 移除服务UUID过滤,扫描所有设备
// manager.scanForPeripherals(withServices: nil, options: [
// 构建服务UUID数组进行过滤
var serviceUUIDs: [CBUUID] = []
// // 添加默认的服务UUID
// serviceUUIDs.append(BleConst.SERVICE_UUID)
// serviceUUIDs.append(BleConst.SERVICE_UUID1)
// 处理传入的UUID参数
for uuidStr in uuids {
do {
let cbuuid: CBUUID
if uuidStr.count == 4 {
// 短UUID,直接使用
cbuuid = CBUUID(string: uuidStr)
} else if uuidStr.count == 36 {
// 完整UUID
cbuuid = CBUUID(string: uuidStr)
} else {
os_log("⚠️ 无效的UUID格式: %{public}@", log: logger, type: .default, uuidStr)
continue
}
serviceUUIDs.append(cbuuid)
os_log("✅ 添加扫描过滤器UUID: %{public}@", log: logger, type: .info, uuidStr)
} catch {
os_log("❌ 构造UUID失败: %{public}@, 错误: %{public}@", log: logger, type: .error, uuidStr, error.localizedDescription)
}
}
// // 开始扫描,使用构建的服务UUID数组进行过滤
// manager.scanForPeripherals(withServices: serviceUUIDs.isEmpty ? nil : serviceUUIDs, options: [
// CBCentralManagerScanOptionAllowDuplicatesKey: true // 允许重复以获取更新的广播数据
// ])
let serviceUUIDs = [BleConst.SERVICE_UUID, BleConst.SERVICE_UUID1]
manager.scanForPeripherals(withServices: nil, options: [
manager.scanForPeripherals(withServices: nil , options: [
CBCentralManagerScanOptionAllowDuplicatesKey: true // 允许重复以获取更新的广播数据
])
os_log("🔍 开始扫描所有BLE设备(无过滤),超时时间: %.1f秒", log: logger, type: .info, timeout)
let filterInfo = serviceUUIDs.isEmpty ? "无过滤" : "过滤器数量: \(serviceUUIDs.count)"
os_log("🔍 开始扫描BLE设备(%{public}@),超时时间: %.1f秒", log: logger, type: .info, filterInfo, timeout)
// 设置扫描超时
scanTimer?.invalidate()

3
local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift

@ -112,9 +112,10 @@ public class SwiftBleServicePlugin: NSObject, FlutterPlugin {
case "startScan":
let arguments = call.arguments as? [String: Any]
let timeout = (arguments?["timeout"] as? Double) ?? 15.0
let uuids = (arguments?["uuids"] as? [String]) ?? []
os_log("🔍 开始传统BLE扫描,超时: %.1f秒", log: logger, type: .info, timeout)
BleService.shared.startScan(timeout: timeout)
BleService.shared.startScan(timeout: timeout, uuids: uuids)
result(true)
case "stopScan":

24
local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/ChatApiService.kt

@ -600,7 +600,29 @@ class ChatApiService(private val context: android.content.Context? = null) : Cor
_mcpClient?.parseJsonArguments(argumentsJson) ?: emptyMap()
}
// 调用MCP工具
val toolResult = _mcpClient?.callTool(functionName, arguments)
val toolResult = try {
withTimeout(60000) { // 60秒超时
_mcpClient?.callTool(functionName, arguments)
}
} catch (e: TimeoutCancellationException) {
Log.w("ChatApiService", "[Session: $sessionid] MCP工具调用超时: $functionName")
mapOf(
"content" to listOf(mapOf(
"type" to "text",
"text" to "Tool call timeout: $functionName"
)),
"isError" to true
)
} catch (e: Exception) {
Log.e("ChatApiService", "[Session: $sessionid] MCP工具调用异常: $functionName", e)
mapOf(
"content" to listOf(mapOf(
"type" to "text",
"text" to "Tool call failed: ${e.message}"
)),
"isError" to true
)
}
Log.d("ChatApiService", "[Session: $sessionid] AI调用工具结果: $functionName, 参数: $arguments, 结果: $toolResult")
// 处理结果
if (toolResult != null) {

Loading…
Cancel
Save