diff --git a/android/app/src/main/kotlin/com/saitong/voitrans/MainActivity.kt b/android/app/src/main/kotlin/com/saitong/voitrans/MainActivity.kt index 33f368e82..172e3776f 100644 --- a/android/app/src/main/kotlin/com/saitong/voitrans/MainActivity.kt +++ b/android/app/src/main/kotlin/com/saitong/voitrans/MainActivity.kt @@ -19,6 +19,11 @@ import io.flutter.plugin.common.MethodChannel // 添加这行导入 class MainActivity: FlutterActivity() { private val TAG = "MainActivity" private var pendingDeepLink: Intent? = null + private var pendingNavigationIntent: Intent? = null + + private val EXTRA_NAVIGATE_TO = "com.saitong.voitrans.extra.NAVIGATE_TO" + private val NAVIGATE_TO_MEETING_RECORD = "meetingRecord" + private val ROUTE_MEETING_RECORD = "/meeting/record" override fun onCreate(savedInstanceState: Bundle?) { Log.d(TAG, "🚀 MainActivity onCreate 开始") @@ -36,6 +41,11 @@ class MainActivity: FlutterActivity() { pendingDeepLink = intent Log.d(TAG, "🔗 暂存深链接,等待Flutter引擎准备完成") } + + if (intent?.hasExtra(EXTRA_NAVIGATE_TO) == true) { + pendingNavigationIntent = intent + Log.d(TAG, "🧭 暂存导航意图,等待Flutter引擎准备完成") + } // 设置日志级别,减少系统级日志 suppressSystemLogs() @@ -54,7 +64,7 @@ class MainActivity: FlutterActivity() { Log.d(TAG, "New Intent extras: ${intent.extras}") // 处理深链接 - handleDeepLink(intent) + handleNavigationIntent(intent) } override fun provideFlutterEngine(context: Context): FlutterEngine? { @@ -106,17 +116,29 @@ class MainActivity: FlutterActivity() { Handler(Looper.getMainLooper()).postDelayed({ pendingDeepLink?.let { intent -> Log.d(TAG, "🔗 处理待处理的深链接") - handleDeepLink(intent) + handleNavigationIntent(intent) pendingDeepLink = null } + + pendingNavigationIntent?.let { intent -> + Log.d(TAG, "🧭 处理待处理的导航意图") + handleNavigationIntent(intent) + pendingNavigationIntent = null + } }, 1000) // 延迟1秒确保Flutter完全准备好 Log.d(TAG, "✅ configureFlutterEngine 完成") } // 处理深链接的统一方法 - private fun handleDeepLink(intent: Intent?) { + private fun handleNavigationIntent(intent: Intent?) { intent?.let { + val navigateTo = it.getStringExtra(EXTRA_NAVIGATE_TO) + if (navigateTo == NAVIGATE_TO_MEETING_RECORD) { + pushRouteToFlutter(ROUTE_MEETING_RECORD) + return + } + if (it.action == Intent.ACTION_VIEW && it.data != null) { val uri = it.data Log.d(TAG, "🔗 处理深链接: $uri") @@ -133,16 +155,7 @@ class MainActivity: FlutterActivity() { "com.saitong.voitrans/deeplink" ) - val arguments = mapOf( - "url" to uri.toString(), - "scheme" to uri?.scheme, - "host" to uri?.host, - "path" to uri?.path, - "query" to uri?.query, - "queryParameters" to uri?.queryParameterNames?.associateWith { - uri.getQueryParameter(it) - } - ) + val arguments = buildUrlArguments(uri.toString()) Log.d(TAG, "🔗 准备发送参数: $arguments") @@ -160,6 +173,41 @@ class MainActivity: FlutterActivity() { } } + private fun pushRouteToFlutter(route: String) { + try { + val engine = flutterEngine + if (engine == null) { + Log.w(TAG, "❌ FlutterEngine 为空,无法 pushRoute") + return + } + Handler(Looper.getMainLooper()).post { + try { + engine.navigationChannel.pushRoute(route) + } catch (e: Exception) { + Log.e(TAG, "❌ pushRoute 失败", e) + } + } + } catch (e: Exception) { + Log.e(TAG, "❌ pushRouteToFlutter 出错", e) + } + } + + private fun buildUrlArguments(url: String): Map { + return try { + val uri = android.net.Uri.parse(url) + mapOf( + "url" to url, + "scheme" to uri.scheme, + "host" to uri.host, + "path" to uri.path, + "query" to uri.query, + "queryParameters" to uri.queryParameterNames.associateWith { uri.getQueryParameter(it) } + ) + } catch (e: Exception) { + mapOf("url" to url) + } + } + override fun onDestroy() { super.onDestroy() } @@ -242,4 +290,3 @@ class MainActivity: FlutterActivity() { } } } - diff --git a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/AudioRecordingForegroundService.kt b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/AudioRecordingForegroundService.kt index 0b1d1b1fb..620c08dda 100644 --- a/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/AudioRecordingForegroundService.kt +++ b/local_plugins/azure_speech/android/src/main/kotlin/com/yunqiinnovation/azure_speech/tools/AudioRecordingForegroundService.kt @@ -113,8 +113,10 @@ class AudioRecordingForegroundService : Service() { * @return 通知对象 */ private fun createNotification(): Notification { - // 创建点击通知时的意图(可以打开应用主界面) - val intent = packageManager.getLaunchIntentForPackage(packageName) + val intent = (packageManager.getLaunchIntentForPackage(packageName) ?: Intent()).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP) + putExtra("com.saitong.voitrans.extra.NAVIGATE_TO", "meetingRecord") + } val pendingIntent = PendingIntent.getActivity( this, 0, @@ -123,14 +125,15 @@ class AudioRecordingForegroundService : Service() { ) return NotificationCompat.Builder(this, CHANNEL_ID) - .setContentTitle("语音助手正在运行") - .setContentText("正在录制音频,点击返回应用") - .setSmallIcon(android.R.drawable.ic_btn_speak_now) // 使用系统默认麦克风图标 + .setContentTitle("Voitrans") + .setContentText("Recording audio, tap to return to app") + .setSmallIcon(applicationInfo.icon) .setContentIntent(pendingIntent) .setOngoing(true) // 设置为持续通知,用户无法滑动删除 .setPriority(NotificationCompat.PRIORITY_LOW) .setCategory(NotificationCompat.CATEGORY_SERVICE) .setShowWhen(false) + .setAutoCancel(false) // 点击通知后不自动取消 .build() } -} \ No newline at end of file +}