Commit 178a615ea0ebafc62d648ff3484334a712b9bf39

Authored by 常守达
1 parent 4c43a3d4

feat(ui): 退登添加日志诊断

1 import 'dart:async'; 1 import 'dart:async';
2 2
  3 +import 'package:doublefeel_flutter/core/logging/app_diagnostic_log_store.dart';
3 import 'package:flutter/widgets.dart'; 4 import 'package:flutter/widgets.dart';
4 import 'package:get/get.dart'; 5 import 'package:get/get.dart';
5 6
@@ -50,4 +51,47 @@ abstract final class AppBootstrap { @@ -50,4 +51,47 @@ abstract final class AppBootstrap {
50 unawaited(AppConfigService.to.fetch()); 51 unawaited(AppConfigService.to.fetch());
51 } 52 }
52 } 53 }
  54 +
  55 + static Future<void> initForBackground() async {
  56 + WidgetsFlutterBinding.ensureInitialized();
  57 + AppLogger.init();
  58 +
  59 + await UserAgentProvider.init();
  60 +
  61 + final local = await LocalStorage.open();
  62 +
  63 + final environmentConfig = AppEnvironmentConfig(local);
  64 + await environmentConfig.init();
  65 + // 1. 【核心】只读取已保存的地区与环境,不要在后台调用 _detectRegion() 重新探测并写入 SharedPreferences,防止误切海外服
  66 + // environmentConfig.environment.value = await local.readEnvironment();
  67 + // environmentConfig.region.value =
  68 + // await local.readRegion() ?? AppRegion.china;
  69 +
  70 + final userPreferencesStorage =
  71 + UserPreferencesStorage(local.sharedPreferences);
  72 + await userPreferencesStorage.init();
  73 +
  74 + final userAccountStorage = UserAccountStorage(local.sharedPreferences);
  75 +
  76 + InitialBinding(
  77 + environmentConfig: environmentConfig,
  78 + userPreferencesStorage: userPreferencesStorage,
  79 + userAccountStorage: userAccountStorage,
  80 + localStorage: local,
  81 + ).dependencies();
  82 +
  83 + NativeHealthDataUpdateBridge.initialize();
  84 + // 2. 后台无 UI,不需要初始化全局 Loading 弹窗
  85 + LoadingService.init();
  86 + // 3. 后台计算不需要重复初始化融云/分析等前台 SDK
  87 + if (local.termsAgreed) {
  88 + await Get.find<UserStateService>().initializeSdks();
  89 + unawaited(AppConfigService.to.fetch());
  90 + }
  91 + AppDiagnosticLogStore.instance.log(
  92 + category: 'initForBackground',
  93 + action: 'success',
  94 + details: {},
  95 + );
  96 + }
53 } 97 }
@@ -8,6 +8,7 @@ import 'package:doublefeel_flutter/core/services/user_state_service.dart'; @@ -8,6 +8,7 @@ import 'package:doublefeel_flutter/core/services/user_state_service.dart';
8 import 'package:flutter/material.dart'; 8 import 'package:flutter/material.dart';
9 import 'package:get/get.dart'; 9 import 'package:get/get.dart';
10 10
  11 +import '../../../../core/logging/app_diagnostic_log_store.dart';
