172 lines
5.1 KiB
Dart
172 lines
5.1 KiB
Dart
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);
|
||
}
|