boost_logger.dart 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:path_provider/path_provider.dart';
  4. import 'package:flutter_app_group_directory/flutter_app_group_directory.dart';
  5. import 'log/logger.dart';
  6. class BoostLogger {
  7. static const String LOG_FOLDER = 'boost_logs';
  8. static const String APP_LOG_FILE = 'app.json';
  9. static const String CORE_LOG_FILE = 'core.json';
  10. static const String TAG = 'BoostLogger';
  11. Map<String, dynamic> _currentSession = {};
  12. String? _logPath;
  13. /// 单例模式实现
  14. static final BoostLogger _instance = BoostLogger._internal();
  15. factory BoostLogger() => _instance;
  16. BoostLogger._internal();
  17. /// 获取日志目录
  18. Future<Directory> _getLogDirectory() async {
  19. if (Platform.isIOS) {
  20. try {
  21. // iOS 使用 App Group 目录
  22. final Directory? appGroupDirectory =
  23. await FlutterAppGroupDirectory.getAppGroupDirectory(
  24. 'group.app.xixi.nomo',
  25. );
  26. // 验证 App Group 目录是否有效
  27. if (appGroupDirectory != null) {
  28. final logDir = Directory('${appGroupDirectory.path}/$LOG_FOLDER');
  29. if (!await logDir.exists()) {
  30. await logDir.create(recursive: true);
  31. }
  32. return logDir;
  33. } else {
  34. // App Group 目录不可用,回退到应用文档目录
  35. log(
  36. TAG,
  37. 'App Group directory not available, falling back to documents directory',
  38. );
  39. final appDir = await getApplicationDocumentsDirectory();
  40. final logDir = Directory('${appDir.path}/$LOG_FOLDER');
  41. if (!await logDir.exists()) {
  42. await logDir.create(recursive: true);
  43. }
  44. return logDir;
  45. }
  46. } catch (e) {
  47. // 如果 App Group 出现错误,回退到应用文档目录
  48. log(
  49. TAG,
  50. 'Error with App Group directory: $e, falling back to documents directory',
  51. );
  52. final appDir = await getApplicationDocumentsDirectory();
  53. final logDir = Directory('${appDir.path}/$LOG_FOLDER');
  54. if (!await logDir.exists()) {
  55. await logDir.create(recursive: true);
  56. }
  57. return logDir;
  58. }
  59. } else {
  60. // Android 使用外部存储目录
  61. final appDir = await getExternalStorageDirectory();
  62. if (appDir == null) {
  63. throw Exception('Failed to get external storage directory');
  64. }
  65. final logDir = Directory('${appDir.path}/$LOG_FOLDER');
  66. if (!await logDir.exists()) {
  67. await logDir.create(recursive: true);
  68. }
  69. return logDir;
  70. }
  71. }
  72. /// 初始化日志系统
  73. Future<void> init() async {
  74. try {
  75. final logDir = await _getLogDirectory();
  76. _logPath = logDir.path;
  77. // 清除旧的app日志文件
  78. final appFile = File('${logDir.path}/$APP_LOG_FILE');
  79. if (await appFile.exists()) {
  80. await appFile.delete();
  81. }
  82. // 清除旧的内核日志文件
  83. final coreFile = File('${logDir.path}/$CORE_LOG_FILE');
  84. if (await coreFile.exists()) {
  85. await coreFile.delete();
  86. }
  87. // 初始化空的会话数据
  88. _currentSession = {};
  89. await _saveSession();
  90. } catch (e) {
  91. log(TAG, 'BoostLogger init error: $e');
  92. }
  93. }
  94. //读取历史日志
  95. Future<void> readHistoryLog() async {
  96. try {
  97. final logDir = await _getLogDirectory();
  98. _logPath = logDir.path;
  99. getCurrentSession();
  100. } catch (e) {
  101. log(TAG, 'BoostLogger readHistoryLog error: $e');
  102. }
  103. }
  104. /// 设置整个部分的数据
  105. Future<void> setSection(String section, Map<String, dynamic> data) async {
  106. try {
  107. _currentSession[section] = data;
  108. await _saveSession();
  109. } catch (e) {
  110. log(TAG, 'BoostLogger setSection error: $e');
  111. }
  112. }
  113. /// 设置整个部分的数据
  114. Future<void> setSectionObj(String section, dynamic data) async {
  115. try {
  116. _currentSession[section] = data;
  117. await _saveSession();
  118. } catch (e) {
  119. log(TAG, 'BoostLogger setSectionObj error: $e');
  120. }
  121. }
  122. /// 更新部分中的特定字段
  123. Future<void> updateField(String section, String field, dynamic value) async {
  124. try {
  125. final sectionData = _currentSession[section] as Map<String, dynamic>;
  126. sectionData[field] = value;
  127. _currentSession[section] = sectionData;
  128. await _saveSession();
  129. } catch (e) {
  130. log(TAG, 'BoostLogger updateField error: $e');
  131. }
  132. }
  133. /// 向数组添加数据
  134. Future<void> appendToArray(
  135. String section,
  136. String arrayField,
  137. Map<String, dynamic> data,
  138. ) async {
  139. try {
  140. final sectionData =
  141. _currentSession[section] as Map<String, dynamic>? ?? {};
  142. final array = sectionData[arrayField] as List<dynamic>? ?? [];
  143. array.add(data);
  144. sectionData[arrayField] = array;
  145. _currentSession[section] = sectionData;
  146. await _saveSession();
  147. } catch (e) {
  148. log(TAG, 'BoostLogger appendToArray error: $e');
  149. }
  150. }
  151. /// 保存会话数据到文件
  152. Future<void> _saveSession() async {
  153. if (_logPath == null) return;
  154. try {
  155. final file = File('$_logPath/$APP_LOG_FILE');
  156. // 使用 writeAsStringSync 确保写入完成
  157. final jsonString = const JsonEncoder.withIndent(
  158. ' ',
  159. ).convert(_currentSession);
  160. await file.writeAsString(jsonString, flush: true);
  161. // 验证文件写入
  162. final content = await file.readAsString();
  163. final savedData = jsonDecode(content) as Map<String, dynamic>;
  164. log(TAG, 'BoostLogger verify saved data: $savedData');
  165. } catch (e) {
  166. log(TAG, 'BoostLogger save session error: $e');
  167. }
  168. }
  169. /// 获取当前会话数据
  170. Map<String, dynamic> getCurrentSession() {
  171. try {
  172. // 从文件读取最新数据
  173. final file = File('$_logPath/$APP_LOG_FILE');
  174. if (file.existsSync()) {
  175. final content = file.readAsStringSync();
  176. _currentSession = jsonDecode(content) as Map<String, dynamic>;
  177. }
  178. return Map<String, dynamic>.from(_currentSession);
  179. } catch (e) {
  180. log(TAG, 'BoostLogger getCurrentSession error: $e');
  181. return {};
  182. }
  183. }
  184. /// 获取日志文件路径
  185. Future<String?> getAppLogFilePath() async {
  186. return _logPath != null ? '$_logPath/$APP_LOG_FILE' : null;
  187. }
  188. /// 获取核心日志文件路径
  189. Future<String?> getCoreLogFilePath() async {
  190. return _logPath != null ? '$_logPath/$CORE_LOG_FILE' : null;
  191. }
  192. /// 清理资源
  193. Future<void> release() async {
  194. try {
  195. // 检查 _currentSession 是否为空
  196. if (_currentSession.isEmpty) {
  197. return;
  198. }
  199. await _saveSession();
  200. _currentSession.clear();
  201. } catch (e) {
  202. log(TAG, 'BoostLogger release error: $e');
  203. }
  204. }
  205. }