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.
 
 
 
 
 

333 lines
10 KiB

import 'dart:io';
import 'package:dating_touchme_app/config/env_config.dart';
import 'package:dating_touchme_app/controller/global.dart';
import 'package:dating_touchme_app/controller/overlay_controller.dart';
import 'package:dating_touchme_app/im/im_manager.dart';
import 'package:dating_touchme_app/network/network_service.dart';
import 'package:dating_touchme_app/pages/main/main_page.dart';
import 'package:dating_touchme_app/pages/mine/login_page.dart';
import 'package:dating_touchme_app/pages/setting/teenager_mode_page.dart';
import 'package:dating_touchme_app/rtc/rtc_manager.dart';
import 'package:dating_touchme_app/widget/live/draggable_overlay_widget.dart';
import 'package:dating_touchme_app/widget/message/video_call_overlay_widget.dart';
import 'package:dating_touchme_app/widget/user_agreement_dialog.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:fluwx/fluwx.dart';
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'package:ota_update/ota_update.dart';
import 'extension/my_cupertino_localizations.dart';
void main() async {
// 设置全局错误处理
FlutterError.onError = (FlutterErrorDetails details) {
FlutterError.presentError(details);
if (kReleaseMode) {
// 在生产环境中,可以将错误发送到错误收集服务
print('Flutter Error: ${details.exception}');
}
};
// 处理异步错误
PlatformDispatcher.instance.onError = (error, stack) {
print('Platform Error: $error');
print('Stack: $stack');
return true;
};
try {
WidgetsFlutterBinding.ensureInitialized();
// 初始化GetStorage
await GetStorage.init();
// 设置环境配置 - 根据是否为release模式
EnvConfig.setEnvironment(Environment.dev);
// 初始化RTC,如果失败也不阻止应用启动
try {
await RTCManager.instance.initialize(appId: '4c2ea9dcb4c5440593a418df0fdd512d');
} catch (e) {
print('RTC初始化失败: $e');
}
// 注意:IM初始化改为异步,在应用启动后执行,避免阻塞应用启动
// IM初始化将在 MyApp 的 initState 中异步执行
// 初始化全局依赖
final networkService = NetworkService();
Get.put(networkService);
Get.put(networkService.userApi);
Get.put(networkService.homeApi);
// 初始化全局 Overlay 控制器
Get.put(OverlayController());
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.light,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
),
);
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
if (Platform.isIOS) {
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: [SystemUiOverlay.top],
);
}
} catch (e, stackTrace) {
print('应用初始化失败: $e');
print('堆栈跟踪: $stackTrace');
// 即使初始化失败,也尝试启动应用
}
runApp(
GetMaterialApp(
locale: Locale('zh', 'CN'), // 使用GetX的locale
supportedLocales: const [Locale('zh', 'CN')],
/// 国际化配置 代理
localizationsDelegates: const [
ChineseArabicMonthDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, // iOS
],
theme: ThemeData(
scaffoldBackgroundColor: Colors.white,
// 设置导航栏样式
appBarTheme: AppBarTheme(
systemOverlayStyle: SystemUiOverlayStyle(
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.light,
),
),
),
builder: (context, child) {
final smartDialogBuilder = FlutterSmartDialog.init();
return smartDialogBuilder(
context,
Stack(
children: [
child ?? const SizedBox(),
// 全局 overlay 组件
Obx(() {
try {
if (Get.isRegistered<OverlayController>()) {
final overlayController = Get.find<OverlayController>();
// 视频通话小窗
if (overlayController.showVideoCallOverlay.value) {
return VideoCallOverlayWidget(
targetUserId: overlayController.videoCallTargetUserId ?? '',
targetUserName: overlayController.videoCallTargetUserName,
targetAvatarUrl: overlayController.videoCallTargetAvatarUrl,
onClose: () {
overlayController.hideVideoCall();
},
);
}
// 直播房间小窗
if (overlayController.showOverlay.value) {
return DraggableOverlayWidget(
size: 60,
backgroundColor: const Color.fromRGBO(0, 0, 0, 0.6),
onClose: () {
overlayController.hide();
},
);
}
}
} catch (e) {
print('获取OverlayController失败: $e');
}
return const SizedBox.shrink();
}),
],
),
);
},
home: MyApp(),
),
);
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Fluwx fluwx = Fluwx();
bool _screenUtilInitialized = false;
bool _showAgreementDialog = false;
@override
void initState() {
super.initState();
_initFluwx();
// 异步初始化IM,避免阻塞应用启动
_initIMAsync();
// 检查是否已同意协议
_checkAgreement();
updateTest();
}
updateTest() async {
// try {
// OtaUpdate()
// .execute(
// 'http://oss.famitech.cn/ai_girlfriend/app/yuanyujiaowu_doubao.apk',
// // OPTIONAL
// destinationFilename: 'yuanyujiaowu_doubao.apk',
//
// ).listen(
// (OtaEvent event) {
// print(event.value);
// print("event.value");
// print(event.status);
// },
// );
// } catch (e) {
// print('Failed to make OTA update. Details: $e');
// }
}
/// 检查是否已同意用户协议
void _checkAgreement() {
final storage = GetStorage();
final hasAgreed = storage.read<bool>('hasAgreedUserAgreement') ?? false;
if (!hasAgreed) {
// 延迟显示弹框,确保UI已初始化
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_showAgreementDialog = true;
});
});
}
}
/// 处理同意协议
void _onAgreeAgreement() {
final storage = GetStorage();
storage.write('hasAgreedUserAgreement', true);
setState(() {
_showAgreementDialog = false;
});
}
/// 处理不同意协议 - 退出应用
void _onDisagreeAgreement() {
if (Platform.isIOS) {
// iOS上退出应用
exit(0);
} else {
// Android上退出应用
SystemNavigator.pop();
}
}
/// 异步初始化IM SDK,避免阻塞应用启动
void _initIMAsync() {
// 使用 Future.delayed 确保在应用完全启动后再初始化
Future.delayed(const Duration(milliseconds: 500), () async {
try {
print('🚀 开始异步初始化IM SDK(懒加载模式)...');
print('📋 AppKey: 1165251016193374#demo');
// 使用 ensureInitialized 方法,确保 init 至少被调用过一次
await IMManager.instance.ensureInitialized(appKey: '1165251016193374#demo');
print('✅ IM SDK异步初始化完成');
} catch (e, stackTrace) {
print('❌ IM SDK异步初始化失败');
print('错误类型: ${e.runtimeType}');
print('错误信息: $e');
print('堆栈跟踪:');
print('$stackTrace');
// 检查是否是特定错误
if (e.toString().contains('PlatformException')) {
print('⚠️ 可能是原生层配置问题,请检查:');
print(' 1. Android: 检查 AndroidManifest.xml 中的权限配置');
print(' 2. iOS: 检查 Info.plist 中的权限配置');
print(' 3. 检查网络连接');
}
// IM初始化失败不应该阻止应用运行
}
});
}
_initFluwx() async {
try {
await fluwx.registerApi(
appId: 'wx57624b8918fdd95c',
doOnAndroid: true,
doOnIOS: true,
universalLink: 'https://your.univerallink.com/link/',
);
await fluwx.isWeChatInstalled;
} catch (e) {
print('微信SDK初始化失败: $e');
// 微信SDK初始化失败不应该阻止应用运行
}
}
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
// ScreenUtil.init 只应该初始化一次,不应该在每次build时调用
if (!_screenUtilInitialized) {
ScreenUtil.init(context, designSize: const Size(375, 812));
_screenUtilInitialized = true;
}
// 判断token是否为空
final storage = GetStorage();
final userId = storage.read<String>('userId');
final teenagerMode = storage.read<bool>('teenagerMode') ?? false;
GlobalData().teenagerMode = teenagerMode;
Widget homeWidget;
if(teenagerMode){
homeWidget = TeenagerModePage();
} else if (userId != null && userId.isNotEmpty) {
// 如果token不为空,显示主页;如果token为空,显示登录页面
GlobalData().userId = userId;
homeWidget = MainPage();
} else {
homeWidget = LoginPage();
}
// 如果需要显示协议弹框,则显示
if (_showAgreementDialog) {
return Stack(
children: [
homeWidget,
UserAgreementDialog(
onAgree: _onAgreeAgreement,
onDisagree: _onDisagreeAgreement,
),
],
);
}
return homeWidget;
}
}