初始化
This commit is contained in:
+202
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user