11 import '../../../../core/logging/app_logger.dart'; 12 import '../../../../core/logging/app_logger.dart';
12 import '../../../../core/services/raw_data_service/health_raw_data_core_service.dart'; 13 import '../../../../core/services/raw_data_service/health_raw_data_core_service.dart';
13 import '../../../../core/services/raw_data_service/health_raw_models.dart'; 14 import '../../../../core/services/raw_data_service/health_raw_models.dart';
@@ -30,6 +31,7 @@ class DeveloperOptionsItem { @@ -30,6 +31,7 @@ class DeveloperOptionsItem {
30 } 31 }
31 32
32 enum DeveloperOptionsAction { 33 enum DeveloperOptionsAction {
  34 + shareAppDiagnosticLog,
33 shareHealthRawDataDatabase, 35 shareHealthRawDataDatabase,
34 shareNativeAppleHealthObserverRecord, 36 shareNativeAppleHealthObserverRecord,
35 shareFlutterObserverRecord, 37 shareFlutterObserverRecord,
@@ -72,6 +74,10 @@ class DeveloperOptionsController extends GetxController { @@ -72,6 +74,10 @@ class DeveloperOptionsController extends GetxController {
72 routeName: Routes.TOKEN_LOGIN, 74 routeName: Routes.TOKEN_LOGIN,
73 ), 75 ),
74 DeveloperOptionsItem( 76 DeveloperOptionsItem(
  77 + title: '分享启动及登录态诊断日志',
  78 + action: DeveloperOptionsAction.shareAppDiagnosticLog,
  79 + ),
  80 + DeveloperOptionsItem(
75 title: '分享本地计算数据库文件', 81 title: '分享本地计算数据库文件',
76 action: DeveloperOptionsAction.shareHealthRawDataDatabase, 82 action: DeveloperOptionsAction.shareHealthRawDataDatabase,
77 ), 83 ),
@@ -138,6 +144,9 @@ class DeveloperOptionsController extends GetxController { @@ -138,6 +144,9 @@ class DeveloperOptionsController extends GetxController {
138 } 144 }
139 145
140 switch (item.action) { 146 switch (item.action) {
  147 + case DeveloperOptionsAction.shareAppDiagnosticLog:
  148 + await shareAppDiagnosticLog();
  149 + break;
141 case DeveloperOptionsAction.shareHealthRawDataDatabase: 150 case DeveloperOptionsAction.shareHealthRawDataDatabase:
142 await shareHealthRawDataDatabase(); 151 await shareHealthRawDataDatabase();
143 break; 152 break;
@@ -195,6 +204,16 @@ class DeveloperOptionsController extends GetxController { @@ -195,6 +204,16 @@ class DeveloperOptionsController extends GetxController {
195 } 204 }
196 } 205 }
197 206
  207 + Future<void> shareAppDiagnosticLog() async {
  208 + try {
  209 + final bytes = await AppDiagnosticLogStore.instance.readBytes();
  210 + await _platformHostApi.shareFileData(bytes);
  211 + } catch (error, stackTrace) {
  212 + AppLogger.e('Share AppDiagnosticLog failed', error, stackTrace);
  213 + Get.snackbar('Share failed', error.toString());
  214 + }
  215 + }
  216 +
198 Future<void> shareHealthRawDataDatabase() async { 217 Future<void> shareHealthRawDataDatabase() async {
199 try { 218 try {
200 final bytes = await _healthRawDataCoreService.readDatabaseFileBytes(); 219 final bytes = await _healthRawDataCoreService.readDatabaseFileBytes();
@@ -2,6 +2,7 @@ import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_ @@ -2,6 +2,7 @@ import 'package:doublefeel_flutter/app/modules/friends/controllers/friend_trend_
2 import 'package:doublefeel_flutter/app/modules/friends/controllers/friends_controller.dart'; 2 import 'package:doublefeel_flutter/app/modules/friends/controllers/friends_controller.dart';
3 import 'package:doublefeel_flutter/core/constants/flutter_bridge_method_name.dart'; 3 import 'package:doublefeel_flutter/core/constants/flutter_bridge_method_name.dart';
4 import 'package:doublefeel_flutter/core/constants/intent_keys.dart'; 4 import 'package:doublefeel_flutter/core/constants/intent_keys.dart';
  5 +import 'package:doublefeel_flutter/core/logging/app_diagnostic_log_store.dart';
5 import 'package:doublefeel_flutter/core/network/api/friend_api.dart'; 6 import 'package:doublefeel_flutter/core/network/api/friend_api.dart';
6 import 'package:doublefeel_flutter/core/result/app_result.dart'; 7 import 'package:doublefeel_flutter/core/result/app_result.dart';
7 import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart'; 8 import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart';
@@ -47,6 +48,13 @@ class HomeController extends GetxController { @@ -47,6 +48,13 @@ class HomeController extends GetxController {
47 SchedulerBinding.instance.addPostFrameCallback((_) async { 48 SchedulerBinding.instance.addPostFrameCallback((_) async {
48 try { 49 try {
49 final route = await _platformHostApi.requestUnhandedUrl(); 50 final route = await _platformHostApi.requestUnhandedUrl();
  51 + AppDiagnosticLogStore.instance.log(
  52 + category: 'requestUnhandedUrl',
  53 + action: 'native_return_url',
  54 + details: {
  55 + 'route': route ?? '',
  56 + },
  57 + );
50 // final route ='doublefeel://flutter/home?tab=today&scroll_to_latest_hrv=true'; 58 // final route ='doublefeel://flutter/home?tab=today&scroll_to_latest_hrv=true';
51 // final route = 'doublefeel://flutter/friend-home?user_id=131'; 59 // final route = 'doublefeel://flutter/friend-home?user_id=131';
52 // final route = 'doublefeel://flutter/home?tab=trend&type=sleep'; 60 // final route = 'doublefeel://flutter/home?tab=trend&type=sleep';
  1 +import 'package:doublefeel_flutter/core/logging/app_diagnostic_log_store.dart';
1 import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart'; 2 import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart';
2 import 'package:doublefeel_flutter/core/util/app_toast.dart'; 3 import 'package:doublefeel_flutter/core/util/app_toast.dart';
3 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 4 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
@@ -43,6 +44,11 @@ class SplashController extends GetxController { @@ -43,6 +44,11 @@ class SplashController extends GetxController {
43 final splashDelay = 44 final splashDelay =
44 Get.testMode ? Duration.zero : const Duration(milliseconds: 800); 45 Get.testMode ? Duration.zero : const Duration(milliseconds: 800);
45 await Future<void>.delayed(splashDelay); 46 await Future<void>.delayed(splashDelay);
  47 + AppDiagnosticLogStore.instance.log(
  48 + category: 'Splash',
  49 + action: 'navigate_to_login_due_to_empty_token',
  50 + details: {},
  51 + );
46 Get.offAllNamed(AppRoutes.login); 52 Get.offAllNamed(AppRoutes.login);
47 return; 53 return;
48 } 54 }
@@ -55,6 +61,13 @@ class SplashController extends GetxController { @@ -55,6 +61,13 @@ class SplashController extends GetxController {
55 } catch (_) {} 61 } catch (_) {}
56 await Get.offAllNamed(AppRoutes.home); 62 await Get.offAllNamed(AppRoutes.home);
57 } else { 63 } else {
  64 + AppDiagnosticLogStore.instance.log(
  65 + category: 'Splash',
  66 + action: 'navigate_to_login_due_to_session_refresh_failed',
  67 + details: {
  68 + 'tokenLength': token.length,
  69 + },
  70 + );
58 Get.offAllNamed(AppRoutes.login); 71 Get.offAllNamed(AppRoutes.login);
59 } 72 }
60 } 73 }
@@ -77,6 +90,14 @@ class SplashController extends GetxController { @@ -77,6 +90,14 @@ class SplashController extends GetxController {
77 return true; 90 return true;
78 91
79 case AppFailure(:final error): 92 case AppFailure(:final error):
  93 + AppDiagnosticLogStore.instance.log(
  94 + category: 'Splash',
  95 + action: 'refresh_session_failure',
  96 + details: {
  97 + 'errorType': error.runtimeType.toString(),
  98 + 'displayMessage': error.displayMessage,
  99 + },
  100 + );
80 if (error.isAccessTokenInvalid) { 101 if (error.isAccessTokenInvalid) {
81 return false; 102 return false;
82 } 103 }
  1 +import 'package:doublefeel_flutter/core/logging/app_diagnostic_log_store.dart';
1 import 'package:doublefeel_flutter/core/network/dio_client.dart'; 2 import 'package:doublefeel_flutter/core/network/dio_client.dart';
2 import 'package:doublefeel_flutter/pigeon/platform_api.g.dart'; 3 import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
3 import 'package:flutter/foundation.dart'; 4 import 'package:flutter/foundation.dart';
@@ -21,6 +22,13 @@ class AppEnvironmentConfig { @@ -21,6 +22,13 @@ class AppEnvironmentConfig {
21 Future<AppEnvironmentConfig> init() async { 22 Future<AppEnvironmentConfig> init() async {
22 environment.value = await _storage.readEnvironment(); 23 environment.value = await _storage.readEnvironment();
23 _isNativeDebug = await _platformHostApi.isDebugEnvoriment(); 24 _isNativeDebug = await _platformHostApi.isDebugEnvoriment();
  25 + AppDiagnosticLogStore.instance.log(
  26 + category: 'Debug',
  27 + action: 'detect_debug_from_native_success',
  28 + details: {
  29 + 'isDebug': _isNativeDebug,
  30 + },
  31 + );
24 final stored = await _storage.readRegion(); 32 final stored = await _storage.readRegion();
25 if (stored == null) { 33 if (stored == null) {
26 final detected = await _detectRegion(); 34 final detected = await _detectRegion();
@@ -36,11 +44,27 @@ class AppEnvironmentConfig { @@ -36,11 +44,27 @@ class AppEnvironmentConfig {
36 44
37 Future<AppRegion> _detectRegion() async { 45 Future<AppRegion> _detectRegion() async {
38 try { 46 try {
39 - return await _platformHostApi.isChinaRegion()  
40 - ? AppRegion.china  
41 - : AppRegion.global;  
42 - } catch (_) {  
43 - return _detectRegionFromLocale(); 47 + final isChina = await _platformHostApi.isChinaRegion();
  48 + AppDiagnosticLogStore.instance.log(
  49 + category: 'Region',
  50 + action: 'detect_region_from_native_success',
  51 + details: {
  52 + 'isChina': isChina,
  53 + },
  54 + );
  55 + return isChina ? AppRegion.china : AppRegion.global;
  56 + } catch (error, stackTrace) {
  57 + final fallback = _detectRegionFromLocale();
  58 + AppDiagnosticLogStore.instance.log(
  59 + category: 'Region',
  60 + action: 'detect_region_from_native_failed',
  61 + details: {
  62 + 'error': error.toString(),
  63 + 'stackTrace': stackTrace.toString(),
  64 + 'fallbackResult': fallback.name,
  65 + },
  66 + );
  67 + return fallback;
44 } 68 }
45 } 69 }
46 70
@@ -72,8 +96,17 @@ class AppEnvironmentConfig { @@ -72,8 +96,17 @@ class AppEnvironmentConfig {
72 if (Get.isRegistered<DioClient>()) { 96 if (Get.isRegistered<DioClient>()) {
73 Get.find<DioClient>().refreshBaseUrl(); 97 Get.find<DioClient>().refreshBaseUrl();
74 } 98 }
75 - } catch (e) { 99 + } catch (e, stackTrace) {
76 debugPrint('setRegion failed: $e'); 100 debugPrint('setRegion failed: $e');
  101 + AppDiagnosticLogStore.instance.log(
  102 + category: 'Region',
  103 + action: 'set_region_failed',
  104 + details: {
  105 + 'error': e.toString(),
  106 + 'stackTrace': stackTrace.toString(),
  107 + 'targetRegion': value.name,
  108 + },
  109 + );
77 } 110 }
78 } 111 }
79 112
@@ -2,6 +2,7 @@ import 'package:doublefeel_flutter/app/actions/dialog_action.dart'; @@ -2,6 +2,7 @@ import 'package:doublefeel_flutter/app/actions/dialog_action.dart';
2 import 'package:doublefeel_flutter/app/models/dialog_meta_data.dart'; 2 import 'package:doublefeel_flutter/app/models/dialog_meta_data.dart';
3 import 'package:doublefeel_flutter/app/routes/app_pages.dart'; 3 import 'package:doublefeel_flutter/app/routes/app_pages.dart';
4 import 'package:doublefeel_flutter/app/utils/dialog_utils.dart'; 4 import 'package:doublefeel_flutter/app/utils/dialog_utils.dart';
  5 +import 'package:doublefeel_flutter/core/logging/app_diagnostic_log_store.dart';
5 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart'; 6 import 'package:doublefeel_flutter/l10n/l10n_extensions.dart';
6 import 'package:get/get.dart'; 7 import 'package:get/get.dart';
7 8
@@ -64,7 +65,13 @@ class AppErrorHandler { @@ -64,7 +65,13 @@ class AppErrorHandler {
64 iconAsset: 'assets/images/common/ic_warning.png', 65 iconAsset: 'assets/images/common/ic_warning.png',
65 )); 66 ));
66 if (confirmResult.action != DialogAction.confirm) return; 67 if (confirmResult.action != DialogAction.confirm) return;
67 - 68 + AppDiagnosticLogStore.instance.log(
  69 + category: 'AccessToken',
  70 + action: 'invalid',
  71 + details: {
  72 + 'error': '401',
  73 + },
  74 + );
68 Get.offAllNamed(AppRoutes.login); 75 Get.offAllNamed(AppRoutes.login);
69 } 76 }
70 77
  1 +import 'dart:convert';
  2 +import 'dart:io';
  3 +import 'dart:typed_data';
  4 +
  5 +import 'package:path_provider/path_provider.dart';
  6 +
  7 +import 'app_logger.dart';
  8 +
  9 +/// Persists structured diagnostic events (region detection, login/user-prefs lifecycle, etc.)
  10 +/// to a local JSON file using path_provider, which can be shared from Developer Options.
  11 +class AppDiagnosticLogStore {
  12 + AppDiagnosticLogStore({Directory? rootDirectory})
  13 + : _rootDirectory = rootDirectory;
  14 +
  15 + static final AppDiagnosticLogStore instance = AppDiagnosticLogStore();
  16 +
  17 + static const _fileName = 'app_diagnostic_events.json';
  18 + static const _maxEventCount = 500;
  19 +
  20 + final Directory? _rootDirectory;
  21 + Future<void> _writeQueue = Future.value();
  22 +
  23 + /// Appends a diagnostic event to the local file.
  24 + Future<void> log({
  25 + required String category,
  26 + required String action,
  27 + Map<String, Object?>? details,
  28 + }) {
  29 + _writeQueue = _writeQueue.then((_) async {
  30 + try {
  31 + final now = DateTime.now();
  32 + final event = <String, Object?>{
  33 + 'category': category,
  34 + 'action': action,
  35 + 'timestamp': now.toIso8601String(),
  36 + 'timestamp_readable': _readableTime(now),
  37 + 'timestamp_unix': now.millisecondsSinceEpoch / 1000,
  38 + if (details != null && details.isNotEmpty)
  39 + 'details': _sanitizeMap(details),
  40 + };
  41 +
  42 + try {
  43 + AppLogger.d('[$category] $action details=$details');
  44 + } catch (_) {}
  45 +
  46 + final file = await _file();
  47 + await file.parent.create(recursive: true);
  48 + final events = await _readEvents(file);
  49 + events.add(event);
  50 +
  51 + final limited = events.length > _maxEventCount
  52 + ? events.sublist(events.length - _maxEventCount)
  53 + : events;
  54 +
  55 + const encoder = JsonEncoder.withIndent(' ');
  56 + await file.writeAsString(encoder.convert(limited), flush: true);
  57 + } catch (error, stackTrace) {
  58 + try {
  59 + AppLogger.e('AppDiagnosticLogStore log failed', error, stackTrace);
  60 + } catch (_) {}
  61 + }
  62 + });
  63 + return _writeQueue;
  64 + }
  65 +
  66 + /// Reads the log file as [Uint8List] bytes for sharing via platform APIs.
  67 + Future<Uint8List> readBytes() async {
  68 + final file = await _file();
  69 + if (!await file.exists()) {
  70 + const emptyContent = '[\n {\n "message": "No diagnostic logs found"\n }\n]';
  71 + return Uint8List.fromList(utf8.encode(emptyContent));
  72 + }
  73 + return await file.readAsBytes();
  74 + }
  75 +
  76 + /// Reads the log file content as a formatted string.
  77 + Future<String> readText() async {
  78 + final file = await _file();
  79 + if (!await file.exists()) {
  80 + return '暂无诊断日志';
  81 + }
  82 + final text = await file.readAsString();
  83 + return text.trim().isEmpty ? '暂无诊断日志' : text;
  84 + }
  85 +
  86 + /// Clears the log file.
  87 + Future<void> clear() async {
  88 + final file = await _file();
  89 + if (await file.exists()) {
  90 + await file.delete();
  91 + }
  92 + }
  93 +
  94 + Future<File> _file() async {
  95 + final root = _rootDirectory ?? await getApplicationDocumentsDirectory();
  96 + return File('${root.path}/$_fileName');
  97 + }
  98 +
  99 + Future<List<Map<String, Object?>>> _readEvents(File file) async {
  100 + if (!await file.exists()) {
  101 + return <Map<String, Object?>>[];
  102 + }
  103 + try {
  104 + final text = await file.readAsString();
  105 + if (text.trim().isEmpty) {
  106 + return <Map<String, Object?>>[];
  107 + }
  108 + final json = jsonDecode(text);
  109 + if (json is List) {
  110 + return json
  111 + .whereType<Map>()
  112 + .map((e) => _sanitizeMap(e.cast<String, Object?>()))
  113 + .toList();
  114 + }
  115 + } catch (_) {}
  116 + return <Map<String, Object?>>[];
  117 + }
  118 +
  119 + static Map<String, Object?> _sanitizeMap(Map<String, Object?> map) {
  120 + return map.map((key, value) => MapEntry(key, _sanitizeValue(value)));
  121 + }
  122 +
  123 + static Object? _sanitizeValue(Object? value) {
  124 + return switch (value) {
  125 + null => null,
  126 + String() => value,
  127 + num() => value,
  128 + bool() => value,
  129 + DateTime() => value.toIso8601String(),
  130 + List() => value.map(_sanitizeValue).toList(),
  131 + Map() => value.map(
  132 + (key, val) => MapEntry(key.toString(), _sanitizeValue(val)),
  133 + ),
  134 + _ => value.toString(),
  135 + };
  136 + }
  137 +
  138 + static String _readableTime(DateTime time) {
  139 + return '${time.year.toString().padLeft(4, '0')}-'
  140 + '${time.month.toString().padLeft(2, '0')}-'
  141 + '${time.day.toString().padLeft(2, '0')} '
  142 + '${time.hour.toString().padLeft(2, '0')}:'
  143 + '${time.minute.toString().padLeft(2, '0')}:'
  144 + '${time.second.toString().padLeft(2, '0')}';
  145 + }
  146 +}
1 import 'dart:convert'; 1 import 'dart:convert';
2 2
3 import 'package:doublefeel_flutter/core/config/app_environment_config.dart'; 3 import 'package:doublefeel_flutter/core/config/app_environment_config.dart';
  4 +import 'package:doublefeel_flutter/core/logging/app_diagnostic_log_store.dart';
  5 +import 'package:doublefeel_flutter/core/logging/app_logger.dart';
4 import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart'; 6 import 'package:doublefeel_flutter/core/services/raw_data_service/health_raw_data_core_service.dart';
5 import 'package:doublefeel_flutter/pigeon/platform_api.g.dart'; 7 import 'package:doublefeel_flutter/pigeon/platform_api.g.dart';
6 import 'package:get/get.dart'; 8 import 'package:get/get.dart';
@@ -42,7 +44,17 @@ class UserPreferencesStorage { @@ -42,7 +44,17 @@ class UserPreferencesStorage {
42 try { 44 try {
43 final map = jsonDecode(raw) as Map<String, dynamic>; 45 final map = jsonDecode(raw) as Map<String, dynamic>;
44 preferences.value = UserPreferences.fromJson(map); 46 preferences.value = UserPreferences.fromJson(map);
45 - } catch (_) { 47 + } catch (error, stackTrace) {
  48 + AppLogger.e('UserPreferences JSON parse failed', error, stackTrace);
  49 + AppDiagnosticLogStore.instance.log(
  50 + category: 'UserPreferences',
  51 + action: 'load_deserialization_failed',
  52 + details: {
  53 + 'error': error.toString(),
  54 + 'stackTrace': stackTrace.toString(),
  55 + 'rawPreview': raw.length > 200 ? '${raw.substring(0, 200)}...' : raw,
  56 + },
  57 + );
46 preferences.value = UserPreferences.empty; 58 preferences.value = UserPreferences.empty;
47 } 59 }
48 _syncLoginInfoToNative(userInfo: preferences.value); 60 _syncLoginInfoToNative(userInfo: preferences.value);
@@ -41,7 +41,7 @@ Future<void> healthBackgroundMain() async { @@ -41,7 +41,7 @@ Future<void> healthBackgroundMain() async {
41 await _healthBackgroundLog(channel, 'entry.start'); 41 await _healthBackgroundLog(channel, 'entry.start');
42 try { 42 try {
43 await _healthBackgroundLog(channel, 'bootstrap.start'); 43 await _healthBackgroundLog(channel, 'bootstrap.start');
44 - await AppBootstrap.init(); 44 + await AppBootstrap.initForBackground();
45 await _healthBackgroundLog(channel, 'bootstrap.success'); 45 await _healthBackgroundLog(channel, 'bootstrap.success');
46 } catch (error, stackTrace) { 46 } catch (error, stackTrace) {
47 await _healthBackgroundLog( 47 await _healthBackgroundLog(