diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 1813b0c5a..16798fdab 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -55,6 +55,9 @@ android { excludes.add("META-INF/notice.txt") excludes.add("META-INF/*.kotlin_module") } + jniLibs { + useLegacyPackaging = true + } } defaultConfig { @@ -83,6 +86,8 @@ android { storePassword = keystoreProperties.getProperty("storePassword") enableV1Signing = true enableV2Signing = true + enableV3Signing = false + enableV4Signing = false } getByName("debug") { // debug 使用与 release 相同的签名配置 @@ -92,6 +97,8 @@ android { storePassword = keystoreProperties.getProperty("storePassword") enableV1Signing = true enableV2Signing = true + enableV3Signing = false + enableV4Signing = false } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4e946db0e..7400593aa 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -72,6 +72,7 @@ android:networkSecurityConfig="@xml/network_security_config" android:usesCleartextTraffic="true" + android:extractNativeLibs="true" android:enableOnBackInvokedCallback="true" tools:replace="android:label"> diff --git a/lib/data/services/network/api.dart b/lib/data/services/network/api.dart index 07a26ad71..9920fdf89 100644 --- a/lib/data/services/network/api.dart +++ b/lib/data/services/network/api.dart @@ -348,4 +348,20 @@ class Api { params: params, ); } + + static modifyRecordEchomeet([params]) { + Map data = { + 'title': 'NULL', + 'address': 'NULL', + 'personnel': 'NULL', + 'translate': 'NULL', + 'summary': 'NULL', + }; + data.addAll(params); + return DioManager().request( + NWMethod.post, + '/api/home/echomeet_modifyrecords', + params: data, + ); + } } diff --git a/lib/modules/meeting/controllers/meeting_details_controller.dart b/lib/modules/meeting/controllers/meeting_details_controller.dart index 5557e3038..aa2e1f4a3 100644 --- a/lib/modules/meeting/controllers/meeting_details_controller.dart +++ b/lib/modules/meeting/controllers/meeting_details_controller.dart @@ -238,6 +238,10 @@ class MeetingDetailsController extends GetxController textList[index] = dataMap; } } + await Api.modifyRecordEchomeet({ + 'id': id, + 'translate': jsonEncode(textList), + }); isSpeakerText.value = false; editSpeakerTextId.value = 0; editSpeakerTextList = []; diff --git a/lib/modules/meeting/controllers/meeting_home_controller.dart b/lib/modules/meeting/controllers/meeting_home_controller.dart index d1abd4066..1e0cf5b4d 100644 --- a/lib/modules/meeting/controllers/meeting_home_controller.dart +++ b/lib/modules/meeting/controllers/meeting_home_controller.dart @@ -585,6 +585,7 @@ class MeetingHomeController extends GetxController { void editMeetingTitle(int id) async { if (titleController.text.isNotEmpty) { String title = titleController.text + titleCSuffix; + Api.modifyRecordEchomeet({'id': id, 'title': title}); SqfliteApi.editMeetingTitle(id, {'title': title}); int originalIndex = originalDataList.indexWhere((item) => item['id'] == id); diff --git a/lib/modules/meeting/views/bottomSheet/speaker_all_bottom_sheet.dart b/lib/modules/meeting/views/bottomSheet/speaker_all_bottom_sheet.dart index 2accd0bf3..057b42ae2 100644 --- a/lib/modules/meeting/views/bottomSheet/speaker_all_bottom_sheet.dart +++ b/lib/modules/meeting/views/bottomSheet/speaker_all_bottom_sheet.dart @@ -9,6 +9,7 @@ import 'package:get_storage/get_storage.dart'; import 'package:lottie/lottie.dart'; import '../../../../data/services/db/sqflite_api.dart'; +import '../../../../data/services/network/api.dart'; import '../../controllers/meeting_details_controller.dart'; class SpeakerAllBottomSheet extends StatefulWidget { @@ -559,6 +560,11 @@ class _SpeakerAllBottomSheetState extends State { bool isEditSummary = false; String summaryText = _controller.meetingDetails.value.summary; _controller.textList.value = newTextList; + Map modifyData = { + 'id': _controller.meetingData.value.id, + 'translate': jsonEncode(_controller.textList), + 'personnel': personnel, + }; for (var element in personnelList) { if (summaryText.contains('[${element['original']}]')) { summaryText = summaryText.replaceAll( @@ -571,11 +577,13 @@ class _SpeakerAllBottomSheetState extends State { 'summary': summaryText, 'personnel': personnel, }); + modifyData.addAll({'summary': summaryText}); _controller.meetingDetails.value.summary = summaryText; _controller.summaryNumberModifications.value++; } else { SqfliteApi.editMeeting(_controller.id, {'personnel': personnel}); } + await Api.modifyRecordEchomeet(modifyData); _controller.meetingDetails.value.personnel = personnel; _controller.personnelNumberModifications.value++; _controller.meetingDetails.refresh(); diff --git a/lib/modules/meeting/views/bottomSheet/speaker_bottom_sheet.dart b/lib/modules/meeting/views/bottomSheet/speaker_bottom_sheet.dart index 429cdb1ff..a9483f856 100644 --- a/lib/modules/meeting/views/bottomSheet/speaker_bottom_sheet.dart +++ b/lib/modules/meeting/views/bottomSheet/speaker_bottom_sheet.dart @@ -7,6 +7,7 @@ import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../../../../data/services/db/sqflite_api.dart'; +import '../../../../data/services/network/api.dart'; import '../../controllers/meeting_details_controller.dart'; class SpeakerBottomSheet extends StatefulWidget { @@ -336,6 +337,10 @@ class _SpeakerBottomSheetState extends State { dataMap['speaker'] = _speakerController.text; _controller.textList[index] = dataMap; } + await Api.modifyRecordEchomeet({ + 'id': _controller.meetingData.value.id, + 'translate': jsonEncode(_controller.textList), + }); _addHistorySpeaker(); Get.back(); } @@ -366,6 +371,11 @@ class _SpeakerBottomSheetState extends State { var result = await SqfliteApi.editMeetingSpeaker(editSpeakerList); if (result != null) { _controller.textList.value = newTextList; + Map modifyData = { + 'id': _controller.meetingData.value.id, + 'translate': jsonEncode(_controller.textList), + 'personnel': personnel, + }; if (_controller.meetingDetails.value.summary .contains('[${widget.speakerName}]')) { String summaryText = _controller.meetingDetails.value.summary @@ -375,11 +385,13 @@ class _SpeakerBottomSheetState extends State { 'summary': summaryText, 'personnel': personnel, }); + modifyData.addAll({'summary': summaryText}); _controller.meetingDetails.value.summary = summaryText; _controller.summaryNumberModifications.value++; } else { SqfliteApi.editMeeting(_controller.id, {'personnel': personnel}); } + await Api.modifyRecordEchomeet(modifyData); _controller.meetingDetails.value.personnel = personnel; _addHistorySpeaker(); Get.back(); diff --git a/lib/modules/meeting/views/tabs/summary_tab.dart b/lib/modules/meeting/views/tabs/summary_tab.dart index 5863fe14b..995e18d42 100644 --- a/lib/modules/meeting/views/tabs/summary_tab.dart +++ b/lib/modules/meeting/views/tabs/summary_tab.dart @@ -6,6 +6,7 @@ import 'package:get/get.dart'; import 'package:parchment/codecs.dart'; import '../../../../data/services/db/sqflite_api.dart'; +import '../../../../data/services/network/api.dart'; import '../../controllers/meeting_details_controller.dart'; import '../bottomSheet/ai_bottom_sheet.dart'; import '../bottomSheet/generate_bottom_sheet.dart'; @@ -133,6 +134,10 @@ class _SummaryTabState extends State { final markdown = const ParchmentMarkdownCodec().encode(_fleatherController!.document); if (markdown != _controller.meetingDetails.value.summary) { + Api.modifyRecordEchomeet({ + 'id': _controller.id, + 'summary': markdown, + }); SqfliteApi.editMeeting( _controller.id, {'summary': markdown}, @@ -272,6 +277,12 @@ class _SummaryTabState extends State { isEdit = true; } if (isEdit) { + Api.modifyRecordEchomeet({ + 'id': _controller.id, + 'address': _controller.meetingDetails.value.address, + 'personnel': + _controller.meetingDetails.value.personnel, + }); SqfliteApi.editMeeting( _controller.id, { diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt index e7c4fc3bb..864cd0f5a 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt @@ -746,7 +746,8 @@ object AgentService : CoroutineScope { // 执行打断 lastInterruptTime = currentTime - interruptCurrentResponse() + stopTts() + // interruptCurrentResponse() } } } diff --git a/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift b/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift index d0e87a0b3..b22c0e2c5 100644 --- a/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift +++ b/local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift @@ -2332,7 +2332,8 @@ extension AgentServiceImpl: AzureAsrHelper.ContinuousRecognizeCallback { sendEvent(name: "recognizing", data: data) if isSpeaking || isAiStreaming { - interruptCurrentResponse() + stopTts() + // interruptCurrentResponse() } } } diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt index ee0cbd907..8a4fbd717 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/AzureAsrHelper.kt @@ -130,7 +130,7 @@ class AzureAsrHelper(private val context: Context) { val xunfeiConfigReady = this.xunfeiAppId.isNotBlank() && this.xunfeiAccessKeyId.isNotBlank() && this.xunfeiAccessKeySecret.isNotBlank() - this.useXunfei = supportedLanguages.all { it == "zh-CN" || it == "en-US" } && xunfeiConfigReady + this.useXunfei = supportedLanguages.all { it == "zh-CN" || it == "en-US" || it == "zh-HK"|| it == "en-TW" } && xunfeiConfigReady // 根据支持的语言数量决定是否启用自动语言检测 this.isAutoDetectLanguage = supportedLanguages.size >= 2 diff --git a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift index 3b1017217..9658a20af 100644 --- a/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift +++ b/local_plugins/azure_speech/ios/azure_speech/Sources/azure_speech/AzureAsrHelper.swift @@ -132,7 +132,7 @@ public class AzureAsrHelper: NSObject { let xunfeiConfigReady = !self.xunfeiAppId.isEmpty && !self.xunfeiAccessKeyId.isEmpty && !self.xunfeiAccessKeySecret.isEmpty - self.useXunfei = supportedLanguages.allSatisfy { $0 == "zh-CN" || $0 == "en-US" } && xunfeiConfigReady + self.useXunfei = supportedLanguages.allSatisfy { $0 == "zh-CN" || $0 == "en-US" || $0 == "zh-HK" || $0 == "en-TW" } && xunfeiConfigReady // 根据支持的语言数量决定是否启用自动语言检测 self.isAutoDetectLanguage = supportedLanguages.count >= 2 diff --git a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt index bb16bc993..0eb96287f 100644 --- a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt +++ b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt @@ -152,8 +152,8 @@ class SystemFunctionHandler(private val context: Context? = null) { // 注册获取当前位置函数 client.registerLocalFunction( - name = "get_current_location", - description = "获取当前地理位置", + name = "get_user_current_location", + description = "获取用户当前地理位置", parameters = mapOf( "type" to "object", "properties" to emptyMap(), diff --git a/local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationService.kt b/local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationService.kt index 5e051d418..3c3b0b3bc 100644 --- a/local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationService.kt +++ b/local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationService.kt @@ -5,6 +5,7 @@ import android.app.Activity import android.app.ActivityManager import android.content.Context import android.content.pm.PackageManager +import android.location.LocationManager import android.os.Build import android.os.Handler import android.os.Looper @@ -150,6 +151,10 @@ object LocationService { callback.onLocationError(-2, "后台定位权限需要打开始终定位权限才可,请打开app重新设置权限后再使用") return } + if (!isLocationServiceEnabled(ctx)) { + callback.onLocationError(-6, "定位服务未开启,请在系统设置中打开位置服务开关") + return + } if (!initialized) { callback.onLocationError(-3, "定位服务未初始化") return @@ -287,6 +292,24 @@ object LocationService { return 0 } + /** + * 检查系统位置服务开关状态 + * @param context 应用上下文 + * @return true:位置服务已开启;false:位置服务关闭或检测失败 + * @throws 无显式抛出异常(内部捕获并记录日志) + */ + fun isLocationServiceEnabled(context: Context): Boolean { + try { + val lm = context.getSystemService(Context.LOCATION_SERVICE) as? LocationManager + val gpsOn = lm?.isProviderEnabled(LocationManager.GPS_PROVIDER) == true + val networkOn = lm?.isProviderEnabled(LocationManager.NETWORK_PROVIDER) == true + return gpsOn || networkOn + } catch (e: Exception) { + Log.e(TAG, "检测位置服务开关失败: ${e.message}", e) + return false + } + } + private fun hasForegroundLocationPermission(context: Context): Boolean { return ContextCompat.checkSelfPermission( context, diff --git a/local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationServicePlugin.kt b/local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationServicePlugin.kt index 21bd7184f..87e88edac 100644 --- a/local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationServicePlugin.kt +++ b/local_plugins/location_service/android/src/main/kotlin/com/yunqiinnovation/location_service/LocationServicePlugin.kt @@ -25,7 +25,19 @@ class LocationServicePlugin: FlutterPlugin, MethodCallHandler { override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) { Log.d(TAG, "Method call: ${call.method}") - + when (call.method) { + "isLocationServiceEnabled" -> { + try { + val enabled = LocationService.isLocationServiceEnabled(context) + result.success(enabled) + } catch (e: Exception) { + result.error("CHECK_SERVICE_FAILED", e.message, null) + } + } + else -> { + result.notImplemented() + } + } } override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) { diff --git a/local_plugins/location_service/lib/location_service.dart b/local_plugins/location_service/lib/location_service.dart index 1e83bc0d0..07466b799 100644 --- a/local_plugins/location_service/lib/location_service.dart +++ b/local_plugins/location_service/lib/location_service.dart @@ -12,7 +12,7 @@ class LocationService { ); // 内部构造函数 - LocationService._internal() {} + LocationService._internal(); /// 检查定位权限 Future> checkPermission() async { @@ -40,6 +40,21 @@ class LocationService { } } + /// 检查系统位置服务是否开启 + /// 参数:无 + /// 返回值:true 表示已开启;false 表示未开启或检测失败 + /// 异常:抛出 Exception,表示方法通道调用失败或平台异常 + Future isLocationServiceEnabled() async { + try { + final enabled = await _methodChannel.invokeMethod( + 'isLocationServiceEnabled', + ); + return enabled ?? false; + } catch (e) { + throw Exception('检查位置服务失败: $e'); + } + } + /// 获取当前位置(按需获取) Future> location() async { try {