Browse Source

上传app优化代码

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
28b4416fd3
  1. 3
      android/app/build.gradle.kts
  2. 4
      android/app/src/main/AndroidManifest.xml
  3. 135
      android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MainActivity.kt
  4. 144
      android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MyApplication.kt
  5. 140
      lib/main.dart
  6. 15
      lib/modules/splash/controllers/splash_controller.dart
  7. 6
      local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt
  8. 11
      local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift
  9. 12
      local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicLoginManager.kt

3
android/app/build.gradle.kts

@ -61,7 +61,8 @@ android {
manifestPlaceholders.putAll(
mapOf(
"redirectSchemeName" to "spotify-sdk",
"redirectHostName" to "auth"
"redirectHostName" to "auth",
"applicationName" to "com.saitong.voitrans.MyApp" // 新增:声明自定义 Application
)
)
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).

4
android/app/src/main/AndroidManifest.xml

@ -2,6 +2,7 @@
xmlns:tools="http://schemas.android.com/tools">
<!-- 添加必要的权限 -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- Android 13+ 前台服务特定类型权限 -->
@ -84,8 +85,7 @@
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:launchMode="singleTask"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"

135
android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MainActivity.kt

@ -13,22 +13,147 @@ import android.content.Context
import android.os.Handler
import android.os.Looper
import android.util.Log
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.plugin.common.MethodChannel // 添加这行导入
class MainActivity: FlutterActivity() {
private val TAG = "MainActivity"
private var pendingDeepLink: Intent? = null
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "🚀 MainActivity onCreate 开始")
super.onCreate(savedInstanceState)
// 检查 Intent 信息
intent?.let {
Log.d(TAG, "Intent action: ${it.action}")
Log.d(TAG, "Intent data: ${it.data}")
Log.d(TAG, "Intent extras: ${it.extras}")
}
// 暂存深链接,等Flutter引擎完全准备好后处理
if (intent?.action == Intent.ACTION_VIEW && intent?.data != null) {
pendingDeepLink = intent
Log.d(TAG, "🔗 暂存深链接,等待Flutter引擎准备完成")
}
// 设置日志级别,减少系统级日志
suppressSystemLogs()
Log.d(TAG, "✅ MainActivity onCreate 完成")
}
// 添加 onNewIntent 方法处理深链接
override fun onNewIntent(intent: Intent) {
Log.d(TAG, "🔗 onNewIntent 被调用")
super.onNewIntent(intent)
setIntent(intent) // 更新当前 Intent
// 检查新的 Intent 信息
Log.d(TAG, "New Intent action: ${intent.action}")
Log.d(TAG, "New Intent data: ${intent.data}")
Log.d(TAG, "New Intent extras: ${intent.extras}")
// 处理深链接
handleDeepLink(intent)
}
override fun provideFlutterEngine(context: Context): FlutterEngine? {
Log.d(TAG, "🔍 provideFlutterEngine 被调用")
val engine = FlutterEngineCache.getInstance().get("main_engine")
if (engine == null) {
Log.w(TAG, "❌ FlutterEngine 缓存为空,这可能导致问题")
// 如果缓存为空,让 Flutter 框架创建默认 Engine
return null
}
// 检查 Engine 状态 - 使用更兼容的方式
try {
// 检查 Dart 执行器是否正在运行
val isExecutorRunning = engine.dartExecutor.isExecutingDart
Log.d(TAG, "FlutterEngine Dart 执行状态: $isExecutorRunning")
// 如果需要,可以检查其他状态
if (!isExecutorRunning) {
Log.w(TAG, "⚠️ FlutterEngine Dart 执行器未运行,可能需要重新初始化")
}
} catch (e: Exception) {
Log.w(TAG, "❌ 检查 FlutterEngine 状态时出错", e)
}
Log.d(TAG, "✅ 使用缓存的 FlutterEngine")
return engine
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
Log.d(TAG, "🔧 configureFlutterEngine 开始")
// 检查插件是否已经注册,避免重复注册
val pluginRegistry = flutterEngine.plugins
// 只有在插件未注册时才调用 GeneratedPluginRegistrant
if (!pluginRegistry.has(io.flutter.plugins.pathprovider.PathProviderPlugin::class.java)) {
Log.d(TAG, "📦 注册 Flutter 插件")
super.configureFlutterEngine(flutterEngine)
GeneratedPluginRegistrant.registerWith(flutterEngine)
} else {
Log.d(TAG, "⚠️ 插件已注册,跳过重复注册")
}
// 注册标准Flutter插件
GeneratedPluginRegistrant.registerWith(flutterEngine)
// Flutter引擎配置完成后,处理待处理的深链接
Handler(Looper.getMainLooper()).postDelayed({
pendingDeepLink?.let { intent ->
Log.d(TAG, "🔗 处理待处理的深链接")
handleDeepLink(intent)
pendingDeepLink = null
}
}, 1000) // 延迟1秒确保Flutter完全准备好
Log.d(TAG, "✅ configureFlutterEngine 完成")
}
// 处理深链接的统一方法
private fun handleDeepLink(intent: Intent?) {
intent?.let {
if (it.action == Intent.ACTION_VIEW && it.data != null) {
val uri = it.data
Log.d(TAG, "🔗 处理深链接: $uri")
try {
Log.d(TAG, "🔗 开始发送深链接到 Flutter")
// 通过 MethodChannel 将深链接信息传递给 Flutter
flutterEngine?.dartExecutor?.binaryMessenger?.let { messenger ->
Log.d(TAG, "🔗 获取到 BinaryMessenger")
val channel = MethodChannel(
messenger,
"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)
}
)
Log.d(TAG, "🔗 准备发送参数: $arguments")
channel.invokeMethod("handleDeepLink", arguments)
Log.d(TAG, "✅ 深链接信息已发送到 Flutter")
} ?: run {
Log.w(TAG, "❌ BinaryMessenger 为空,无法发送深链接")
}
} catch (e: Exception) {
Log.e(TAG, "❌ 处理深链接时出错", e)
}
} else {
Log.d(TAG, "🔗 Intent 不是深链接或数据为空")
}
}
}
override fun onDestroy() {
@ -112,5 +237,5 @@ class MainActivity: FlutterActivity() {
// 反射方法可能不存在,忽略
}
}
}
}

