From d2d5b8614d2e9c9cdceeded3186c65a10a87945c Mon Sep 17 00:00:00 2001 From: fdp <1286779656@qq.com> Date: Wed, 24 Sep 2025 10:35:33 +0800 Subject: [PATCH] =?UTF-8?q?ble=E9=87=8D=E6=9E=84=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/pairing_controller.dart | 32 +- .../agent_service/BleMediaService.kt | 240 +++--- .../ble_service/BleCompanionManager.kt | 704 ++++++++++-------- .../ble_service/BleCompanionService.kt | 74 -- .../yunqiinnovation/ble_service/BleService.kt | 1 + .../ble_service/BleServicePlugin.kt | 54 +- .../ble_service/BootReceiver.kt | 12 +- 7 files changed, 570 insertions(+), 547 deletions(-) delete mode 100644 local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionService.kt diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index b3ff77b52..4d0b9f809 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -659,22 +659,22 @@ class PairingController extends GetxController with WidgetsBindingObserver { 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设备关联失败 - } + // 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, diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt index 97d2e9a1d..98c4af6c0 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/BleMediaService.kt @@ -8,8 +8,10 @@ import android.app.Service import android.content.Context import android.content.Intent import android.content.SharedPreferences +import android.content.res.AssetManager import android.os.Build import android.os.IBinder +import android.os.LocaleList import androidx.core.app.NotificationCompat import android.util.Log import kotlinx.coroutines.CoroutineScope @@ -21,6 +23,9 @@ import kotlin.coroutines.CoroutineContext import kotlinx.coroutines.Dispatchers import com.yunqiinnovation.ble_service.BleConst import com.yunqiinnovation.ble_service.BleService +import java.io.IOException +import java.util.Locale +import org.json.JSONObject /** * BLE代理服务 @@ -28,6 +33,7 @@ import com.yunqiinnovation.ble_service.BleService * 1. 语音代理初始化和管理 * 2. BLE设备连接管理 * 3. 后台扫描结果处理 + * 4. 自主配置获取和管理 */ class BleMediaService : Service(), CoroutineScope { @@ -48,12 +54,12 @@ class BleMediaService : Service(), CoroutineScope { private const val KEY_MCP_SERVER = "mcpServer" private const val KEY_VOLCANO_APP_ID = "volcanoAppId" private const val KEY_VOLCANO_TOKEN = "volcanoToken" - private const val KEY_SERVER_URL = "serverurl" private const val KEY_USER_TOKEN = "usertoken" private const val KEY_SUPPORTED_LANGUAGES = "supportedLanguages" private const val KEY_MUSICSERVICE_TYPE = "musicServiceType" private const val APP_NAVIGATION_MODE = "navigationMode" + // 用于跟踪服务是否正在运行 private val isRunning = AtomicBoolean(false) @@ -72,9 +78,6 @@ class BleMediaService : Service(), CoroutineScope { // 语音代理是否已初始化 private var isChatAgentInitialized = false - - // 当前启动Intent - private var currentIntent: Intent? = null override fun onCreate() { super.onCreate() @@ -90,9 +93,6 @@ class BleMediaService : Service(), CoroutineScope { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.i(TAG, "BleAgentService.onStartCommand: ${intent?.action}") - // 保存当前Intent,用于后续初始化 - currentIntent = intent - // 初始化语音代理 if (!isChatAgentInitialized) { initializeChatAgent() @@ -113,24 +113,14 @@ class BleMediaService : Service(), CoroutineScope { /** * 初始化语音交互代理 + * 自主获取配置参数,不依赖Flutter层传入 */ private fun initializeChatAgent() { try { - // 获取SharedPreferences - val prefs = applicationContext.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) - - // 尝试从Intent中获取参数 - val configFromIntent = extractConfigFromIntent(currentIntent) - - // 如果Intent中有参数,则保存到SharedPreferences - if (configFromIntent.isNotEmpty()) { - Log.d(TAG, "从Intent中获取到配置参数,保存到SharedPreferences") - saveConfigToPreferences(configFromIntent, prefs) - } + Log.i(TAG, "开始自主获取配置参数...") - // 合并Intent和SharedPreferences中的参数 - val config = getConfigFromPreferences(prefs) - Log.d(TAG, "当前配置参数: $config") + // 获取配置参数 + val config = getServiceConfig() // 检查必要的配置是否存在 val azureSpeechKey = config[KEY_AZURE_SPEECH_KEY]?.toString() ?: "" @@ -138,6 +128,8 @@ class BleMediaService : Service(), CoroutineScope { if (azureSpeechKey.isEmpty() || openaiApiKey.isEmpty()) { Log.w(TAG, "语音代理初始化失败: API密钥未配置") + Log.w(TAG, "Azure Speech Key: ${if (azureSpeechKey.isEmpty()) "未配置" else "已配置"}") + Log.w(TAG, "OpenAI API Key: ${if (openaiApiKey.isEmpty()) "未配置" else "已配置"}") return } @@ -148,7 +140,7 @@ class BleMediaService : Service(), CoroutineScope { if(config.isNotEmpty()) { // 初始化ChatAgent - Log.i(TAG, "开始初始化ChatAgent") + Log.i(TAG, "开始初始化ChatAgent,配置参数数量: ${config.size}") val success = BleAgent.initialize(applicationContext, config) if (success) { isChatAgentInitialized = true @@ -163,98 +155,145 @@ class BleMediaService : Service(), CoroutineScope { } /** - * 从Intent中提取配置参数 + * 自主获取服务配置 + * 从多个源获取配置参数:SharedPreferences、Assets、系统设置等 */ - private fun extractConfigFromIntent(intent: Intent?): Map { + private fun getServiceConfig(): Map { val config = mutableMapOf() - intent?.let { - // 提取可能存在的配置参数 - it.getStringExtra(KEY_AZURE_SPEECH_KEY)?.let { value -> config[KEY_AZURE_SPEECH_KEY] = value } - it.getStringExtra(KEY_AZURE_SPEECH_REGION)?.let { value -> config[KEY_AZURE_SPEECH_REGION] = value } - it.getStringExtra(KEY_OPENAI_API_KEY)?.let { value -> config[KEY_OPENAI_API_KEY] = value } - it.getStringExtra(KEY_OPENAI_BASE_URL)?.let { value -> config[KEY_OPENAI_BASE_URL] = value } - it.getStringExtra(KEY_OPENAI_MODEL)?.let { value -> config[KEY_OPENAI_MODEL] = value } - it.getStringExtra(KEY_OPENAI_VISION_MODEL)?.let { value -> config[KEY_OPENAI_VISION_MODEL] = value } - it.getStringExtra(KEY_SYSTEM_PROMPT)?.let { value -> config[KEY_SYSTEM_PROMPT] = value } - it.getStringExtra(KEY_MCP_SERVER)?.let { value -> config[KEY_MCP_SERVER] = value } - it.getStringExtra(KEY_VOLCANO_APP_ID)?.let { value -> config[KEY_VOLCANO_APP_ID] = value } - it.getStringExtra(KEY_VOLCANO_TOKEN)?.let { value -> config[KEY_VOLCANO_TOKEN] = value } - it.getStringExtra(KEY_SERVER_URL)?.let { value -> config[KEY_SERVER_URL] = value } - it.getStringExtra(KEY_USER_TOKEN)?.let { value -> config[KEY_USER_TOKEN] = value } - it.getStringExtra(KEY_MUSICSERVICE_TYPE)?.let { value -> config[KEY_MUSICSERVICE_TYPE] = value } - it.getStringExtra(APP_NAVIGATION_MODE)?.let { value -> config[APP_NAVIGATION_MODE] = value } - // 提取 supportedLanguages 参数 - it.getStringArrayListExtra(KEY_SUPPORTED_LANGUAGES)?.let { languages -> - if (languages.isNotEmpty()) { - config[KEY_SUPPORTED_LANGUAGES] = languages - } + + try { + // 1. 从SharedPreferences获取基础配置 + val prefs = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) + + // 添加字符串类型的配置参数(使用默认值) + config[KEY_AZURE_SPEECH_KEY] = getConfigString(prefs, KEY_AZURE_SPEECH_KEY, "") + config[KEY_AZURE_SPEECH_REGION] = getConfigString(prefs, KEY_AZURE_SPEECH_REGION, "eastasia") + config[KEY_OPENAI_API_KEY] = getConfigString(prefs, KEY_OPENAI_API_KEY, "") + config[KEY_OPENAI_BASE_URL] = getConfigString(prefs, KEY_OPENAI_BASE_URL, "https://api.openai.com/v1") + config[KEY_OPENAI_MODEL] = getConfigString(prefs, KEY_OPENAI_MODEL, "gpt-3.5-turbo") + config[KEY_OPENAI_VISION_MODEL] = getConfigString(prefs, KEY_OPENAI_VISION_MODEL, "gpt-4-vision-preview") + config[KEY_SYSTEM_PROMPT] = getConfigString(prefs, KEY_SYSTEM_PROMPT, "") + config[KEY_VOLCANO_APP_ID] = getConfigString(prefs, KEY_VOLCANO_APP_ID, "2316081933") + config[KEY_VOLCANO_TOKEN] = getConfigString(prefs, KEY_VOLCANO_TOKEN, "mcJTh6OelBqU_L78lgGd77Nyrc_-5-En") + config[KEY_SERVER_URL] = getConfigString(prefs, KEY_SERVER_URL, "") + config[KEY_USER_TOKEN] = getConfigString(prefs, KEY_USER_TOKEN, "") + config[KEY_MUSICSERVICE_TYPE] = getConfigString(prefs, KEY_MUSICSERVICE_TYPE, "AUTO") + config[APP_NAVIGATION_MODE] = getConfigString(prefs, APP_NAVIGATION_MODE, "external_auto") + + // 2. 从Assets获取MCP配置 + val mcpConfig = loadMcpConfigFromAssets() + if (mcpConfig.isNotEmpty()) { + config[KEY_MCP_SERVER] = mcpConfig + Log.d(TAG, "成功从Assets加载MCP配置") + } else { + Log.w(TAG, "未能从Assets加载MCP配置,使用空配置") + config[KEY_MCP_SERVER] = "{\"mcpServers\":{}}" } + + // 3. 获取系统语言配置 + val supportedLanguages = getSystemSupportedLanguages() + config[KEY_SUPPORTED_LANGUAGES] = supportedLanguages + Log.d(TAG, "系统支持的语言: ${supportedLanguages.joinToString(", ")}") + + Log.d(TAG, "配置获取完成,参数数量: ${config.size}") + + } catch (e: Exception) { + Log.e(TAG, "获取服务配置时发生异常", e) } - Log.i(TAG, "从Intent中提取到配置参数: $config") + return config } /** - * 将配置参数保存到SharedPreferences + * 从Assets目录加载MCP配置文件 */ - private fun saveConfigToPreferences(config: Map, prefs: SharedPreferences) { - prefs.edit().apply { - config.forEach { (key, value) -> - when (value) { - is String -> { - if (value.isNotEmpty()) { - putString(key, value) - } - } - is List<*> -> { - // 处理 supportedLanguages 列表 - if (key == KEY_SUPPORTED_LANGUAGES) { - val languageList = value.filterIsInstance() - if (languageList.isNotEmpty()) { - // 将语言列表转换为逗号分隔的字符串保存 - putString(key, languageList.joinToString(",")) - } - } - } - } - } - apply() + private fun loadMcpConfigFromAssets(): String { + return try { + val assetManager: AssetManager = assets + val inputStream = assetManager.open(".mcp.json") + val size = inputStream.available() + val buffer = ByteArray(size) + inputStream.read(buffer) + inputStream.close() + val jsonString = String(buffer, Charsets.UTF_8) + Log.d(TAG, "成功从Assets加载.mcp.json文件") + jsonString + } catch (e: IOException) { + Log.w(TAG, "无法从Assets加载.mcp.json文件: ${e.message}") + // 返回默认的空MCP配置 + "{\"mcpServers\":{}}" } } /** - * 从SharedPreferences获取配置 + * 获取系统支持的语言列表 + * 根据系统当前语言设置动态配置语音识别语言 */ - private fun getConfigFromPreferences(prefs: SharedPreferences): Map { - val config = mutableMapOf() - - // 添加字符串类型的配置参数 - config[KEY_AZURE_SPEECH_KEY] = getConfigString(prefs, KEY_AZURE_SPEECH_KEY, "") - config[KEY_AZURE_SPEECH_REGION] = getConfigString(prefs, KEY_AZURE_SPEECH_REGION, "eastasia") - config[KEY_OPENAI_API_KEY] = getConfigString(prefs, KEY_OPENAI_API_KEY, "") - config[KEY_OPENAI_BASE_URL] = getConfigString(prefs, KEY_OPENAI_BASE_URL, "https://api.openai.com/v1") - config[KEY_OPENAI_MODEL] = getConfigString(prefs, KEY_OPENAI_MODEL, "gpt-3.5-turbo") - config[KEY_OPENAI_VISION_MODEL] = getConfigString(prefs, KEY_OPENAI_VISION_MODEL, "gpt-4-vision-preview") - config[KEY_SYSTEM_PROMPT] = getConfigString(prefs, KEY_SYSTEM_PROMPT, "gpt-3.5-turbo") - config[KEY_MCP_SERVER] = getConfigString(prefs, KEY_MCP_SERVER, "") - config[KEY_VOLCANO_APP_ID] = getConfigString(prefs, KEY_VOLCANO_APP_ID, "") - config[KEY_VOLCANO_TOKEN] = getConfigString(prefs, KEY_VOLCANO_TOKEN, "") - config[KEY_SERVER_URL] = getConfigString(prefs, KEY_SERVER_URL, "") - config[KEY_USER_TOKEN] = getConfigString(prefs, KEY_USER_TOKEN, "") - config[KEY_MUSICSERVICE_TYPE] = getConfigString(prefs, KEY_MUSICSERVICE_TYPE, "") - config[APP_NAVIGATION_MODE] = getConfigString(prefs, APP_NAVIGATION_MODE, "") - - // 添加 supportedLanguages 参数处理 - val supportedLanguagesStr = getConfigString(prefs, KEY_SUPPORTED_LANGUAGES, "") - if (supportedLanguagesStr.isNotEmpty()) { - // 将逗号分隔的字符串转换回语言列表 - val languageList = supportedLanguagesStr.split(",").map { it.trim() }.filter { it.isNotEmpty() } - if (languageList.isNotEmpty()) { - config[KEY_SUPPORTED_LANGUAGES] = languageList + private fun getSystemSupportedLanguages(): List { + val supportedLanguages = mutableListOf() + + try { + // 获取系统当前语言设置 + val currentLocale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + LocaleList.getDefault().get(0) + } else { + @Suppress("DEPRECATION") + Locale.getDefault() + } + + val language = currentLocale.language + val country = currentLocale.country + + // 构造Azure Speech SDK需要的语言格式 + when (language) { + "zh" -> { + when (country) { + "CN" -> supportedLanguages.add("zh-CN") + "TW" -> supportedLanguages.add("zh-TW") + "HK" -> supportedLanguages.add("zh-HK") + else -> supportedLanguages.add("zh-CN") // 默认简体中文 + } + } + "en" -> { + when (country) { + "US" -> supportedLanguages.add("en-US") + "GB" -> supportedLanguages.add("en-GB") + "AU" -> supportedLanguages.add("en-AU") + "CA" -> supportedLanguages.add("en-CA") + else -> supportedLanguages.add("en-US") // 默认美式英语 + } + } + "ja" -> supportedLanguages.add("ja-JP") + "ko" -> supportedLanguages.add("ko-KR") + "fr" -> supportedLanguages.add("fr-FR") + "de" -> supportedLanguages.add("de-DE") + "es" -> supportedLanguages.add("es-ES") + "it" -> supportedLanguages.add("it-IT") + "pt" -> supportedLanguages.add("pt-BR") + "ru" -> supportedLanguages.add("ru-RU") + else -> { + // 对于不支持的语言,添加通用格式 + if (country.isNotEmpty()) { + supportedLanguages.add("$language-$country") + } else { + supportedLanguages.add("en-US") // 最终兜底 + } + } + } + + // 确保至少有一个语言 + if (supportedLanguages.isEmpty()) { + supportedLanguages.add("en-US") } + + Log.d(TAG, "检测到系统语言: $language-$country,配置语音识别语言: ${supportedLanguages.joinToString(", ")}") + + } catch (e: Exception) { + Log.e(TAG, "获取系统语言配置失败,使用默认语言: $e") + supportedLanguages.add("en-US") } - - return config + + return supportedLanguages } /** @@ -278,6 +317,9 @@ class BleMediaService : Service(), CoroutineScope { super.onDestroy() } + /** + * 检查BLE连接状态并尝试连接 + */ private fun checkBleConnection() { Log.i(TAG, "checkBleConnection收到连接请求") @@ -335,4 +377,4 @@ class BleMediaService : Service(), CoroutineScope { return builder.build() } -} \ No newline at end of file +} \ No newline at end of file diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionManager.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionManager.kt index 52f7e2acd..83756adaf 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionManager.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionManager.kt @@ -34,6 +34,7 @@ class BleCompanionManager(private val context: Context) { private const val PREF_NAME = "ble_companion_prefs" private const val KEY_ASSOCIATION_IDS = "association_ids" private const val KEY_PAIRED_MAC = "paired_mac" + private const val KEY_PAIRED_UUID = "paired_uuid" } // 会话保存 @@ -43,7 +44,21 @@ class BleCompanionManager(private val context: Context) { // 用于验证的临时MAC地址 private var pendingMacAddress: String? = null - + // 创建PendingIntent + // 创建PendingIntent + val scanIntent = Intent(BleConst.ACTION_SCAN_RESULT) + .setClass(context, BleWakeReceiver::class.java) + + val pendingIntent = PendingIntent.getBroadcast( + context, + 0, + scanIntent, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE + } else { + PendingIntent.FLAG_UPDATE_CURRENT + } + ) /** * 获取CompanionDeviceManager服务(使用Activity上下文) */ @@ -63,313 +78,344 @@ class BleCompanionManager(private val context: Context) { } /** - * 获取已关联的设备MAC地址 + * 获取已连接的设备MAC地址 */ fun getPairedMacAddress(): String? { return sharedPreferences.getString(KEY_PAIRED_MAC, null) } - - /** - * 保存已关联的设备MAC地址 - */ - fun savePairedMacAddress(macAddress: String) { - sharedPreferences.edit().putString(KEY_PAIRED_MAC, macAddress).apply() - Log.i(TAG, "已保存配对设备MAC: $macAddress") - } - - /** - * 清除已关联的设备MAC地址 + /** + * 保存连接的设备UUID */ - fun clearPairedMacAddress() { - sharedPreferences.edit().remove(KEY_PAIRED_MAC).apply() - Log.i(TAG, "已清除配对设备MAC") - } - - /** - * 检查是否有已关联的设备 - */ - @RequiresApi(Build.VERSION_CODES.O) - fun hasAssociations(): Boolean { - val associationIds = getAssociationIds() - return associationIds.isNotEmpty() - } - /** - * 获取所有关联ID + * 保存连接的设备UUID列表 + * 将UUID列表转换为JSON字符串进行存储 */ - @RequiresApi(Build.VERSION_CODES.O) - fun getAssociationIds(): List { - // 使用默认上下文获取CompanionDeviceManager - val companionDeviceManager = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.getSystemService(Context.COMPANION_DEVICE_SERVICE) as? CompanionDeviceManager - } else { - null + fun savePairedUuid(uuids: List) { + if (uuids.isNotEmpty()) { + // 将列表转换为JSON字符串格式进行存储 + val uuidsJson = uuids.joinToString(",") { "\"$it\"" } + val jsonString = "[$uuidsJson]" + sharedPreferences.edit().putString(KEY_PAIRED_UUID, jsonString).apply() + Log.i(TAG, "已保存连接设备UUID列表: $uuids") } - return getAssociationIds(companionDeviceManager) } - + /** - * 获取所有关联ID(使用指定的CompanionDeviceManager) + * 获取已连接的设备UUID列表 + * 从JSON字符串解析为UUID列表 */ - @RequiresApi(Build.VERSION_CODES.O) - private fun getAssociationIds(companionDeviceManager: CompanionDeviceManager?): List { - if (companionDeviceManager == null) { - return emptyList() - } - - // 注意: allAssociations 仅在API 33 (Android 13)及以上版本可用 - // 在早期版本中,使用associations (返回的是String数组) - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + fun getPairedUuid(): List { + val jsonString = sharedPreferences.getString(KEY_PAIRED_UUID, null) + return if (!jsonString.isNullOrEmpty()) { try { - // 由于AssociationInfo类在API 30+引入,使用反射获取更安全 - val method = CompanionDeviceManager::class.java.getMethod("getAllAssociations") - @Suppress("UNCHECKED_CAST") - val associations = method.invoke(companionDeviceManager) as? List - associations?.map { association -> - // 尝试获取AssociationInfo.id - val idField = association.javaClass.getField("id") - idField.get(association).toString() - } ?: emptyList() + // 简单的JSON解析,移除方括号和引号,然后分割 + jsonString.trim('[', ']') + .split(",") + .map { it.trim().trim('"') } + .filter { it.isNotEmpty() } } catch (e: Exception) { - Log.e(TAG, "获取关联ID失败: ${e.message}", e) + Log.e(TAG, "解析UUID列表失败: ${e.message}") emptyList() } } else { - // API 26-32 使用 associations 方法 - companionDeviceManager.associations?.toList() ?: emptyList() + emptyList() } } + + + /** + * 保存连接的设备MAC地址 + */ + fun savePairedMacAddress(macAddress: String) { + sharedPreferences.edit().putString(KEY_PAIRED_MAC, macAddress).apply() + Log.i(TAG, "已保存连接设备MAC: $macAddress") + } /** - * 开始设备关联流程 - * - * @param activity 当前Activity,用于启动系统关联对话框 - * @param deviceNamePattern 设备名称正则表达式,例如"MyHeadset.*" - * @param serviceUuid 可选的服务UUID - * @param macAddress 可选的MAC地址 + * 清除已连接的设备MAC地址 */ - @RequiresApi(Build.VERSION_CODES.O) - fun startAssociation( - activity: Activity, - deviceNamePattern: String? = null, - serviceUuid: String? = null, - macAddress: String? = null - ): Boolean { - // 使用Activity上下文获取CompanionDeviceManager - val companionDeviceManager = getCompanionDeviceManager(activity) - if (companionDeviceManager == null) { - Log.e(TAG, "设备不支持CompanionDeviceManager") - return false - } + fun clearPairedMacAddress() { + sharedPreferences.edit().remove(KEY_PAIRED_MAC).apply() + Log.i(TAG, "已清除连接设备MAC") + } + + // /** + // * 检查是否有已关联的设备 + // */ + // @RequiresApi(Build.VERSION_CODES.O) + // fun hasAssociations(): Boolean { + // val associationIds = getAssociationIds() + // return associationIds.isNotEmpty() + // } + + // /** + // * 获取所有关联ID + // */ + // @RequiresApi(Build.VERSION_CODES.O) + // fun getAssociationIds(): List { + // // 使用默认上下文获取CompanionDeviceManager + // val companionDeviceManager = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // context.getSystemService(Context.COMPANION_DEVICE_SERVICE) as? CompanionDeviceManager + // } else { + // null + // } + // return getAssociationIds(companionDeviceManager) + // } + + // /** + // * 获取所有关联ID(使用指定的CompanionDeviceManager) + // */ + // @RequiresApi(Build.VERSION_CODES.O) + // private fun getAssociationIds(companionDeviceManager: CompanionDeviceManager?): List { + // if (companionDeviceManager == null) { + // return emptyList() + // } - try { - // 构建设备过滤器 - val deviceFilterBuilder = BluetoothDeviceFilter.Builder() + // // 注意: allAssociations 仅在API 33 (Android 13)及以上版本可用 + // // 在早期版本中,使用associations (返回的是String数组) + // return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // try { + // // 由于AssociationInfo类在API 30+引入,使用反射获取更安全 + // val method = CompanionDeviceManager::class.java.getMethod("getAllAssociations") + // @Suppress("UNCHECKED_CAST") + // val associations = method.invoke(companionDeviceManager) as? List + // associations?.map { association -> + // // 尝试获取AssociationInfo.id + // val idField = association.javaClass.getField("id") + // idField.get(association).toString() + // } ?: emptyList() + // } catch (e: Exception) { + // Log.e(TAG, "获取关联ID失败: ${e.message}", e) + // emptyList() + // } + // } else { + // // API 26-32 使用 associations 方法 + // companionDeviceManager.associations?.toList() ?: emptyList() + // } + // } + + // /** + // * 开始设备关联流程 + // * + // * @param activity 当前Activity,用于启动系统关联对话框 + // * @param deviceNamePattern 设备名称正则表达式,例如"MyHeadset.*" + // * @param serviceUuid 可选的服务UUID + // * @param macAddress 可选的MAC地址 + // */ + // @RequiresApi(Build.VERSION_CODES.O) + // fun startAssociation( + // activity: Activity, + // deviceNamePattern: String? = null, + // serviceUuid: String? = null, + // macAddress: String? = null + // ): Boolean { + // // 使用Activity上下文获取CompanionDeviceManager + // val companionDeviceManager = getCompanionDeviceManager(activity) + // if (companionDeviceManager == null) { + // Log.e(TAG, "设备不支持CompanionDeviceManager") + // return false + // } + + // try { + // // 构建设备过滤器 + // val deviceFilterBuilder = BluetoothDeviceFilter.Builder() - // 添加设备名称 - 严格匹配模式 - deviceNamePattern?.let { - // 使用"^设备名称$"格式创建精确匹配的正则表达式 - val exactNamePattern = Pattern.compile("^$it$") - deviceFilterBuilder.setNamePattern(exactNamePattern) - Log.i(TAG, "设置严格名称匹配: $it") - } + // // 添加设备名称 - 严格匹配模式 + // deviceNamePattern?.let { + // // 使用"^设备名称$"格式创建精确匹配的正则表达式 + // val exactNamePattern = Pattern.compile("^$it$") + // deviceFilterBuilder.setNamePattern(exactNamePattern) + // Log.i(TAG, "设置严格名称匹配: $it") + // } - // 添加服务UUID - serviceUuid?.let { - try { - val uuid = ParcelUuid(java.util.UUID.fromString(it)) - deviceFilterBuilder.addServiceUuid(uuid, null) - Log.i(TAG, "设置服务UUID匹配: $it") - } catch (e: Exception) { - Log.e(TAG, "设置服务UUID失败: ${e.message}", e) - } - } + // // 添加服务UUID + // serviceUuid?.let { + // try { + // val uuid = ParcelUuid(java.util.UUID.fromString(it)) + // deviceFilterBuilder.addServiceUuid(uuid, null) + // Log.i(TAG, "设置服务UUID匹配: $it") + // } catch (e: Exception) { + // Log.e(TAG, "设置服务UUID失败: ${e.message}", e) + // } + // } - // 添加MAC地址 - 严格匹配 - macAddress?.let { - try { - // 检查是否是有效的MAC地址格式 - if (!isValidMacAddress(it)) { - Log.e(TAG, "无效的MAC地址格式: $it") - return false - } + // // 添加MAC地址 - 严格匹配 + // macAddress?.let { + // try { + // // 检查是否是有效的MAC地址格式 + // if (!isValidMacAddress(it)) { + // Log.e(TAG, "无效的MAC地址格式: $it") + // return false + // } - // 存储MAC地址到临时变量,成功匹配后再保存 - pendingMacAddress = it + // // 存储MAC地址到临时变量,成功匹配后再保存 + // pendingMacAddress = it - // 设置MAC地址严格匹配 - deviceFilterBuilder.setAddress(it) - Log.i(TAG, "设置MAC地址严格匹配: $it") - } catch (e: Exception) { - Log.e(TAG, "设置MAC地址失败: ${e.message}", e) - return false - } - } ?: run { - // 如果没有提供MAC地址也没有提供设备名称,则返回错误 - if (deviceNamePattern == null && serviceUuid == null) { - Log.e(TAG, "严格匹配模式下必须提供MAC地址、设备名称或服务UUID之一") - return false - } - } + // // 设置MAC地址严格匹配 + // deviceFilterBuilder.setAddress(it) + // Log.i(TAG, "设置MAC地址严格匹配: $it") + // } catch (e: Exception) { + // Log.e(TAG, "设置MAC地址失败: ${e.message}", e) + // return false + // } + // } ?: run { + // // 如果没有提供MAC地址也没有提供设备名称,则返回错误 + // if (deviceNamePattern == null && serviceUuid == null) { + // Log.e(TAG, "严格匹配模式下必须提供MAC地址、设备名称或服务UUID之一") + // return false + // } + // } - // 创建请求 - val associationRequest = AssociationRequest.Builder() - .addDeviceFilter(deviceFilterBuilder.build()) - .setSingleDevice(true) // 找到一个即停止 - .build() + // // 创建请求 + // val associationRequest = AssociationRequest.Builder() + // .addDeviceFilter(deviceFilterBuilder.build()) + // .setSingleDevice(true) // 找到一个即停止 + // .build() - // 发起关联请求 - companionDeviceManager.associate( - associationRequest, - object : CompanionDeviceManager.Callback() { - override fun onDeviceFound(intentSender: IntentSender) { - try { - activity.startIntentSenderForResult( - intentSender, - REQUEST_CODE_ASSOCIATE, - null, - 0, - 0, - 0 - ) - Log.i(TAG, "已启动设备选择对话框") - } catch (e: Exception) { - Log.e(TAG, "启动设备选择对话框失败: ${e.message}", e) - } - } + // // 发起关联请求 + // companionDeviceManager.associate( + // associationRequest, + // object : CompanionDeviceManager.Callback() { + // override fun onDeviceFound(intentSender: IntentSender) { + // try { + // activity.startIntentSenderForResult( + // intentSender, + // REQUEST_CODE_ASSOCIATE, + // null, + // 0, + // 0, + // 0 + // ) + // Log.i(TAG, "已启动设备选择对话框") + // } catch (e: Exception) { + // Log.e(TAG, "启动设备选择对话框失败: ${e.message}", e) + // } + // } - // API 26 (Android 8) 使用 onDeviceFound - // API 28+ (Android 9+) 使用 onAssociationPending - @RequiresApi(Build.VERSION_CODES.P) - override fun onAssociationPending(intentSender: IntentSender) { - try { - activity.startIntentSenderForResult( - intentSender, - REQUEST_CODE_ASSOCIATE, - null, - 0, - 0, - 0 - ) - Log.i(TAG, "已启动设备选择对话框") - } catch (e: Exception) { - Log.e(TAG, "启动设备选择对话框失败: ${e.message}", e) - } - } + // // API 26 (Android 8) 使用 onDeviceFound + // // API 28+ (Android 9+) 使用 onAssociationPending + // @RequiresApi(Build.VERSION_CODES.P) + // override fun onAssociationPending(intentSender: IntentSender) { + // try { + // activity.startIntentSenderForResult( + // intentSender, + // REQUEST_CODE_ASSOCIATE, + // null, + // 0, + // 0, + // 0 + // ) + // Log.i(TAG, "已启动设备选择对话框") + // } catch (e: Exception) { + // Log.e(TAG, "启动设备选择对话框失败: ${e.message}", e) + // } + // } - // API 33+ (Android 13+) 使用 onAssociationCreated - @RequiresApi(Build.VERSION_CODES.TIRAMISU) - override fun onAssociationCreated(associationInfo: AssociationInfo) { - Log.i(TAG, "设备关联已创建: ${associationInfo.displayName}, ID: ${associationInfo.id}") - // 保存关联ID - try { - val macAddressMethod = associationInfo.javaClass.getMethod("getDeviceMacAddress") - val mac = macAddressMethod.invoke(associationInfo) as? String - mac?.let { savePairedMacAddress(it) } - } catch (e: Exception) { - Log.e(TAG, "获取设备MAC地址失败: ${e.message}", e) - } - } + // // API 33+ (Android 13+) 使用 onAssociationCreated + // @RequiresApi(Build.VERSION_CODES.TIRAMISU) + // override fun onAssociationCreated(associationInfo: AssociationInfo) { + // Log.i(TAG, "设备关联已创建: ${associationInfo.displayName}, ID: ${associationInfo.id}") + // // 保存关联ID + // try { + // val macAddressMethod = associationInfo.javaClass.getMethod("getDeviceMacAddress") + // val mac = macAddressMethod.invoke(associationInfo) as? String + // mac?.let { savePairedMacAddress(it) } + // } catch (e: Exception) { + // Log.e(TAG, "获取设备MAC地址失败: ${e.message}", e) + // } + // } - override fun onFailure(error: CharSequence?) { - Log.e(TAG, "设备关联失败: $error") - } - }, - null - ) + // override fun onFailure(error: CharSequence?) { + // Log.e(TAG, "设备关联失败: $error") + // } + // }, + // null + // ) - return true - } catch (e: Exception) { - Log.e(TAG, "启动设备关联失败: ${e.message}", e) - return false - } - } + // return true + // } catch (e: Exception) { + // Log.e(TAG, "启动设备关联失败: ${e.message}", e) + // return false + // } + // } - /** - * 处理关联结果 - * - * @param requestCode 请求码 - * @param resultCode 结果码 - * @param data Intent数据 - * @return 是否处理了关联结果 - */ - @RequiresApi(Build.VERSION_CODES.O) - fun handleAssociationResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { - if (requestCode != REQUEST_CODE_ASSOCIATE) { - return false - } + // /** + // * 处理关联结果 + // * + // * @param requestCode 请求码 + // * @param resultCode 结果码 + // * @param data Intent数据 + // * @return 是否处理了关联结果 + // */ + // @RequiresApi(Build.VERSION_CODES.O) + // fun handleAssociationResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { + // if (requestCode != REQUEST_CODE_ASSOCIATE) { + // return false + // } - Log.i(TAG, "收到关联结果: resultCode=$resultCode") + // Log.i(TAG, "收到关联结果: resultCode=$resultCode") - if (resultCode == Activity.RESULT_OK && data != null) { - // 获取选中的蓝牙设备 - val bluetoothDevice: BluetoothDevice? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - data.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE, BluetoothDevice::class.java) - } else { - @Suppress("DEPRECATION") - data.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE) - } + // if (resultCode == Activity.RESULT_OK && data != null) { + // // 获取选中的蓝牙设备 + // val bluetoothDevice: BluetoothDevice? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // data.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE, BluetoothDevice::class.java) + // } else { + // @Suppress("DEPRECATION") + // data.getParcelableExtra(CompanionDeviceManager.EXTRA_DEVICE) + // } - // 获取关联ID (Android 13+) - val associationId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - try { - // 由于EXTRA_ASSOCIATION_ID常量仅在API 33+可用,直接使用已知的常量字符串值 - // 不再尝试使用反射获取字段 - val extraAssociationIdKey = "android.companion.extra.ASSOCIATION_ID" - data.getStringExtra(extraAssociationIdKey) - } catch (e: Exception) { - Log.e(TAG, "获取关联ID失败: ${e.message}", e) - null - } - } else { - null - } + // // 获取关联ID (Android 13+) + // val associationId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // try { + // // 由于EXTRA_ASSOCIATION_ID常量仅在API 33+可用,直接使用已知的常量字符串值 + // // 不再尝试使用反射获取字段 + // val extraAssociationIdKey = "android.companion.extra.ASSOCIATION_ID" + // data.getStringExtra(extraAssociationIdKey) + // } catch (e: Exception) { + // Log.e(TAG, "获取关联ID失败: ${e.message}", e) + // null + // } + // } else { + // null + // } - // 获取并验证MAC地址 - if (bluetoothDevice != null) { - val deviceMac = bluetoothDevice.address - val deviceName = bluetoothDevice.name ?: "未知设备" + // bluetoothDevice?.let { device -> + // val deviceMac = device.address + // Log.i(TAG, "设备关联成功: ${device.name} ($deviceMac)") - // 验证MAC地址格式 - if (!isValidMacAddress(deviceMac)) { - Log.e(TAG, "设备 '$deviceName' 返回的MAC地址格式无效: $deviceMac") - return false - } - - // 检查是否与预期的MAC地址匹配 - if (pendingMacAddress != null && pendingMacAddress != deviceMac) { - Log.w(TAG, "选中的设备MAC地址 ($deviceMac) 与预期的MAC地址 ($pendingMacAddress) 不匹配") - // 如果要严格匹配MAC,可以在这里返回false - return false - } + // // 验证MAC地址是否匹配预期 + // pendingMacAddress?.let { expectedMac -> + // if (deviceMac.equals(expectedMac, ignoreCase = true)) { + // Log.i(TAG, "MAC地址验证成功: $deviceMac") + // } else { + // Log.w(TAG, "MAC地址不匹配: 预期=$expectedMac, 实际=$deviceMac") + // } + // } - // 匹配成功后,保存新的MAC地址 - savePairedMacAddress(deviceMac) - Log.i(TAG, "设备关联成功: $deviceName ($deviceMac), 关联ID: $associationId") + // // 保存设备MAC地址 + // savePairedMacAddress(deviceMac) - // 清除临时MAC地址 - pendingMacAddress = null + // // 保存关联ID (如果可用) + // associationId?.let { id -> + // Log.i(TAG, "保存关联ID: $id") + // // 这里可以保存关联ID到SharedPreferences或其他存储 + // } - // 🎯 立即发起BLE连接 - // try { - // Log.i(TAG, "配对成功,立即发起BLE连接: $deviceMac") - // BleService.connect(deviceMac) - // } catch (e: Exception) { - // Log.e(TAG, "配对成功后发起BLE连接失败: ${e.message}", e) - // } + // // 清除临时MAC地址 + // pendingMacAddress = null - return true - } else { - Log.e(TAG, "无法获取关联的蓝牙设备信息") - } - } else { - Log.w(TAG, "设备关联被取消或失败: resultCode=$resultCode") - // 清除临时MAC地址 - pendingMacAddress = null - } - - return false - } + // return true + // } ?: run { + // Log.e(TAG, "无法获取蓝牙设备信息") + // return false + // } + // } else { + // Log.w(TAG, "设备关联被取消或失败") + // // 清除临时MAC地址 + // pendingMacAddress = null + // return false + // } + // } /** * 注册后台扫描 @@ -382,12 +428,14 @@ class BleCompanionManager(private val context: Context) { ) { try { Log.d(TAG, "添加后台扫描过滤器UUID: $uuids, macAddress: $macAddress") - val mac = getPairedMacAddress() - if (mac.isNullOrEmpty()) { + //val mac = getPairedMacAddress() + + if (macAddress.isNullOrEmpty()||uuids.isNullOrEmpty()) { Log.e(TAG, "注册后台扫描失败: 没有配对的设备MAC地址") return } - + savePairedMacAddress(macAddress) + savePairedUuid(uuids) val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager val bluetoothAdapter = bluetoothManager?.adapter val bluetoothLeScanner = bluetoothAdapter?.bluetoothLeScanner @@ -440,24 +488,24 @@ class BleCompanionManager(private val context: Context) { .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) .build() - // 创建PendingIntent - val scanIntent = Intent(BleConst.ACTION_SCAN_RESULT) - .setClass(context, BleWakeReceiver::class.java) + // // 创建PendingIntent + // val scanIntent = Intent(BleConst.ACTION_SCAN_RESULT) + // .setClass(context, BleWakeReceiver::class.java) - val pendingIntent = PendingIntent.getBroadcast( - context, - 0, - scanIntent, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE - } else { - PendingIntent.FLAG_UPDATE_CURRENT - } - ) + // val pendingIntent = PendingIntent.getBroadcast( + // context, + // 0, + // scanIntent, + // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE + // } else { + // PendingIntent.FLAG_UPDATE_CURRENT + // } + // ) // 启动后台扫描 bluetoothLeScanner.startScan(filters, settings, pendingIntent) - Log.i(TAG, "已注册后台扫描,目标设备MAC: $mac") + Log.i(TAG, "已注册后台扫描,目标设备MAC: $macAddress") } catch (e: Exception) { Log.e(TAG, "注册后台扫描失败: ${e.message}", e) } @@ -477,20 +525,20 @@ class BleCompanionManager(private val context: Context) { return } - // 创建PendingIntent - val scanIntent = Intent(BleConst.ACTION_SCAN_RESULT) - .setClass(context, BleWakeReceiver::class.java) + // // 创建PendingIntent + // val scanIntent = Intent(BleConst.ACTION_SCAN_RESULT) + // .setClass(context, BleWakeReceiver::class.java) - val pendingIntent = PendingIntent.getBroadcast( - context, - 0, - scanIntent, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE - } else { - PendingIntent.FLAG_UPDATE_CURRENT - } - ) + // val pendingIntent = PendingIntent.getBroadcast( + // context, + // 0, + // scanIntent, + // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE + // } else { + // PendingIntent.FLAG_UPDATE_CURRENT + // } + // ) // 停止后台扫描 bluetoothLeScanner.stopScan(pendingIntent) @@ -500,42 +548,42 @@ class BleCompanionManager(private val context: Context) { } } - /** - * 清除所有关联 - */ - @RequiresApi(Build.VERSION_CODES.O) - fun clearAllAssociations() { - try { - // 获取CompanionDeviceManager - val companionDeviceManager = context.getSystemService(Context.COMPANION_DEVICE_SERVICE) as? CompanionDeviceManager - if (companionDeviceManager == null) { - Log.e(TAG, "无法获取CompanionDeviceManager") - return - } + // /** + // * 清除所有关联 + // */ + // @RequiresApi(Build.VERSION_CODES.O) + // fun clearAllAssociations() { + // try { + // // 获取CompanionDeviceManager + // val companionDeviceManager = context.getSystemService(Context.COMPANION_DEVICE_SERVICE) as? CompanionDeviceManager + // if (companionDeviceManager == null) { + // Log.e(TAG, "无法获取CompanionDeviceManager") + // return + // } - // 清除本地保存的MAC地址 - clearPairedMacAddress() + // // 清除本地保存的MAC地址 + // clearPairedMacAddress() - // 获取所有关联ID - val associationIds = getAssociationIds(companionDeviceManager) + // // 获取所有关联ID + // val associationIds = getAssociationIds(companionDeviceManager) - // 遍历解除关联 - for (id in associationIds) { - try { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - companionDeviceManager.disassociate(id) - } else { - companionDeviceManager.disassociate(id) - } - Log.i(TAG, "已解除设备关联: $id") - } catch (e: Exception) { - Log.e(TAG, "解除设备关联失败: $id, ${e.message}", e) - } - } - } catch (e: Exception) { - Log.e(TAG, "清除所有关联失败: ${e.message}", e) - } - } + // // 遍历解除关联 + // for (id in associationIds) { + // try { + // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + // companionDeviceManager.disassociate(id) + // } else { + // companionDeviceManager.disassociate(id) + // } + // Log.i(TAG, "已解除设备关联: $id") + // } catch (e: Exception) { + // Log.e(TAG, "解除设备关联失败: $id, ${e.message}", e) + // } + // } + // } catch (e: Exception) { + // Log.e(TAG, "清除所有关联失败: ${e.message}", e) + // } + // } /** * 验证是否是有效的MAC地址格式 diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionService.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionService.kt deleted file mode 100644 index 56104eca1..000000000 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleCompanionService.kt +++ /dev/null @@ -1,74 +0,0 @@ -package com.yunqiinnovation.ble_service - -import android.companion.AssociationInfo -import android.companion.CompanionDeviceService -import android.content.Intent -import android.os.Build -import android.os.IBinder -import androidx.annotation.RequiresApi -import android.util.Log - -/** - * BleCompanionService - * 用于监听配对设备的出现和消失 - * 注:此服务仅在Android 11 (API 30)及以上版本可用 - */ -@RequiresApi(Build.VERSION_CODES.R) -class BleCompanionService : CompanionDeviceService() { - private val TAG = "BleCompanionService" - - override fun onCreate() { - super.onCreate() - Log.i(TAG, "BleCompanionService已创建") - } - - override fun onDeviceAppeared(info: AssociationInfo) { - super.onDeviceAppeared(info) - Log.i(TAG, "检测到配对设备出现: ${info.displayName}, ID: ${info.id}") - - // 当配对设备出现时,启动前台服务 - try { - val serviceIntent = Intent().apply { - // 尝试使用BleMediaService,如果不存在则回退到BleService - val serviceClassName = try { - Log.d(TAG, "BleMediaService存在") - Class.forName("com.yunqiinnovation.agent_service.BleMediaService").name - } catch (e: ClassNotFoundException) { - Log.d(TAG, "BleMediaService不存在,回退到BleService") - BleService::class.java.name - } - - setClassName(this@BleCompanionService, serviceClassName) - action = "android.intent.action.DEVICE_APPEARED" - putExtra("assocId", info.id) - putExtra("displayName", info.displayName) - - // 如果设备信息中有MAC地址,也可以传递 - // 使用反射获取MAC地址,因为deviceMacAddress在不同API版本可能不同或不存在 - try { - val macAddressMethod = info.javaClass.getMethod("getDeviceMacAddress") - val mac = macAddressMethod.invoke(info) as? String - mac?.let { putExtra("mac", it) } - } catch (e: Exception) { - Log.e(TAG, "获取设备MAC地址失败: ${e.message}", e) - } - } - - // 启动前台服务 - startForegroundService(serviceIntent) - Log.i(TAG, "已启动服务") - } catch (e: Exception) { - Log.e(TAG, "启动服务失败: ${e.message}", e) - } - } - - override fun onDeviceDisappeared(info: AssociationInfo) { - super.onDeviceDisappeared(info) - Log.i(TAG, "配对设备消失: ${info.displayName}, ID: ${info.id}") - - // 可以选择停止服务或执行其他清理操作 - } - - // 注意: 不需要重写 onBindCompanionDeviceService 和 onUnbindCompanionDeviceService - // 这些方法在 Android 12+ 才添加,我们可以使用父类的默认实现 -} \ No newline at end of file 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 375807025..12bf9f64e 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 @@ -520,6 +520,7 @@ object BleService { */ fun connect() { try { + Log.i(TAG, "设备连接与通信: 自动连接已配对的BLE设备") // 创建 BleCompanionManager 实例 val companionManager = BleCompanionManager(context) diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt index edafa1b57..c718f87eb 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BleServicePlugin.kt @@ -123,21 +123,21 @@ class BleServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware, // 实现ActivityResultListener接口 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { - // 处理设备关联结果 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val handled = bleCompanionManager.handleAssociationResult(requestCode, resultCode, data) - if (handled) { - // 返回设备关联结果 - pendingAssociationResult?.success(true) - pendingAssociationResult = null - return true - } else { - pendingAssociationResult?.success(false) - pendingAssociationResult = null - return true - } - } - return false + // // 处理设备关联结果 + // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + // val handled = bleCompanionManager.handleAssociationResult(requestCode, resultCode, data) + // if (handled) { + // // 返回设备关联结果 + // pendingAssociationResult?.success(true) + // pendingAssociationResult = null + // return true + // } else { + // pendingAssociationResult?.success(false) + // pendingAssociationResult = null + // return true + // } + // } + return true } // 添加sendEvent函数 @@ -247,18 +247,18 @@ class BleServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware, return } - // 启动设备关联 - val success = bleCompanionManager.startAssociation( - currentActivity, - deviceNamePattern, - serviceUuid, - macAddress - ) + // // 启动设备关联 + // val success = bleCompanionManager.startAssociation( + // currentActivity, + // deviceNamePattern, + // serviceUuid, + // macAddress + // ) - if (!success) { - pendingAssociationResult = null - result.error("FAILED", "启动设备关联失败", null) - } + // if (!success) { + // pendingAssociationResult = null + // result.error("FAILED", "启动设备关联失败", null) + // } // 不要立即返回结果,等待onActivityResult回调 } "getPairedMacAddress" -> { @@ -304,7 +304,7 @@ class BleServicePlugin : FlutterPlugin, MethodCallHandler, ActivityAware, } "clearAssociations" -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - bleCompanionManager.clearAllAssociations() + // bleCompanionManager.clearAllAssociations() result.success(true) } else { result.error("UNSUPPORTED", "设备不支持Companion Device Manager", null) diff --git a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BootReceiver.kt b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BootReceiver.kt index fca18fa9d..4ee7223c8 100644 --- a/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BootReceiver.kt +++ b/local_plugins/ble_service/android/src/main/kotlin/com/yunqiinnovation/ble_service/BootReceiver.kt @@ -12,16 +12,22 @@ class BootReceiver : BroadcastReceiver() { private val TAG = "BootReceiver" override fun onReceive(ctx: Context, i: Intent) { val serviceClass = try { - Log.i(TAG, "BleMediaService不存在") + Log.d(TAG, "BleMediaService不存在") Class.forName("com.yunqiinnovation.agent_service.BleMediaService") } catch (e: ClassNotFoundException) { - Log.i(TAG, "BleMediaService不存在") + Log.d(TAG, "BleMediaService不存在") return } if (i.action == Intent.ACTION_BOOT_COMPLETED) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + { + Log.d(TAG, "BleMediaService") ctx.startForegroundService(Intent(ctx, serviceClass)) - else ctx.startService(Intent(ctx, serviceClass)) + } + else{ + Log.d(TAG, "BleMediaService") + ctx.startService(Intent(ctx, serviceClass)) + } } } } \ No newline at end of file