You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
8.4 KiB
260 lines
8.4 KiB
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
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:get_storage/get_storage.dart';
|
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
|
|
import 'core/utils/app_lifecycle_manager.dart';
|
|
import 'routes/app_pages.dart';
|
|
import 'routes/app_routes.dart';
|
|
import 'core/translations/app_translations.dart';
|
|
import 'core/theme/app_theme.dart';
|
|
import 'core/theme/theme_service.dart';
|
|
import 'core/bindings/initial_binding.dart';
|
|
import 'core/utils/logger.dart';
|
|
import 'core/services/native_localization_sync.dart';
|
|
import 'core/services/ai_orb_controller.dart';
|
|
import 'data/services/login_service.dart';
|
|
import 'modules/meeting/controllers/meeting_home_controller.dart';
|
|
import 'modules/splash/controllers/splash_controller.dart';
|
|
|
|
bool _deepLinkHandlerInitialized = false;
|
|
|
|
void main() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
// App 不做横屏适配,锁死竖屏(原生侧 AndroidManifest/Info.plist 也各锁了一道,
|
|
// 这里是 Flutter 侧兜底,避免个别机型仅靠原生配置锁不住)
|
|
await SystemChrome.setPreferredOrientations([
|
|
DeviceOrientation.portraitUp,
|
|
]);
|
|
|
|
// 初始化存储
|
|
await GetStorage.init();
|
|
|
|
// 加载环境变量
|
|
await dotenv.load(fileName: ".env");
|
|
Logger.i("Main", "环境变量加载成功");
|
|
|
|
// 初始化文件日志
|
|
await Logger.initFileLog();
|
|
|
|
// 初始化登录服务
|
|
Get.put(LoginService());
|
|
|
|
// 延迟初始化深链接处理器,确保Flutter完全准备好
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
Future.delayed(const Duration(milliseconds: 1500), () {
|
|
_initDeepLinkHandler();
|
|
});
|
|
});
|
|
|
|
runApp(MainApp());
|
|
}
|
|
|
|
// 初始化深链接处理器
|
|
void _initDeepLinkHandler() {
|
|
if (_deepLinkHandlerInitialized) return;
|
|
_deepLinkHandlerInitialized = true;
|
|
|
|
Logger.d("DeepLink", "初始化深链接处理器");
|
|
|
|
const platform = MethodChannel('com.yimai.eaimar/deeplink');
|
|
|
|
platform.setMethodCallHandler((call) async {
|
|
Logger.d("DeepLink", "Flutter 收到深链接调用: ${call.method}");
|
|
|
|
if (call.method == 'handleDeepLink') {
|
|
final arguments = call.arguments as Map<dynamic, dynamic>;
|
|
Logger.d("DeepLink", "深链接参数: $arguments");
|
|
|
|
final url = arguments['url'] as String?;
|
|
if (url != null) {
|
|
Logger.d("DeepLink", "处理深链接 URL: $url");
|
|
await _handleDeepLinkNavigation(url);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (call.method == 'handleSharedFile') {
|
|
final arguments = call.arguments as Map<dynamic, dynamic>;
|
|
final filePath = arguments['filePath'] as String?;
|
|
if (filePath == null || filePath.isEmpty) return;
|
|
await _handleSharedAudioFile(filePath);
|
|
return;
|
|
}
|
|
});
|
|
|
|
Logger.i("DeepLink", "深链接处理器初始化完成");
|
|
}
|
|
|
|
// 处理深链接导航
|
|
Future<void> _handleDeepLinkNavigation(String url) async {
|
|
Logger.d("DeepLink", "开始处理深链接导航: $url");
|
|
|
|
try {
|
|
final uri = Uri.parse(url);
|
|
Logger.d("DeepLink",
|
|
"解析URI: scheme=${uri.scheme}, host=${uri.host}, path=${uri.path}");
|
|
|
|
if (uri.scheme == 'deepvoice' && uri.host == 'qqmusic') {
|
|
Logger.i("DeepLink", "检测到QQ音乐登录回调");
|
|
|
|
// 等待SplashController注册
|
|
int retryCount = 0;
|
|
const maxRetries = 10;
|
|
|
|
while (retryCount < maxRetries) {
|
|
try {
|
|
if (Get.isRegistered<SplashController>()) {
|
|
Logger.i("DeepLink", "找到SplashController,处理QQ音乐登录");
|
|
final controller = Get.find<SplashController>();
|
|
controller.handleQQMusicLogin();
|
|
return;
|
|
}
|
|
} catch (e) {
|
|
Logger.e("DeepLink", "获取SplashController失败", e);
|
|
}
|
|
|
|
retryCount++;
|
|
Logger.d("DeepLink", "等待SplashController注册 ($retryCount/$maxRetries)");
|
|
await Future.delayed(const Duration(milliseconds: 500));
|
|
}
|
|
|
|
Logger.w("DeepLink", "超时等待SplashController注册");
|
|
}
|
|
} catch (e) {
|
|
Logger.e("DeepLink", "处理深链接时出错", e);
|
|
}
|
|
}
|
|
|
|
Future<void> _handleSharedAudioFile(String filePath) async {
|
|
try {
|
|
if (!File(filePath).existsSync()) {
|
|
Logger.w("DeepLink", "分享文件不存在: $filePath");
|
|
return;
|
|
}
|
|
|
|
int retryCount = 0;
|
|
const maxRetries = 10;
|
|
while (retryCount < maxRetries) {
|
|
try {
|
|
if (Get.isRegistered<MeetingHomeController>()) {
|
|
final controller = Get.find<MeetingHomeController>();
|
|
controller.addAudio(filePath);
|
|
return;
|
|
}
|
|
|
|
Get.toNamed(
|
|
Routes.meeting,
|
|
arguments: {
|
|
'filePath': filePath,
|
|
},
|
|
);
|
|
return;
|
|
} catch (e) {
|
|
retryCount++;
|
|
await Future.delayed(const Duration(milliseconds: 300));
|
|
}
|
|
}
|
|
} catch (e) {
|
|
Logger.e("DeepLink", "处理分享文件失败", e);
|
|
}
|
|
}
|
|
|
|
class MainApp extends StatelessWidget {
|
|
const MainApp({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
// 在应用构建时立即初始化深链接处理
|
|
_initDeepLinkHandler();
|
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
unawaited(NativeLocalizationSync.syncToNative());
|
|
});
|
|
// 获取保存的主题设置
|
|
final themeMode = ThemeService().getThemeMode();
|
|
|
|
return ScreenUtilInit(
|
|
designSize: const Size(375, 812),
|
|
minTextAdapt: true,
|
|
splitScreenMode: true,
|
|
builder: (_, child) {
|
|
return GetMaterialApp(
|
|
title: 'EAIMAR',
|
|
theme: AppTheme.lightTheme,
|
|
darkTheme: AppTheme.darkTheme,
|
|
themeMode: themeMode, // 使用提前获取的主题模式
|
|
initialBinding: InitialBinding(),
|
|
initialRoute: Routes.splash,
|
|
getPages: AppPages.pages,
|
|
routingCallback: (routing) {
|
|
if (Get.isRegistered<AiOrbController>()) {
|
|
Get.find<AiOrbController>().onRouteChanged(routing?.current);
|
|
}
|
|
if (!Get.isRegistered<AppLifecycleManager>()) return;
|
|
unawaited(
|
|
Get.find<AppLifecycleManager>().refreshBleWakeupPolicy(
|
|
route: routing?.current,
|
|
),
|
|
);
|
|
},
|
|
debugShowCheckedModeBanner: false,
|
|
translations: AppTranslations(),
|
|
localizationsDelegates: const [
|
|
GlobalMaterialLocalizations.delegate,
|
|
GlobalWidgetsLocalizations.delegate,
|
|
GlobalCupertinoLocalizations.delegate,
|
|
],
|
|
locale: AppTranslations.deviceLocale(),
|
|
fallbackLocale: AppTranslations.fallbackLocale,
|
|
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,
|
|
// AI 球已改为只在 AI tab 内渲染(见 ai_tab.dart),
|
|
// 不再作为全局悬浮层叠加在所有页面之上
|
|
child: widget!,
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
});
|
|
|
|
// // 使用 ScreenUtilInit 包装整个应用
|
|
// return ScreenUtilInit(
|
|
// designSize: const Size(375, 812), // 设计稿尺寸,根据你的设计稿调整
|
|
// minTextAdapt: true,
|
|
// splitScreenMode: true,
|
|
// builder: (context, child) {
|
|
// return GetMaterialApp(
|
|
// title: 'Eaimar',
|
|
// theme: AppTheme.lightTheme,
|
|
// darkTheme: AppTheme.darkTheme,
|
|
// themeMode: ThemeService().getThemeMode(),
|
|
// initialRoute: Routes.splash,
|
|
// getPages: AppPages.pages,
|
|
// initialBinding: InitialBinding(),
|
|
// translations: AppTranslations(),
|
|
// locale: Get.deviceLocale,
|
|
// fallbackLocale: const Locale('en', 'US'),
|
|
// debugShowCheckedModeBanner: false,
|
|
// );
|
|
// },
|
|
// );
|
|
}
|
|
}
|
|
|