144
android/app/src/main/kotlin/com/yunqiinnovation/deepsound/MyApplication.kt

@ -0,0 +1,144 @@
package com.saitong.voitrans
import android.app.ActivityManager
import android.content.Context
import android.util.Log
import io.flutter.app.FlutterApplication
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterEngineCache
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.plugins.GeneratedPluginRegistrant
// Application.kt
class MyApp : FlutterApplication() {
companion object {
private const val TAG = "MyApp"
private const val ENGINE_ID = "main_engine"
// 标记 Engine 是否已经执行过 Dart 入口点
@Volatile
private var isDartEntrypointExecuted = false
// 记录应用启动时间,用于判断是否为新启动
@Volatile
private var appStartTime = 0L
}
override fun onCreate() {
super.onCreate()
appStartTime = System.currentTimeMillis()
Log.d(TAG, "MyApp onCreate - 进程启动")
val cache = FlutterEngineCache.getInstance()
val existingEngine = cache.get(ENGINE_ID)
if (existingEngine == null) {
Log.d(TAG, "创建新的 FlutterEngine")
createAndCacheEngine(cache)
} else {
Log.d(TAG, "FlutterEngine 已存在,检查状态")
// 检查现有 Engine 的状态
try {
val isExecuting = existingEngine.dartExecutor.isExecutingDart
Log.d(TAG, "Engine Dart执行状态: $isExecuting")
if (!isExecuting && isMainProcess()) {
Log.d(TAG, "Engine 存在但Dart未执行,重新执行")
existingEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
isDartEntrypointExecuted = true
}
} catch (e: Exception) {
Log.e(TAG, "检查或重新执行 Dart 入口点失败", e)
// 如果失败,重新创建 Engine
cache.remove(ENGINE_ID)
createAndCacheEngine(cache)
}
}
}
private fun createAndCacheEngine(cache: FlutterEngineCache) {
// 在主进程中总是创建并执行Dart入口点
if (isMainProcess()) {
Log.d(TAG, "✅ 在主进程创建 FlutterEngine 并执行 Dart")
val flutterEngine = FlutterEngine(this)
// 注册插件(只在这里注册一次)
Log.d(TAG, "📦 注册 Flutter 插件")
GeneratedPluginRegistrant.registerWith(flutterEngine)
try {
Log.d(TAG, "🚀 开始执行 Dart 入口点")
flutterEngine.dartExecutor.executeDartEntrypoint(
DartExecutor.DartEntrypoint.createDefault()
)
isDartEntrypointExecuted = true
cache.put(ENGINE_ID, flutterEngine)
Log.d(TAG, "✅ FlutterEngine 创建并缓存成功")
} catch (e: Exception) {
Log.e(TAG, "❌ 执行 Dart 入口点失败", e)
// 如果执行失败,仍然缓存 Engine,但标记为未执行
isDartEntrypointExecuted = false
cache.put(ENGINE_ID, flutterEngine)
}
} else {
Log.d(TAG, "⚠️ 在非主进程,仅创建 FlutterEngine")
// 非主进程只创建 Engine,不执行 Dart 入口点
val flutterEngine = FlutterEngine(this)
cache.put(ENGINE_ID, flutterEngine)
}
}
private fun isMainProcess(): Boolean {
val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val processes = am.runningAppProcesses ?: return true
val mainProcessName = packageName
val myPid = android.os.Process.myPid()
for (process in processes) {
if (process.pid == myPid) {
return process.processName == mainProcessName
}
}
return true
}
private fun isAppInForeground(): Boolean {
val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val processes = am.runningAppProcesses ?: return false
val pkg = packageName
for (p in processes) {
if (p.processName == pkg &&
p.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
return true
}
}
return false
}
private fun isAppBeingLaunched(): Boolean {
// 改进的启动检测逻辑
val currentTime = System.currentTimeMillis()
val isRecentStart = (currentTime - appStartTime) < 3000 // 3秒内认为是新启动
if (isRecentStart) {
Log.d(TAG, "检测到应用新启动")
return true
}
// 备用检测方法(兼容旧版本)
return try {
val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val tasks = am.getRunningTasks(1)
val result = tasks.isNotEmpty() && tasks[0].topActivity?.packageName == packageName
Log.d(TAG, "通过 RunningTasks 检测启动状态: $result")
result
} catch (e: Exception) {
Log.w(TAG, "无法获取 RunningTasks,可能缺少权限", e)
// 如果无法获取任务信息,默认认为是启动状态
true
}
}
}

