diff --git a/lib/data/models/appconfig_model.dart b/lib/data/models/appconfig_model.dart index 88c0a9661..2353a9444 100644 --- a/lib/data/models/appconfig_model.dart +++ b/lib/data/models/appconfig_model.dart @@ -87,6 +87,10 @@ class DBProduct { final bool? broadcastpeertranslate; //通话翻译是否本地播报对方翻译内容 final String? updatedescription; final String? updatepackageaddress; + // 产品渠道方:official / mobile 等,用于判定是否为“移动精灵”设备 + final String? channel; + // 渠道附加数据(JSON 字符串),例如:{"platform_id":"...","platform_key":"...","tui":"..."} + final String? channelextra; DBProduct({ required this.id, @@ -102,6 +106,8 @@ class DBProduct { required this.broadcastpeertranslate, required this.updatedescription, required this.updatepackageaddress, + this.channel, + this.channelextra, }); factory DBProduct.fromJson(Map json) => diff --git a/lib/data/models/appconfig_model.g.dart b/lib/data/models/appconfig_model.g.dart index 4227611e4..5918c025c 100644 --- a/lib/data/models/appconfig_model.g.dart +++ b/lib/data/models/appconfig_model.g.dart @@ -87,6 +87,8 @@ DBProduct _$DBProductFromJson(Map json) => DBProduct( broadcastpeertranslate: json['broadcastpeertranslate'] as bool?, updatedescription: json['updatedescription'] as String?, updatepackageaddress: json['updatepackageaddress'] as String?, + channel: json['channel'] as String?, + channelextra: json['channelextra'] as String?, ); Map _$DBProductToJson(DBProduct instance) => { @@ -103,4 +105,6 @@ Map _$DBProductToJson(DBProduct instance) => { 'broadcastpeertranslate': instance.broadcastpeertranslate, 'updatedescription': instance.updatedescription, 'updatepackageaddress': instance.updatepackageaddress, + 'channel': instance.channel, + 'channelextra': instance.channelextra, }; diff --git a/lib/data/services/ble_manager.dart b/lib/data/services/ble_manager.dart index 14d137ccf..29fe982f0 100644 --- a/lib/data/services/ble_manager.dart +++ b/lib/data/services/ble_manager.dart @@ -955,16 +955,15 @@ class BleManager extends GetxService { } // STS 模式参数(移动精灵) - // 优先使用设备检测结果(YIDONG_PID 匹配时写入),否则用服务端 AGENT_TYPE - final agentType = _storage.read('device_agent_type') - ?? AppConfig.env('AGENT_TYPE') - ?? 'stt_llm_tts'; + // 仅以配对时根据 DBProduct.channel=='mobile' 写入的 storage 为准, + // 不做任何 env 兜底——若 storage 里无对应参数,进入移动精灵时直接报错暴露问题 + final agentType = _storage.read('device_agent_type') ?? ''; final agentMode = (agentType == 'yidong') ? 'sts' : 'stt_llm_tts'; - final agentId = (agentType == 'yidong') - ? (AppConfig.env('MOBILE_ELF_AGENT_ID') ?? 'mobile_elf') - : 'default_agent'; - final stsProductId = AppConfig.env('MOBILE_ELF_PRODUCT_ID') ?? ''; - final stsProductKey = AppConfig.env('MOBILE_ELF_PRODUCT_KEY') ?? ''; + final agentId = (agentType == 'yidong') ? 'mobile_elf' : 'default_agent'; + // STS 平台认证参数从 DBProduct.channelextra 解析后存入 storage, + // 不再读取 .env 中的 MOBILE_ELF_PRODUCT_ID/KEY + final stsProductId = _storage.read('sts_product_id') ?? ''; + final stsProductKey = _storage.read('sts_product_key') ?? ''; // 使用当前连接设备的 SN(配对时写入),认证失败由原生层上报 credential_failed 事件 final stsDeviceNo = _storage.read('device_sts_code') ?? ''; final stsDeviceId = _storage.read('sts_device_id') ?? ''; diff --git a/lib/modules/home/controllers/home_controller.dart b/lib/modules/home/controllers/home_controller.dart index fa75943b7..3d6aea3d5 100644 --- a/lib/modules/home/controllers/home_controller.dart +++ b/lib/modules/home/controllers/home_controller.dart @@ -222,10 +222,9 @@ class HomeController extends GetxController { } void exploreAIFeatures() { - // 优先读设备检测写入的 storage(YIDONG_PID 匹配时),否则降级到服务端 AGENT_TYPE - final agentType = GetStorage().read('device_agent_type') - ?? AppConfig.env('AGENT_TYPE') - ?? 'stt_llm_tts'; + // 按设备渠道路由:配对时 DBProduct.channel=='mobile' 才会写入 device_agent_type='yidong', + // 其他渠道(官方等)默认走单段式 stt_llm_tts 逻辑。不再读取 .env 中的 AGENT_TYPE。 + final agentType = GetStorage().read('device_agent_type') ?? ''; if (agentType == 'yidong') { Get.toNamed(Routes.mobileElf); } else { diff --git a/lib/modules/mobile_elf/controllers/mobile_elf_controller.dart b/lib/modules/mobile_elf/controllers/mobile_elf_controller.dart index cc121a08c..a615ef412 100644 --- a/lib/modules/mobile_elf/controllers/mobile_elf_controller.dart +++ b/lib/modules/mobile_elf/controllers/mobile_elf_controller.dart @@ -6,7 +6,6 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import 'package:permission_handler/permission_handler.dart'; -import '../../../data/models/appconfig.dart'; import '../../../core/utils/logger.dart'; import '../../../core/utils/permission_util.dart'; @@ -68,7 +67,7 @@ class MobileElfController extends GetxController { // 生命周期 // ═══════════════════════════════════════════════════════════════════════════ - String get _agentId => AppConfig.env('MOBILE_ELF_AGENT_ID') ?? 'mobile_elf'; + String get _agentId => 'mobile_elf'; @override void onInit() { diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart index 1c89ae606..e938d4ca9 100644 --- a/lib/modules/pairing/controllers/pairing_controller.dart +++ b/lib/modules/pairing/controllers/pairing_controller.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'dart:async'; +import 'dart:convert'; import 'package:app_settings/app_settings.dart'; import '/data/models/appconfig_model.dart'; @@ -1194,15 +1195,12 @@ class PairingController extends GetxController with WidgetsBindingObserver { } } - /// 检测是否为移动精灵(YIDONG)设备,并写入 GetStorage + /// 检测是否为移动精灵设备,并写入 GetStorage + /// 判定依据:服务端下发的 DBProduct.channel == 'mobile' + /// 平台认证参数从 DBProduct.channelextra (JSON) 中解析: + /// { "platform_id": "...", "platform_key": "...", "tui": "..." } void _detectAndSaveYidongDevice() { - final yidongPid = AppConfig.env('YIDONG_PID') ?? ''; - if (yidongPid.isEmpty) { - Logger.i(_tag, '[YIDONG] 未配置 YIDONG_PID,跳过检测'); - return; - } - - // 优先使用本次扫描解析的 pid,否则从已绑定设备列表中查找 + // 1) 获取当前设备 pid(BLE 扫描 > 已绑定设备) int? pid = _verifiedDevicePid; String pidSource = 'BLE扫描'; if (pid == null) { @@ -1229,43 +1227,97 @@ class PairingController extends GetxController with WidgetsBindingObserver { return; } - // 将 int pid 转为十六进制字符串(不补零,大写)与 YIDONG_PID 比对 - final pidHex = pid.toRadixString(16).toUpperCase(); - final isYidong = pidHex == yidongPid.toUpperCase(); - - Logger.i(_tag, '[YIDONG] 设备检测: pidHex=$pidHex yidongPid=${yidongPid.toUpperCase()} source=$pidSource matched=$isYidong'); - - if (isYidong) { - _storage.write('device_agent_type', 'yidong'); - // deviceCode 来源: - // 新设备 → BLE 扫描从广播包提取 - // 已绑定设备 → authbindingDevice 从 existingDevice.license 赋值 - if (deviceCode.value.isNotEmpty) { - final prevCode = _storage.read('device_sts_code') ?? ''; - // SN 变了说明换了设备,清除旧凭证,强制重新向移动平台认证 - if (prevCode != deviceCode.value) { - _storage.remove('sts_device_id'); - _storage.remove('sts_device_secret'); - Logger.i(_tag, '[YIDONG] SN 变更($prevCode → ${deviceCode.value}),已清除旧凭证,强制重新认证'); + // 2) 从服务端下发的产品列表中查找对应产品 + DBProduct? product; + try { + product = AppConfig.config.products.firstWhere((p) => p.id == pid); + } catch (_) { + product = null; + } + if (product == null) { + Logger.i(_tag, '[YIDONG] 未在 AppConfig.products 中找到 pid=$pid 对应产品,清理旧凭证'); + _clearYidongStorage(); + return; + } + + final channel = (product.channel ?? '').trim().toLowerCase(); + final isYidong = channel == 'mobile'; + Logger.i(_tag, + '[YIDONG] 设备检测: pid=$pid channel=${product.channel} source=$pidSource matched=$isYidong'); + + if (!isYidong) { + _clearYidongStorage(); + return; + } + + // 3) 解析 channelextra,取 platform_id / platform_key / tui + String platformId = ''; + String platformKey = ''; + String tui = ''; + final extra = product.channelextra; + if (extra != null && extra.isNotEmpty) { + try { + final dynamic decoded = jsonDecode(extra); + if (decoded is Map) { + platformId = (decoded['platform_id'] ?? '').toString(); + platformKey = (decoded['platform_key'] ?? '').toString(); + tui = (decoded['tui'] ?? '').toString(); } - _storage.write('device_sts_code', deviceCode.value); - Logger.i(_tag, '[YIDONG] 识别成功,写入 device_sts_code=${deviceCode.value}'); - } else { - // 既无扫描结果也无 license,清除所有凭证,认证失败会提示用户 - _storage.remove('device_sts_code'); + } catch (e) { + Logger.e(_tag, '[YIDONG] 解析 channelextra 失败: $e raw=$extra'); + } + } + if (platformId.isEmpty || platformKey.isEmpty) { + Logger.w(_tag, + '[YIDONG] channelextra 缺失 platform_id/platform_key,无法配置 STS,清理旧凭证'); + _clearYidongStorage(); + return; + } + + // 4) 写入存储:设备标识 + STS 平台认证参数 + _storage.write('device_agent_type', 'yidong'); + _storage.write('sts_product_id', platformId); + _storage.write('sts_product_key', platformKey); + if (tui.isNotEmpty) { + _storage.write('sts_tui', tui); + } else { + _storage.remove('sts_tui'); + } + Logger.i(_tag, + '[YIDONG] 识别成功,已写入 sts_product_id=$platformId sts_product_key=*** tui=$tui'); + + // deviceCode 来源:新设备=BLE扫描提取;已绑定设备=existingDevice.license + if (deviceCode.value.isNotEmpty) { + final prevCode = _storage.read('device_sts_code') ?? ''; + // SN 变了说明换了设备,清除旧凭证,强制重新向移动平台认证 + if (prevCode != deviceCode.value) { _storage.remove('sts_device_id'); _storage.remove('sts_device_secret'); - Logger.i(_tag, '[YIDONG] deviceCode 为空,已清除所有凭证'); + Logger.i(_tag, + '[YIDONG] SN 变更($prevCode → ${deviceCode.value}),已清除旧凭证,强制重新认证'); } + _storage.write('device_sts_code', deviceCode.value); + Logger.i(_tag, '[YIDONG] 写入 device_sts_code=${deviceCode.value}'); } else { - _storage.remove('device_agent_type'); _storage.remove('device_sts_code'); _storage.remove('sts_device_id'); _storage.remove('sts_device_secret'); - Logger.i(_tag, '[YIDONG] 非移动精灵设备,已清除相关存储'); + Logger.i(_tag, '[YIDONG] deviceCode 为空,已清除设备凭证'); } } + /// 清理移动精灵相关本地存储 + void _clearYidongStorage() { + _storage.remove('device_agent_type'); + _storage.remove('device_sts_code'); + _storage.remove('sts_device_id'); + _storage.remove('sts_device_secret'); + _storage.remove('sts_product_id'); + _storage.remove('sts_product_key'); + _storage.remove('sts_tui'); + Logger.i(_tag, '[YIDONG] 非移动精灵设备,已清除相关存储'); + } + /// 导航到主页 void _navigateToHome() { // 检测是否为移动精灵(YIDONG)设备 diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/StsAgent.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/StsAgent.kt index b76a16a58..5601dfb5c 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/StsAgent.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/StsAgent.kt @@ -416,9 +416,19 @@ class StsAgent( if (inCall) resetVad() } - /** 清空消息历史 */ + /** 清空消息历史(内存 + SQLite) */ fun clearHistory() { messages = JSONArray() + // 同步删除本地数据库中该 agentId 的所有消息,避免页面 onInit 再次加载到旧消息 + val agentId = config.agentId + launch { + try { + val ok = chatStorageHelper.deleteMessages(agentId = agentId) + Log.i(TAG, "[YIDONG] clearHistory: 数据库清理 agentId=$agentId success=$ok") + } catch (e: Exception) { + Log.e(TAG, "[YIDONG] clearHistory: 数据库清理异常 ${e.message}", e) + } + } } /** 释放资源 */