// main.dart - 优化版本 // 保留设备信息加载,但优化初始化流程 import 'dart:async'; import 'dart:developer' as dev; import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_crashlytics/firebase_crashlytics.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:logging/logging.dart'; import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; import 'package:puzzleweave/ads/applovin_ads_controller.dart'; import 'package:puzzleweave/app_lifecycle/app_lifecycle.dart'; import 'package:puzzleweave/audio/jc_audio_controller.dart'; import 'package:puzzleweave/firebase/firebase_options.dart'; import 'package:puzzleweave/homepage/home_screen.dart'; import 'package:puzzleweave/l10n/app_localizations.dart'; import 'package:puzzleweave/models/data.dart'; import 'package:puzzleweave/models/items.dart'; import 'package:puzzleweave/persistence/persistence.dart'; import 'package:puzzleweave/play/board_play.dart'; import 'package:puzzleweave/remote_config/remote_config.dart'; import 'package:puzzleweave/settings/settings_controller.dart'; import 'package:puzzleweave/utils/utils.dart'; import 'package:puzzleweave/utils/memory_monitor.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:puzzleweave/firebase/adjust_helper.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; import 'config/config.dart' as cfg; import 'config/config.dart'; import 'config/device.dart'; Logger _log = Logger('main.dart'); final RouteObserver routeObserver = RouteObserver(); // ✅ 优化点1: 移除所有阻塞性 await void main() { // Subscribe to log messages. Logger.root.onRecord.listen((record) { dev.log( record.message, time: record.time, level: record.level.value, name: record.loggerName, zone: record.zone, error: record.error, stackTrace: record.stackTrace, ); }); WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); // 保持原生闪屏,直到我们完成所有阻塞性初始化后才移除 FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); // 强制竖屏 SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); // 进入全屏沉浸式 if (Platform.isAndroid) { SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); } SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle(statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.dark, statusBarBrightness: Brightness.light), ); // ✅ 立即启动 UI,不等待任何异步初始化 runApp(const MyApp()); } class MyApp extends StatefulWidget { const MyApp({super.key}); @override State createState() => _MyAppState(); } class _MyAppState extends State { bool _isInitialized = false; String? _initError; late Directory _baseDir; @override void initState() { super.initState(); _initializeAsync(); } // ✅ 优化点2: 并行初始化,减少总时间 Future _initializeAsync() async { try { // 1. 先初始化不会被阻塞的并发任务 final results = await Future.wait([_initFirebase(), _initPersistence(), _initBaseDirectory()], eagerError: false); _baseDir = results[2] as Directory; // 非阻塞性初始化(不等待完成) _initRemoteConfig(); _prepareFirstRunData(); setState(() { _isInitialized = true; }); // 关键:一切就绪后,移除原生闪屏并进场! FlutterNativeSplash.remove(); // 启动内存监控 if (Config.isDebug) { MemoryMonitor().startMonitoring( interval: const Duration(seconds: 3), onHighMemory: () => _log.warning('High memory detected'), onCriticalMemory: () => _log.severe('Critical memory - emergency cleanup triggered'), ); } _log.info('App initialization completed successfully'); } catch (e, stack) { _log.severe('App initialization failed', e, stack); setState(() { _initError = e.toString(); _isInitialized = true; // 即使失败也显示 UI }); } } // ✅ 优化点3: Firebase 初始化独立,带超时保护 Future _initFirebase() async { if (kIsWeb || !Platform.isAndroid) return; try { await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform).timeout(Duration(seconds: 10)); // 提取网络环境/连接异常的判断逻辑,共用 bool isEnvIssue(dynamic error, String errorStr) { return error is SocketException || error is HttpException || error is HandshakeException || errorStr.contains('ClientException') || errorStr.contains('SocketException') || errorStr.contains('HandshakeException') || errorStr.contains('Failed host lookup') || errorStr.contains('Network is unreachable') || errorStr.contains('Connection timed out') || errorStr.contains('Connection closed') || errorStr.contains('Connection reset') || errorStr.contains('Software caused connection abort') || errorStr.contains('Unable to connect') || errorStr.contains('Downloaded data is too small'); } FlutterError.onError = (errorDetails) { final errorStr = errorDetails.exceptionAsString(); if (isEnvIssue(errorDetails.exception, errorStr)) { _log.warning('已拦截 UI 渲染层网络异常(不视为崩溃): $errorStr'); FirebaseCrashlytics.instance.log('Env UI Error (Ignored): $errorStr'); return; } FirebaseCrashlytics.instance.recordFlutterFatalError(errorDetails); }; PlatformDispatcher.instance.onError = (error, stack) { final errorStr = error.toString(); if (isEnvIssue(error, errorStr)) { _log.warning('已拦截底层网络环境异常: $errorStr'); FirebaseCrashlytics.instance.log('Env Error (Ignored): $errorStr'); return true; } if (error is MissingPluginException) { _log.warning('插件未找到: $errorStr'); return true; } _log.severe('未处理的逻辑错误', error, stack); FirebaseCrashlytics.instance.recordError(error, stack, fatal: false); return true; }; _log.info('Firebase initialized successfully'); } catch (e) { _log.warning("Firebase initialization failed: $e"); } } Future _initPersistence() async { try { await Persistence().initialize().timeout(Duration(seconds: 5)); Persistence().lastRunTime = DateTime.now(); _log.info('Persistence initialized successfully'); } catch (e) { _log.severe('Persistence initialization failed: $e'); rethrow; } } Future _initBaseDirectory() async { try { return await getApplicationDocumentsDirectory(); } catch (e) { _log.severe('Failed to get base directory: $e'); rethrow; } } void _initRemoteConfig() { try { RemoteConfig().initialize(); _log.info('RemoteConfig initialized'); } catch (e) { _log.warning('RemoteConfig initialization failed: $e'); } } Future _prepareFirstRunData() async { if (!Persistence().firstRun) return; try { final json = await loadJSONFromAsset('assets/builtin/${cfg.Config.firstId}.json'); await saveJson('work/${cfg.Config.firstId}.json', json); _log.info('First run data prepared'); } catch (e) { _log.warning('Failed to prepare first run data: $e'); } } @override Widget build(BuildContext context) { // 显示加载界面 if (!_isInitialized) { return MaterialApp( home: Scaffold( backgroundColor: Color(0xfff4f2e9), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 使用原生最轻量的进度指示器 SizedBox(width: 40, height: 40, child: CircularProgressIndicator(strokeWidth: 3, valueColor: AlwaysStoppedAnimation(Colors.green))), const SizedBox(height: 20), // 可选:添加一个简单的文字,让用户知道在加载 Text( "Loading...", style: TextStyle(color: Color.fromARGB(255, 38, 96, 12), fontSize: 14, fontWeight: FontWeight.w500), ), ], ), ), ), ); } // 初始化失败时显示错误界面 if (_initError != null) { return MaterialApp( home: Scaffold( backgroundColor: Color(0xfff4f2e9), body: Center( child: Padding( padding: EdgeInsets.all(24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.error_outline, size: 64, color: Colors.red), SizedBox(height: 16), Text('Initialization Failed', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)), SizedBox(height: 8), Text( _initError!, textAlign: TextAlign.center, style: TextStyle(color: Colors.grey), ), SizedBox(height: 24), ElevatedButton( onPressed: () { setState(() { _isInitialized = false; _initError = null; }); _initializeAsync(); }, child: Text('Retry'), ), ], ), ), ), ), ); } // 正常启动应用 cfg.Config config = cfg.Config(context, _baseDir); return AppLifecycleObserver( child: MultiProvider( providers: [ Provider(lazy: false, create: (context) => Data(persistence: Persistence())..loadDataFromPersistence()), Provider(lazy: false, create: (context) => SettingsController(persistence: Persistence())..loadStateFromPersistence()), ProxyProvider2, JcAudioController>( lazy: false, create: (context) => JcAudioController()..initialize(), update: (context, settings, lifecycleNotifier, audio) { if (audio == null) throw ArgumentError.notNull(); audio.attachSettings(settings); audio.attachLifecycleNotifier(lifecycleNotifier); return audio; }, dispose: (context, audio) => audio.dispose(), ), Provider(create: (context) => ApplovinAdsController(context)), Provider(lazy: false, create: (context) => config), Provider(lazy: false, create: (context) => config.device), ], child: Prepare( child: MaterialApp( title: 'Jigsort Solitaire', initialRoute: '/', navigatorObservers: [routeObserver], routes: { '/': (context) => const HomeScreen(), '/play': (context) => BoardPlay( item: AssetItem( cfg.Config.firstId, '', 2000, 3000, 3, false, 'assets/builtin/${cfg.Config.firstId}.jpeg', 'assets/builtin/${cfg.Config.firstId}.jpeg', ), firstRun: true, ), }, theme: ThemeData(brightness: Brightness.light, primaryColor: Colors.green, primarySwatch: Colors.blue), localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, localeResolutionCallback: (Locale? locale, Iterable supportedLocales) { var result = supportedLocales.where((element) => element.languageCode == locale?.languageCode); if (result.isNotEmpty) { Device.locale = locale!; _log.info('当前语言(支持):${Device.locale!.countryCode}-${Device.locale!.languageCode}'); return locale; } Device.locale = const Locale('en'); _log.info('当前语言(默认):${Device.locale!.countryCode}-${Device.locale!.languageCode}'); return Device.locale; }, ), ), ), ); } } class Prepare extends StatefulWidget { final Widget child; const Prepare({super.key, required this.child}); @override State createState() => _PrepareState(); } class _PrepareState extends State { @override void initState() { super.initState(); // ✅ 保留:异步加载设备信息(不阻塞 UI) _loadDeviceInfo(); } /// ✅ 优化:异步加载设备信息,不阻塞 UI Future _loadDeviceInfo() async { if (!Platform.isAndroid) return; try { final deviceInfoPlugin = DeviceInfoPlugin(); final androidInfo = await deviceInfoPlugin.androidInfo; if (mounted) { context.read().androidDeviceInfo = androidInfo; _log.info( 'Device info loaded: SDK ${androidInfo.version.sdkInt}, ' 'LowRAM: ${androidInfo.isLowRamDevice}, ' 'CPUs: ${Platform.numberOfProcessors}', ); } } catch (e) { _log.warning('Failed to load device info: $e'); // 失败不影响应用运行 } } @override Widget build(BuildContext context) { return widget.child; } }