140
lib/main.dart

@ -1,37 +1,104 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_intro/flutter_intro.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:get_storage/get_storage.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'core/bindings/initial_binding.dart';
import 'routes/app_pages.dart';
import 'routes/app_routes.dart';
import 'core/translations/app_translations.dart';
import 'core/themes/app_theme.dart';
import 'core/themes/theme_service.dart';
import '../../data/services/login_service.dart';
import 'core/bindings/initial_binding.dart';
import 'data/services/login_service.dart';
import 'dart:ui' as ui;
import 'modules/splash/controllers/splash_controller.dart';
void main() async {
// 确保Flutter绑定初始化
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
// 初始化存储 - 在创建应用之前初始化
// 初始化存储
await GetStorage.init();
// 初始化环境变量
await dotenv.load();
// 加载环境变量
await dotenv.load(fileName: ".env");
print("环境变量加载成功");
// 初始化登录服务
Get.put(LoginService());
// 延迟初始化深链接处理器,确保Flutter完全准备好
WidgetsBinding.instance.addPostFrameCallback((_) {
Future.delayed(const Duration(milliseconds: 1500), () {
_initDeepLinkHandler();
});
});
runApp(MainApp());
}
// 初始化深链接处理器
void _initDeepLinkHandler() {
print("🔗 初始化深链接处理器");
const platform = MethodChannel('com.saitong.voitrans/deeplink');
platform.setMethodCallHandler((call) async {
print("🔗 Flutter 收到深链接调用: ${call.method}");
if (call.method == 'handleDeepLink') {
final arguments = call.arguments as Map<dynamic, dynamic>;
print("🔗 深链接参数: $arguments");
// 初始化登录服务(包含Firebase初始化)
LoginService();
final url = arguments['url'] as String?;
if (url != null) {
print("🔗 处理深链接 URL: $url");
await _handleDeepLinkNavigation(url);
}
}
});
// 运行应用
runApp(const MainApp());
print("✅ 深链接处理器初始化完成");
}
// 处理深链接导航
Future<void> _handleDeepLinkNavigation(String url) async {
print("🔗 开始处理深链接导航: $url");
try {
final uri = Uri.parse(url);
print("🔗 解析URI: scheme=${uri.scheme}, host=${uri.host}, path=${uri.path}");
if (uri.scheme == 'deepvoice' && uri.host == 'qqmusic') {
print("🔗 检测到QQ音乐登录回调");
// 等待SplashController注册
int retryCount = 0;
const maxRetries = 10;
while (retryCount < maxRetries) {
try {
if (Get.isRegistered<SplashController>()) {
print("🔗 找到SplashController,处理QQ音乐登录");
final controller = Get.find<SplashController>();
controller.handleQQMusicLogin();
return;
}
} catch (e) {
print("🔗 获取SplashController失败: $e");
}
retryCount++;
print("🔗 等待SplashController注册 ($retryCount/$maxRetries)");
await Future.delayed(const Duration(milliseconds: 500));
}
print("❌ 超时等待SplashController注册");
}
} catch (e) {
print("❌ 处理深链接时出错: $e");
}
}
class MainApp extends StatelessWidget {
@ -39,46 +106,27 @@ class MainApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 获取保存的主题设置
final themeMode = ThemeService().getThemeMode();
// 在应用构建时立即初始化深链接处理
_initDeepLinkHandler();
// 使用 ScreenUtilInit 包装整个应用
return ScreenUtilInit(
designSize: const Size(375, 812),
designSize: const Size(375, 812), // 设计稿尺寸,根据你的设计稿调整
minTextAdapt: true,
splitScreenMode: true,
builder: (_, child) {
builder: (context, child) {
return GetMaterialApp(
title: 'Voitrans',
title: 'VoiTrans',
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: themeMode, // 使用提前获取的主题模式
initialBinding: InitialBinding(),
themeMode: ThemeService().getThemeMode(),
initialRoute: Routes.splash,
getPages: AppPages.pages,
debugShowCheckedModeBanner: false,
initialBinding: InitialBinding(),
translations: AppTranslations(),
localizationsDelegates: const [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: AppTranslations.deviceLocale(),
fallbackLocale: AppTranslations.getSmartFallbackLocale(),
supportedLocales: AppTranslations.supportedLocales,
builder: EasyLoading.init(
builder: (BuildContext context, Widget? widget) {
EasyLoading.instance.userInteractions = false;
return MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaler: TextScaler.noScaling,
),
child: Intro(
padding: EdgeInsets.zero,
child: widget!,
),
);
},
),
locale: Get.deviceLocale,
fallbackLocale: const Locale('en', 'US'),
debugShowCheckedModeBanner: false,
);
},
);

15
lib/modules/splash/controllers/splash_controller.dart

@ -289,6 +289,21 @@ class SplashController extends GetxController {
return false;
}
}
/// 处理QQ音乐登录回调
void handleQQMusicLogin() {
try {
Logger.i(_tag, '处理QQ音乐登录回调');
// 这里可以添加具体的QQ音乐登录处理逻辑
// 例如:验证登录状态、更新用户信息、导航到相应页面等
// 如果需要导航到特定页面,可以使用:
// Get.toNamed(Routes.qqmusic);
} catch (e) {
Logger.e(_tag, '处理QQ音乐登录回调失败: $e');
}
}
}
/// 显示无网络连接对话框并等待用户操作(阻塞版本)

