Files
SkyJourney 61017f1c39 chore: 初始化脚手架 — sunny_mochi 企业级 Flutter 模板
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
2026-05-14 12:51:05 +08:00

95 lines
2.9 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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(),
);
}
}