rwadurian/frontend/mobile-app/lib/bootstrap.dart

172 lines
5.1 KiB
Dart
Raw 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/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'core/storage/local_storage.dart';
import 'core/di/injection_container.dart';
import 'core/utils/logger.dart';
import 'core/updater/update_service.dart';
import 'core/updater/models/update_config.dart';
import 'core/telemetry/telemetry_service.dart';
import 'core/sentry/sentry_service.dart';
import 'core/sentry/sentry_config.dart';
/// API 基础地址
const String _apiBaseUrl = 'https://rwaapi.szaiai.com';
/// Sentry DSN (从 Sentry 后台获取)
/// 格式: http://public_key@host:port/project_id
/// 生产环境请替换为实际的 DSN
const String _sentryDsn = String.fromEnvironment(
'SENTRY_DSN',
defaultValue: '', // 未配置时禁用 Sentry
);
Future<void> bootstrap(FutureOr<Widget> Function() builder) async {
// Ensure Flutter bindings are initialized
WidgetsFlutterBinding.ensureInitialized();
// Set preferred orientations
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
// Set system UI overlay style
SystemChrome.setSystemUIOverlayStyle(
const SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarIconBrightness: Brightness.dark,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
),
);
// Initialize Hive
await Hive.initFlutter();
// Initialize LocalStorage
final localStorage = await LocalStorage.init();
// Initialize UpdateService (自建服务器模式)
UpdateService().initialize(
UpdateConfig.selfHosted(
apiBaseUrl: _apiBaseUrl,
enabled: true,
checkIntervalSeconds: 86400, // 24小时
),
);
// Create provider container with initialized dependencies
final container = createProviderContainer(localStorage);
// 配置 Sentry
final sentryConfig = _sentryDsn.isNotEmpty
? (kReleaseMode
? SentryConfig.production(dsn: _sentryDsn)
: SentryConfig.development(dsn: _sentryDsn))
: SentryConfig.disabled();
// 使用 Sentry 包装启动流程
await SentryService.init(
config: sentryConfig,
appRunner: () async {
// 设置 Flutter 错误处理
FlutterError.onError = (details) {
AppLogger.e('Flutter Error', details.exception, details.stack);
// 上报到 Sentry
if (SentryService().isInitialized) {
Sentry.captureException(
details.exception,
stackTrace: details.stack,
);
}
// 同时上报到自建遥测服务
if (TelemetryService().isInitialized) {
TelemetryService().logError(
'Flutter error',
error: details.exception,
stackTrace: details.stack,
extra: {'context': details.context?.toString()},
);
}
};
// 捕获异步错误
PlatformDispatcher.instance.onError = (error, stack) {
AppLogger.e('Platform Error', error, stack);
// 上报到 Sentry
if (SentryService().isInitialized) {
Sentry.captureException(error, stackTrace: stack);
}
// 同时上报到自建遥测服务
if (TelemetryService().isInitialized) {
TelemetryService().logError(
'Platform error',
error: error,
stackTrace: stack,
);
}
return true;
};
runApp(
UncontrolledProviderScope(
container: container,
child: await builder(),
),
);
},
);
}
/// 初始化遥测服务(需要 BuildContext在首屏加载后调用
Future<void> initializeTelemetry(BuildContext context, {String? userId}) async {
if (TelemetryService().isInitialized) return;
await TelemetryService().initialize(
apiBaseUrl: _apiBaseUrl,
context: context,
userId: userId,
configSyncInterval: const Duration(hours: 1),
);
// 同步设置 Sentry 用户信息
if (userId != null && SentryService().isInitialized) {
SentryService().setUser(userId: userId);
}
// 设置设备上下文到 Sentry
if (SentryService().isInitialized) {
final deviceContext = TelemetryService().deviceContext;
if (deviceContext != null) {
SentryService().setDeviceContext(
deviceId: TelemetryService().installId,
deviceModel: '${deviceContext.brand} ${deviceContext.model}',
osVersion: deviceContext.osVersion,
appVersion: deviceContext.appVersion,
);
}
}
}
/// 检查应用更新
Future<void> checkForAppUpdate(BuildContext context) async {
if (!UpdateService().isInitialized) return;
// 延迟几秒后检查更新,避免干扰用户
await Future.delayed(const Duration(seconds: 3));
if (!context.mounted) return;
await UpdateService().checkForUpdate(context);
}