6
local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt

@ -1956,7 +1956,7 @@ object AgentService : CoroutineScope {
)
}
if (playlist.isNotEmpty()) {
processQQMusicPlayList(playlist)
// processQQMusicPlayList(playlist)
} else {
Log.w(TAG, "qqmusic_searchandplay_songs 中没有有效的音乐条目")
}
@ -1969,6 +1969,10 @@ object AgentService : CoroutineScope {
val start = cardNavigation.optString("start", "")
val end = cardNavigation.optString("end", "")
processNavigation(start, end);
}else if (toolname == "map_weather") { //导航服务
iscard = true
}else if (toolname == "maps_weather") { //导航服务
iscard = true
}
return mapOf("meta" to metaStr, "broadcast" to broadcast, "notreply" to notreply,"iscard" to iscard);
}

11
local_plugins/agent_service/ios/agent_service/Sources/agent_service/AgentServiceImpl.swift

@ -834,6 +834,7 @@ internal func autoHandleFunctionCallResult(toolName: String, functionCallResult:
private func handleJSONDictionary(_ jsonDict: [String: Any], toolName: String) -> [String: Any] {
var broadcast = true
var notreply = false
var iscard = false
var metadata: [String: Any] = [:]
metadata[toolName] = jsonDict
@ -843,7 +844,11 @@ private func handleJSONDictionary(_ jsonDict: [String: Any], toolName: String) -
if let _notreply = jsonDict["notreply"] as? Bool {
notreply = _notreply
}
if let _iscard = jsonDict["iscard"] as? Bool {
iscard = _iscard
}
metadata["notreply"] = notreply
metadata["iscard"] = iscard
// 处理卡片数据
// if let cardMusic = jsonDict["card_music"] as? [String: Any] {
// processMusicCard(cardMusic)
@ -854,8 +859,12 @@ private func handleJSONDictionary(_ jsonDict: [String: Any], toolName: String) -
processNavigationCard(cardNavigation)
} else if let cardQQMusiclist = jsonDict["data"] as? [[String: Any]], toolName == "qqmusic_searchandplay_songs" {
processQQMusicPlayList(cardQQMusiclist)
} else if toolName == "maps_weather" {
iscard = true
}else if toolName == "map_weather" {
iscard = true
}
metadata["iscard"] = iscard
let metaStr: String
if let jsonData = try? JSONSerialization.data(withJSONObject: metadata, options: []),
let jsonString = String(data: jsonData, encoding: .utf8) {

12
local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicLoginManager.kt

@ -108,7 +108,7 @@ class QQMusicLoginManager(private val context: Context) {
// 已授权,直接请求登录信息
Log.d(TAG, "已授权,直接获取登录信息")
// isBindQQMusicService = true
startAuthProcess2(callback)
startAuthProcess(callback)
}
ErrorCodes.ERROR_API_NO_PERMISSION -> {
// 需要授权
@ -156,11 +156,11 @@ class QQMusicLoginManager(private val context: Context) {
)
// Log.d(TAG, "当前是前台服务")
} else {
// CommonCmd.loginQQMusic(
// context,
// context.packageName,
// BASE_SCHEME,
// )
CommonCmd.loginQQMusic(
context,
context.packageName,
BASE_SCHEME,
)
Log.d(TAG, "当前是后台服务")
}
// 启动QQ音乐登录

Loading…
Cancel
Save