初始化

This commit is contained in:
谢宇宁
2026-09-15 15:44:13 +07:00
commit a23ba685e9
1065 changed files with 101122 additions and 0 deletions
+202
View File
@@ -0,0 +1,202 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'package:hgdj/hj_page/main_page/provider/bottom_bar_provider.dart';
import 'package:hgdj/hj_page/pre_sale/limit_time_provider.dart';
import 'package:hgdj/hj_page/pre_sale/pre_sale_provider.dart';
import 'package:hgdj/hj_page/splash/splash_page.dart';
import 'package:hgdj/hj_utils/codec_support.dart';
import 'package:hgdj/hj_utils/video_view_type.dart';
import 'package:hgdj/routers/router_map.dart';
import 'package:visibility_detector/visibility_detector.dart';
import 'package:hgdj/tools_base/debug_log.dart';
import 'package:hgdj/tools_base/global_store/store.dart';
import 'package:hgdj/tools_base/headphone_monitor.dart';
import 'package:hgdj/tools_base/net/http_manager.dart';
import 'package:hgdj/tools_base/video_download/video_download_manager.dart';
import 'package:hgdj/track_event_manager/device_service.dart';
import 'package:hgdj/track_event_manager/track_session.dart';
// 只引 OKToast 挂载所需符号:oktoast 也导出同名 showToast,全量 import 会与自家 toast.dart 冲突
import 'package:oktoast/oktoast.dart' show OKToast, ToastPosition;
import 'package:provider/provider.dart';
import 'package:ume_core/ume_core.dart';
import 'package:ume_kit_dio/ume_kit_dio.dart';
import 'package:ume_kit_perf/ume_kit_perf.dart';
import 'package:ume_kit_ui/ume_kit_ui.dart';
import 'alert/vip_guide/guide_countdown_dialog.dart';
import 'assets_tool/app_colors.dart';
import 'hj_page/home/provider/home_update_marker_provider.dart';
import 'hj_page/main_page/provider/msg_provider.dart';
import 'hj_page/mine/mine_vip/vip_product_manager.dart';
import 'hj_utils/light_model.dart';
final RouteObserver<ModalRoute<void>> routeObserver =
RouteObserver<ModalRoute<void>>();
void main() async {
runZonedGuarded(() async {
WidgetsFlutterBinding.ensureInitialized();
// 可见性回调默认攒 500ms 才发,短视频切 tab 会拖半秒才静音;压到 100ms(听不出延迟)。
// 不设 0:那样滚动中每帧都回调
VisibilityDetectorController.instance.updateInterval =
const Duration(milliseconds: 100);
VideoDownloadManager.instance.init();
await lightKV.init(); //初始化本地存储(lightKV/MMKV),其余初始化都依赖它,必须最先
httpManager.initDefault();
// 以下五项只读本地 KV / 设备信息、彼此无依赖,并行执行缩短冷启动首帧前耗时
await Future.wait([
globalStore.init(), //获取密码
DeviceInfoService.init(), //获取设备信息
initVideoViewType(), //视频渲染方式:读本机持久化标记,决定 textureView/platformView
CodecSupport.init(), //H.265 硬解能力:查芯片能力 + 读本机禁用标记,决定选 265 还是回落 264
]);
await TrackSessionManager()
.onAppColdStart(); //初始化请求头 sid(依赖 DeviceInfoService
WidgetsBinding.instance.addObserver(_TrackLifecycleObserver());
PromoCountdown.reset(); //优惠倒计时(场景3/4):app 启动时设定一次起点,全局仅此一次,进程存活期间自然倒数、不重置
HeadphoneMonitor.instance.start(); //耳机/蓝牙断开、来电等自动暂停视频,防止音频外放泄露隐私
if (kReleaseMode) {
runApp(const MyApp());
} else {
PluginManager.instance
..register(DioInspector(dio: httpManager.dio))
..register(Performance())
..register(const WidgetInfoInspector())
..register(const WidgetDetailInspector());
runApp(UMEWidget(child: const MyApp()));
}
}, (exception, stackTrace) async {
debugLog('exception = $exception\n stackTrace = $stackTrace');
});
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
PaintingBinding.instance.imageCache.maximumSize = 1000;
PaintingBinding.instance.imageCache.maximumSizeBytes = 500 << 20;
return AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light.copyWith(
statusBarColor: Colors.transparent,
systemNavigationBarColor: Colors.black,
systemNavigationBarIconBrightness: Brightness.light,
//Android 10+ 默认会给透明的状态栏/导航栏自动垫一层半透明黑(contrast scrim)
//导致短视频等全屏页上下多出一层压暗、且各家 ROM 表现不一,显式关掉统一成无遮罩。
//改这两个要同步下面 AppBarTheme.systemOverlayStyle,那边会覆盖本处设置
systemStatusBarContrastEnforced: false,
systemNavigationBarContrastEnforced: false,
),
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
// 触摸收起键盘
FocusManager.instance.primaryFocus?.unfocus();
},
child: ScreenUtilInit(
designSize: const Size(428, 927),
minTextAdapt: true,
splitScreenMode: true,
builder: (context, child) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(value: PreSaleProvider()), //预售
ChangeNotifierProvider.value(value: globalStore),
ChangeNotifierProvider.value(value: HomeBottomProvider()),
ChangeNotifierProvider.value(value: DarkwebBottomProvider()),
ChangeNotifierProvider.value(value: CommunityBottomProvider()),
ChangeNotifierProvider.value(
value: MineMsgProvider()), //消息中心红点,新人倒计时
ChangeNotifierProvider.value(
value: HomeUpdateMarkerProvider()), //首页最新/今日最新红点
ChangeNotifierProvider.value(
value: vipProductManager), //会员卡列表统一数据源
ChangeNotifierProvider.value(value: LimitTimeProvider()), //限时活动
],
child: GetMaterialApp(
// controller 只由 GetBuilder 回收,不跟路由绑定。默认的 full 会把它挂到「注册那刻的栈顶路由」,
// 弹窗期间新建的 GetBuilder 就被记到弹窗名下,弹窗一关 logic 被删、widget 还在(播放器因此永久转圈)。
// 只能写在这,写 main() 里会被 GetMaterialApp.build 覆盖回 full。
// 前提是所有 logic 都走 GetBuilder(init:)——手写 Get.put 的没人回收,要自己 Get.delete
smartManagement: SmartManagement.onlyBuilder,
navigatorObservers: [routeObserver],
debugShowCheckedModeBanner: true,
initialRoute: SplashPage.routeName,
getPages: AppRoutes.routePages,
theme: ThemeData(
platform: TargetPlatform.iOS,
scaffoldBackgroundColor: Color(0xff0F0F0F),
primaryColor: AppColors.primaryColor,
unselectedWidgetColor: Color(0xffD8D8D8),
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
tabBarTheme: const TabBarThemeData(
dividerColor: Colors.transparent,
splashFactory: NoSplash.splashFactory,
),
textSelectionTheme: TextSelectionThemeData(
cursorColor: AppColors.primaryHighColor,
),
appBarTheme: AppBarTheme(
centerTitle: true,
iconTheme: IconThemeData(color: Colors.white, size: 18),
shadowColor: Colors.transparent,
elevation: 0,
scrolledUnderElevation: 0.0,
backgroundColor: Colors.black,
titleTextStyle: TextStyle(
color: Color(0xE5FFFFFF),
fontSize: 18,
fontWeight: FontWeight.w600,
),
//有 AppBar 的页面由 AppBar 自己下发 overlay style,会盖掉最外层
//AnnotatedRegion 的设置,两个 contrastEnforced 必须跟那边保持一致
systemOverlayStyle: SystemUiOverlayStyle.light.copyWith(
systemStatusBarContrastEnforced: false,
systemNavigationBarContrastEnforced: false,
),
),
// 全局 BackButton 用 iOS 经典风格箭头(与项目历史 BaseAppBar 视觉一致)
actionIconTheme: ActionIconThemeData(
backButtonIconBuilder: (context) =>
const Icon(Icons.arrow_back_ios),
),
),
builder: (context, child) => OKToast(
position: ToastPosition.center,
backgroundColor: Colors.black.withValues(alpha: .85),
radius: 8,
textStyle: const TextStyle(color: Colors.white, fontSize: 14),
textPadding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: child!,
),
),
);
},
),
),
);
}
}
class _TrackLifecycleObserver extends WidgetsBindingObserver {
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
if (state == AppLifecycleState.paused ||
state == AppLifecycleState.inactive ||
state == AppLifecycleState.detached) {
TrackSessionManager().onAppPause();
} else if (state == AppLifecycleState.resumed) {
TrackSessionManager().onAppResume();
}
}
}