Template
Core 基础设施:Flavor 三包体系、Drift+SQLCipher 加密数据库 7 拦截器 Dio 网络栈、CrashReporter 崩溃日志、Sealed Failure 错误体系 5 色板主题系统、Auth 认证骨架(Clean Architecture)、Dev Panel、Mock Adapter 通过验证:flutter analyze(0 errors)、flutter test(全绿)、staging APK 74.8MB
95 lines
2.9 KiB
Dart
95 lines
2.9 KiB
Dart
import 'dart:async';
|
||
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:sunny_mochi/app.dart';
|
||
import 'package:sunny_mochi/core/config/env.dart';
|
||
import 'package:sunny_mochi/core/crash/crash_reporter.dart';
|
||
import 'package:sunny_mochi/core/observability/sentry_setup.dart';
|
||
import 'package:sunny_mochi/core/observability/talker_setup.dart';
|
||
import 'package:sunny_mochi/core/storage/app_database.dart';
|
||
import 'package:sunny_mochi/core/sync/sync_service.dart';
|
||
import 'package:sunny_mochi/features/error_report/data/error_logger.dart';
|
||
import 'package:sunny_mochi/i18n/strings.g.dart';
|
||
import 'package:talker_riverpod_logger/talker_riverpod_logger.dart';
|
||
|
||
Future<void> main() async {
|
||
WidgetsFlutterBinding.ensureInitialized();
|
||
unawaited(LocaleSettings.useDeviceLocale());
|
||
|
||
// 1. 崩溃日志预初始化(必须在 Sentry 之前)
|
||
await CrashReporter.preInit();
|
||
final pendingCrash = CrashReporter.consumePending();
|
||
|
||
// 2. Sentry 初始化(空 DSN 时直接 runApp)
|
||
await SentrySetup.init(
|
||
appRunner: () async {
|
||
// 3. 挂载崩溃钩子
|
||
CrashReporter.installHooks();
|
||
appTalker.info('App boot · env=${Env.name} · mock=${Env.useMock}');
|
||
|
||
// 4. 打开加密 SQLite 数据库
|
||
final database = await AppDatabase.open();
|
||
|
||
runApp(
|
||
TranslationProvider(
|
||
child: ProviderScope(
|
||
retry: (_, _) => null,
|
||
overrides: [
|
||
appDatabaseProvider.overrideWithValue(database),
|
||
pendingCrashProvider.overrideWithValue(pendingCrash),
|
||
],
|
||
observers: [
|
||
if (Env.enableDevPanel)
|
||
TalkerRiverpodObserver(talker: appTalker),
|
||
],
|
||
child: const _SyncBootstrap(child: AppRoot()),
|
||
),
|
||
),
|
||
);
|
||
},
|
||
);
|
||
}
|
||
|
||
/// 在 ProviderScope 内启动 SyncService 和 ErrorLogger 清理。
|
||
class _SyncBootstrap extends ConsumerStatefulWidget {
|
||
const _SyncBootstrap({required this.child});
|
||
final Widget child;
|
||
|
||
@override
|
||
ConsumerState<_SyncBootstrap> createState() => _SyncBootstrapState();
|
||
}
|
||
|
||
class _SyncBootstrapState extends ConsumerState<_SyncBootstrap> {
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
unawaited(ref.read(syncServiceProvider).start());
|
||
unawaited(ref.read(errorLoggerProvider).pruneOld());
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
unawaited(ref.read(syncServiceProvider).dispose());
|
||
super.dispose();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) => widget.child;
|
||
}
|
||
|
||
class AppRoot extends StatelessWidget {
|
||
const AppRoot({super.key});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
// 设计基准 375pt(与 iOS JPScaleValue 一致;如设计方调整需同步)
|
||
return const ScreenUtilInit(
|
||
designSize: Size(375, 812),
|
||
minTextAdapt: true,
|
||
child: App(),
|
||
);
|
||
}
|
||
}
|