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.
343 lines
11 KiB
343 lines
11 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(
|
|
// // 地址如果非https需要去 android\app\src\main\res\xml\network_security_config.xml 配置信任地址
|
|
// 'https://pgyerapp.tracup.com/8bab5d3e8551e464d7d059160241ccc9.apk?sign=f2a40c8b607de18a7ab177c3b94f0bab&sign2=fd5574f9bf6d1c9328f1d95c40e87017&t=1767750116&response-content-disposition=attachment%3Bfilename%3D%22%E8%B6%A3%E6%81%8B%E6%81%8B_1.0.0.apk',
|
|
//
|
|
// destinationFilename: '趣恋恋_1.0.0.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((_) {
|
|
if (mounted) {
|
|
setState(() {
|
|
_showAgreementDialog = true;
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
// 已经同意过协议,不显示弹框
|
|
_showAgreementDialog = false;
|
|
}
|
|
}
|
|
|
|
/// 处理同意协议(保存同意状态,确保下次不再显示)
|
|
void _onAgreeAgreement() {
|
|
final storage = GetStorage();
|
|
// 保存用户已同意协议的状态,确保只在第一次安装时显示
|
|
storage.write('hasAgreedUserAgreement', true);
|
|
if (mounted) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
|