core_controller.dart 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. import 'dart:async';
  2. import 'dart:convert';
  3. import 'dart:io';
  4. import 'package:device_info_plus/device_info_plus.dart';
  5. import 'package:dio/dio.dart';
  6. import 'package:get/get.dart';
  7. import 'package:nomo/app/constants/api_domains.dart';
  8. import 'package:nomo/app/constants/keys.dart';
  9. import 'package:nomo/app/dialog/all_dialog.dart';
  10. import 'package:package_info_plus/package_info_plus.dart';
  11. import 'package:uuid/uuid.dart';
  12. import '../../config/translations/strings_enum.dart';
  13. import 'base_core_api.dart';
  14. import '../../utils/boost_report_manager.dart';
  15. import '../../utils/haptic_feedback_manager.dart';
  16. import '../../utils/log/logger.dart';
  17. import '../../utils/network_helper.dart';
  18. import '../components/ix_snackbar.dart';
  19. import '../constants/enums.dart';
  20. import '../constants/errors.dart';
  21. import '../data/models/api_exception.dart';
  22. import '../data/models/failure.dart';
  23. import '../data/models/vpn_message.dart';
  24. import '../data/sp/ix_sp.dart';
  25. import '../constants/sp_keys.dart';
  26. import '../dialog/error_dialog.dart';
  27. import 'api_controller.dart';
  28. class CoreController extends GetxService {
  29. final TAG = 'CoreController';
  30. final _apiController = Get.find<ApiController>();
  31. final _state = ConnectionState.disconnected.obs;
  32. ConnectionState get state => _state.value;
  33. set state(ConnectionState value) => _state.value = value;
  34. // 公开状态流供外部监听
  35. Rx<ConnectionState> get stateStream => _state;
  36. final _timer = "00:00:00".obs;
  37. String get timer => _timer.value;
  38. set timer(String value) => _timer.value = value;
  39. // VPN 事件流订阅
  40. StreamSubscription<String>? _eventSubscription;
  41. CancelToken? _cancelToken;
  42. //全局uuid
  43. final _globalUuid = Uuid().v4();
  44. String locationSelectionType = 'auto';
  45. // 标记 VPN 逻辑是否已开启(调用了 BaseCoreApi().connect())
  46. bool _isVpnStarted = false;
  47. // 标记是否有待处理的断开请求
  48. bool _pendingDisconnect = false;
  49. // 用于等待断开完成的 Completer
  50. Completer<void>? _disconnectCompleter;
  51. @override
  52. void onInit() {
  53. super.onInit();
  54. _initCheckConnect();
  55. _startListeningToEvents();
  56. }
  57. @override
  58. void onClose() {
  59. super.onClose();
  60. // 取消事件流订阅
  61. _eventSubscription?.cancel();
  62. _eventSubscription = null;
  63. }
  64. void _initCheckConnect() {
  65. BaseCoreApi().isConnected().then((value) {
  66. if (value == true) {
  67. state = ConnectionState.connected;
  68. _isVpnStarted = true;
  69. } else {
  70. state = ConnectionState.disconnected;
  71. _isVpnStarted = false;
  72. }
  73. });
  74. }
  75. void handleConnection() async {
  76. // 如果正在断开中,忽略操作
  77. if (state == ConnectionState.disconnecting) {
  78. log(TAG, '正在断开中,忽略操作');
  79. return;
  80. }
  81. if (state == ConnectionState.disconnected) {
  82. // 开始连接 - 轻微震动
  83. state = ConnectionState.connectingVirtual;
  84. _isVpnStarted = false;
  85. _pendingDisconnect = false;
  86. HapticFeedbackManager.connectionStart();
  87. getDispatchInfo();
  88. } else if (state == ConnectionState.connectingVirtual) {
  89. // 虚拟连接中点击断开
  90. if (_isVpnStarted) {
  91. // VPN 逻辑已开启,标记待断开,等待 _onVpnConnecting 返回后执行断开
  92. log(TAG, 'VPN 已启动,标记待断开');
  93. _pendingDisconnect = true;
  94. } else {
  95. // VPN 逻辑还没开启,取消请求并初始化状态
  96. log(TAG, 'VPN 未启动,取消请求并初始化状态');
  97. _cancelToken?.cancel('用户取消连接');
  98. _cancelToken = null;
  99. _uninitState();
  100. }
  101. } else if (state == ConnectionState.connecting) {
  102. // 真实连接中点击断开 - 执行断开逻辑
  103. log(TAG, '真实连接中,执行断开逻辑');
  104. await _performDisconnect();
  105. } else if (state == ConnectionState.connected) {
  106. // 已连接状态,执行断开逻辑
  107. await _performDisconnect();
  108. }
  109. }
  110. /// 执行断开逻辑,等待断开完成
  111. Future<void> _performDisconnect() async {
  112. // 如果已经在断开中,等待断开完成(带超时)
  113. if (_disconnectCompleter != null) {
  114. log(TAG, '已经在断开中,等待完成');
  115. try {
  116. await _disconnectCompleter!.future.timeout(
  117. const Duration(seconds: 10),
  118. onTimeout: () {
  119. log(TAG, '等待断开超时,强制清理');
  120. _forceCleanupDisconnect();
  121. },
  122. );
  123. } catch (e) {
  124. log(TAG, '等待断开异常: $e');
  125. _forceCleanupDisconnect();
  126. }
  127. return;
  128. }
  129. log(TAG, '开始执行断开逻辑, _isVpnStarted=$_isVpnStarted');
  130. // 如果 VPN 根本没启动,直接清理状态即可
  131. if (!_isVpnStarted) {
  132. log(TAG, 'VPN 未启动,直接清理状态');
  133. _uninitState();
  134. return;
  135. }
  136. state = ConnectionState.disconnecting;
  137. _disconnectCompleter = Completer<void>();
  138. try {
  139. BaseCoreApi().disconnect();
  140. } catch (e) {
  141. log(TAG, 'disconnect 调用异常: $e');
  142. _forceCleanupDisconnect();
  143. return;
  144. }
  145. // 等待断开完成(带超时)
  146. try {
  147. await _disconnectCompleter!.future.timeout(
  148. const Duration(seconds: 10),
  149. onTimeout: () {
  150. log(TAG, '断开超时,强制清理');
  151. _forceCleanupDisconnect();
  152. },
  153. );
  154. } catch (e) {
  155. log(TAG, '断开等待异常: $e');
  156. _forceCleanupDisconnect();
  157. }
  158. }
  159. /// 强制清理断开状态
  160. void _forceCleanupDisconnect() {
  161. if (_disconnectCompleter != null && !_disconnectCompleter!.isCompleted) {
  162. _disconnectCompleter!.complete();
  163. }
  164. _disconnectCompleter = null;
  165. _isVpnStarted = false;
  166. _pendingDisconnect = false;
  167. _uninitState();
  168. }
  169. void selectLocationConnect() async {
  170. if (state == ConnectionState.disconnecting) {
  171. log(TAG, '正在断开中,等待断开完成');
  172. if (_disconnectCompleter != null) {
  173. await _disconnectCompleter!.future;
  174. }
  175. }
  176. if (state != ConnectionState.disconnected) {
  177. await _performDisconnect();
  178. // 延迟300ms
  179. await Future.delayed(const Duration(milliseconds: 300));
  180. log(TAG, 'selectLocationConnect disconnected = $state');
  181. state = ConnectionState.connectingVirtual;
  182. _isVpnStarted = false;
  183. _pendingDisconnect = false;
  184. getDispatchInfo();
  185. } else {
  186. handleConnection();
  187. }
  188. }
  189. Future<void> getDispatchInfo() async {
  190. // 如果正在请求中,取消当前请求
  191. if (_cancelToken != null) {
  192. log(TAG, '取消当前请求,重新发起新请求');
  193. _cancelToken?.cancel('取消旧请求,发起新请求');
  194. }
  195. // 创建新的 CancelToken
  196. final currentToken = CancelToken();
  197. _cancelToken = currentToken;
  198. // 创建一条加速日志
  199. await createBoostLog();
  200. try {
  201. final locationId = IXSP.getSelectedLocation()?['id'];
  202. final locationCode = IXSP.getSelectedLocation()?['code'];
  203. final launch = await _apiController.getDispatchInfo(
  204. locationId,
  205. locationCode,
  206. cancelToken: currentToken,
  207. );
  208. // 只有当前 token 没有被替换时才清空
  209. if (_cancelToken == currentToken) {
  210. _cancelToken = null;
  211. }
  212. final remainTime = launch.userConfig?.remainTime ?? 0;
  213. if (remainTime <= 0) {
  214. _onVpnError(Errors.ERROR_REMAIN_TIME, Strings.remainTimeEnded.tr);
  215. return;
  216. }
  217. if (state == ConnectionState.connectingVirtual) {
  218. // 标记 VPN 逻辑已开启
  219. _isVpnStarted = true;
  220. final sessionId = Uuid().v4();
  221. final socksPort = launch.nodesConfig!.socketPort!;
  222. final tunnelConfig = launch.nodesConfig!.tunnelConfig!;
  223. final configJson = jsonEncode(launch.nodesConfig!);
  224. // 根据分流隧道设置获取 allowVpnApps 和 disallowVpnApps
  225. final splitTunnelingApps = _getSplitTunnelingApps();
  226. final allowVpnApps = splitTunnelingApps['allowVpnApps']!;
  227. final disallowVpnApps = splitTunnelingApps['disallowVpnApps']!;
  228. final accessToken = launch.userConfig?.accessToken ?? '';
  229. final peekTimeInterval = launch.appConfig?.peekTimeInterval ?? 600;
  230. final aesKey = Keys.aesKey;
  231. final aesIv = Keys.aesIv;
  232. final baseUrls = ApiDomains.instance.getAllLogUrls();
  233. final params = jsonEncode(_apiController.fp);
  234. BaseCoreApi().connect(
  235. sessionId,
  236. socksPort,
  237. tunnelConfig,
  238. configJson,
  239. remainTime,
  240. false,
  241. allowVpnApps,
  242. disallowVpnApps,
  243. accessToken,
  244. aesKey,
  245. aesIv,
  246. locationId,
  247. locationCode,
  248. baseUrls,
  249. params,
  250. peekTimeInterval,
  251. );
  252. }
  253. } on DioException catch (e, s) {
  254. // 只有当前 token 没有被替换时才清空
  255. if (_cancelToken == currentToken) {
  256. _cancelToken = null;
  257. }
  258. // 如果是取消错误,不处理
  259. if (e.type == DioExceptionType.cancel) {
  260. log(TAG, '请求已取消');
  261. return;
  262. }
  263. if (state == ConnectionState.connectingVirtual) {
  264. state = ConnectionState.disconnected;
  265. }
  266. handleErrorDialog(e, s);
  267. log(TAG, 'getDispatchInfo error: $e');
  268. } catch (e, s) {
  269. // 只有当前 token 没有被替换时才清空
  270. if (_cancelToken == currentToken) {
  271. _cancelToken = null;
  272. }
  273. if (state == ConnectionState.connectingVirtual) {
  274. state = ConnectionState.disconnected;
  275. }
  276. handleErrorDialog(e, s);
  277. log(TAG, 'getDispatchInfo error: $e');
  278. }
  279. }
  280. /// 根据分流隧道设置获取 allowVpnApps 和 disallowVpnApps
  281. /// 直接从 IXSP 读取,参考 SplittunnelingController 的逻辑
  282. Map<String, List<String>> _getSplitTunnelingApps() {
  283. List<String> allowVpnApps = [];
  284. List<String> disallowVpnApps = [];
  285. try {
  286. // 读取选中的模式
  287. final modeString = IXSP.getString(SPKeys.splittunnelingSelectedMode);
  288. if (modeString == null) {
  289. log(TAG, '分流隧道未设置模式');
  290. return {
  291. 'allowVpnApps': allowVpnApps,
  292. 'disallowVpnApps': disallowVpnApps,
  293. };
  294. }
  295. // 判断模式类型
  296. final isExcludeMode = modeString.contains('exclude');
  297. final isIncludeMode = modeString.contains('include');
  298. if (!isExcludeMode && !isIncludeMode) {
  299. log(TAG, '分流隧道模式为 none');
  300. return {
  301. 'allowVpnApps': allowVpnApps,
  302. 'disallowVpnApps': disallowVpnApps,
  303. };
  304. }
  305. // 根据模式获取对应的应用列表
  306. final key = isExcludeMode
  307. ? SPKeys.splittunnelingExcludeSelectedApps
  308. : SPKeys.splittunnelingIncludeSelectedApps;
  309. final selectedAppsJson = IXSP.getString(key);
  310. if (selectedAppsJson != null) {
  311. final selectedPackageNames =
  312. (jsonDecode(selectedAppsJson) as List<dynamic>).cast<String>();
  313. if (isIncludeMode) {
  314. // include 模式:只有选中的应用走 VPN
  315. allowVpnApps = selectedPackageNames;
  316. log(TAG, '分流隧道 include 模式,允许的应用: $allowVpnApps');
  317. } else {
  318. // exclude 模式:选中的应用不走 VPN
  319. disallowVpnApps = selectedPackageNames;
  320. log(TAG, '分流隧道 exclude 模式,排除的应用: $disallowVpnApps');
  321. }
  322. }
  323. } catch (e) {
  324. log(TAG, '获取分流隧道设置失败: $e');
  325. }
  326. return {'allowVpnApps': allowVpnApps, 'disallowVpnApps': disallowVpnApps};
  327. }
  328. /// 开始监听来自 Android 的事件
  329. void _startListeningToEvents() {
  330. _eventSubscription = onEventChange().listen(
  331. _handleEventChange,
  332. onError: (error) {
  333. log(TAG, '事件流错误: $error');
  334. },
  335. );
  336. }
  337. // 处理从原生端接收到的消息
  338. void _handleEventChange(String message) {
  339. try {
  340. final Map<String, dynamic> json = jsonDecode(message);
  341. final String type = json['type'] ?? '';
  342. switch (type) {
  343. case 'vpn_status':
  344. _handleVpnStatus(VpnStatusMessage.fromJson(json));
  345. break;
  346. case 'timer_update':
  347. _handleTimerUpdate(TimerUpdateMessage.fromJson(json));
  348. break;
  349. case 'boost_result':
  350. _handleBoostResult(BoostResultMessage.fromJson(json));
  351. break;
  352. default:
  353. log(TAG, '未知消息类型: $type');
  354. }
  355. } catch (e) {
  356. log(TAG, '解析消息失败: $e');
  357. }
  358. }
  359. void _handleVpnStatus(VpnStatusMessage message) {
  360. final vpnError = VpnStatus.fromValue(message.status);
  361. log(
  362. TAG,
  363. 'VPN状态变化: ${vpnError.label}, status=${message.status}, code=${message.code}, message=${message.message}',
  364. );
  365. // 根据状态码处理不同的VPN状态
  366. switch (vpnError) {
  367. case VpnStatus.idle:
  368. // disconnected
  369. _onVpnDisconnected();
  370. break;
  371. case VpnStatus.connecting:
  372. // connecting
  373. _onVpnConnecting();
  374. break;
  375. case VpnStatus.connected:
  376. // connected
  377. _onVpnConnected();
  378. break;
  379. case VpnStatus.error:
  380. // error
  381. _onVpnError(message.code, message.message);
  382. break;
  383. }
  384. }
  385. void _handleTimerUpdate(TimerUpdateMessage message) {
  386. //log(TAG, '计时更新: time=${message.currentTime}, mode=${message.mode}');
  387. timer = _formatTime(message.currentTime);
  388. }
  389. void _handleBoostResult(BoostResultMessage message) async {
  390. log(
  391. TAG,
  392. '加速结果: locationCode=${message.locationCode}, nodeId=${message.nodeId}, success=${message.success}',
  393. );
  394. if (message.success) {
  395. try {
  396. await _apiController.connected({
  397. 'locationCode': message.locationCode,
  398. 'instanceId': message.nodeId,
  399. });
  400. } catch (e) {
  401. log('handleRouterConnected error: $e');
  402. }
  403. }
  404. try {
  405. final json = jsonDecode(message.param);
  406. await _apiController.uploadLogs(json);
  407. } catch (e) {
  408. log('handleBoostResult error: $e');
  409. }
  410. }
  411. // VPN状态处理方法
  412. void _onVpnDisconnected() {
  413. log(TAG, 'VPN已断开连接');
  414. // 完成断开 Completer
  415. if (_disconnectCompleter != null && !_disconnectCompleter!.isCompleted) {
  416. _disconnectCompleter!.complete();
  417. }
  418. _disconnectCompleter = null;
  419. // 重置标志位
  420. _isVpnStarted = false;
  421. _pendingDisconnect = false;
  422. // 更新UI状态
  423. _uninitState();
  424. // 上传 Boost 日志(不阻塞)
  425. _apiController.uploadBoostLog();
  426. // FeedbackBottomSheet.show();
  427. }
  428. void _onVpnConnecting() {
  429. log(TAG, 'VPN正在连接');
  430. // 检查是否有待处理的断开请求
  431. if (_pendingDisconnect) {
  432. log(TAG, '检测到待处理的断开请求,执行断开');
  433. _pendingDisconnect = false;
  434. _performDisconnect();
  435. return;
  436. }
  437. // 显示连接中状态
  438. state = ConnectionState.connecting;
  439. }
  440. void _onVpnConnected() {
  441. log(TAG, 'VPN已连接');
  442. // 显示已连接状态
  443. state = ConnectionState.connected;
  444. HapticFeedbackManager.connectionSuccess();
  445. }
  446. void _onVpnError(int code, String message) {
  447. log(TAG, 'VPN连接错误: code=$code, message=$message');
  448. // 完成断开 Completer(如果有)
  449. if (_disconnectCompleter != null && !_disconnectCompleter!.isCompleted) {
  450. _disconnectCompleter!.complete();
  451. }
  452. _disconnectCompleter = null;
  453. // 重置标志位
  454. _isVpnStarted = false;
  455. _pendingDisconnect = false;
  456. // 显示错误信息
  457. _uninitState();
  458. showErrorDialog(code, message);
  459. // 上传 Boost 日志(不阻塞)
  460. _apiController.uploadBoostLog();
  461. }
  462. void showErrorDialog(int code, String message) {
  463. var errorMessage = message;
  464. switch (code) {
  465. case Errors.ERROR_NODE_TIMEOUT:
  466. errorMessage = Strings.vpnConnectionTimeoutError.tr;
  467. break;
  468. case Errors.ERROR_NO_NODE:
  469. errorMessage = Strings.vpnNoNodeError.tr;
  470. break;
  471. case Errors.ERROR_INIT:
  472. errorMessage = Strings.vpnInitError.tr;
  473. break;
  474. case Errors.ERROR_KILL:
  475. errorMessage = Strings.vpnKillError.tr;
  476. break;
  477. case Errors.ERROR_REVOKE:
  478. errorMessage = Strings.vpnRevokeError.tr;
  479. break;
  480. case Errors.ERROR_SERVICE_EMPTY:
  481. errorMessage = Strings.vpnServiceEmptyError.tr;
  482. break;
  483. case Errors.ERROR_ROUTER:
  484. errorMessage = Strings.vpnRouterError.tr;
  485. break;
  486. case Errors.ERROR_PERMISSION_DENIED:
  487. errorMessage = Strings.vpnPermissionDeniedError.tr;
  488. break;
  489. case Errors.ERROR_REMAIN_TIME:
  490. errorMessage = Strings.remainTimeEnded.tr;
  491. break;
  492. // 桌面版本错误
  493. case Errors.ERROR_RPC_CALL_FAILED:
  494. errorMessage = Strings.vpnRPCCallFailed.tr;
  495. break;
  496. case Errors.ERROR_RPC_RETURN_FALSE:
  497. errorMessage = Strings.vpnRPCReturnFalse.tr;
  498. break;
  499. }
  500. if (code == Errors.ERROR_REMAIN_TIME) {
  501. AllDialog.showMembershipExpired();
  502. return;
  503. }
  504. if (errorMessage.isNotEmpty) {
  505. ErrorDialog.show(message: errorMessage);
  506. }
  507. }
  508. void _uninitState() {
  509. if (state != ConnectionState.disconnected) {
  510. state = ConnectionState.disconnected;
  511. timer = "00:00:00";
  512. HapticFeedbackManager.connectionDisconnected();
  513. }
  514. }
  515. // 格式化时间显示
  516. String _formatTime(int timeMs) {
  517. final totalSeconds = (timeMs / 1000).abs().round();
  518. final hours = totalSeconds ~/ 3600;
  519. final minutes = (totalSeconds % 3600) ~/ 60;
  520. final seconds = totalSeconds % 60;
  521. return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
  522. }
  523. void handleSnackBarError(dynamic error, StackTrace stackTrace) {
  524. if (error is ApiException) {
  525. IXSnackBar.showIXErrorSnackBar(
  526. title: Strings.error.tr,
  527. message: error.message,
  528. );
  529. } else if (error is Failure) {
  530. IXSnackBar.showIXErrorSnackBar(
  531. title: Strings.error.tr,
  532. message: error.message ?? Strings.unknownError.tr,
  533. );
  534. } else if (error is DioException) {
  535. switch (error.type) {
  536. case DioExceptionType.connectionError:
  537. case DioExceptionType.connectionTimeout:
  538. case DioExceptionType.receiveTimeout:
  539. case DioExceptionType.sendTimeout:
  540. IXSnackBar.showIXErrorSnackBar(
  541. title: Strings.error.tr,
  542. message: Strings.unableToConnectNetwork.tr,
  543. );
  544. break;
  545. default:
  546. IXSnackBar.showIXErrorSnackBar(
  547. title: Strings.error.tr,
  548. message: Strings.unableToConnectServer.tr,
  549. );
  550. }
  551. } else {
  552. IXSnackBar.showIXErrorSnackBar(
  553. title: Strings.error.tr,
  554. message: error.toString(),
  555. );
  556. }
  557. }
  558. void handleErrorDialog(dynamic error, StackTrace stackTrace) {
  559. if (error is ApiException) {
  560. ErrorDialog.show(title: Strings.error.tr, message: error.message);
  561. } else if (error is Failure) {
  562. ErrorDialog.show(
  563. title: Strings.error.tr,
  564. message: error.message ?? Strings.unknownError.tr,
  565. );
  566. } else if (error is DioException) {
  567. switch (error.type) {
  568. case DioExceptionType.connectionError:
  569. case DioExceptionType.connectionTimeout:
  570. case DioExceptionType.receiveTimeout:
  571. case DioExceptionType.sendTimeout:
  572. ErrorDialog.show(
  573. title: Strings.error.tr,
  574. message: Strings.unableToConnectNetwork.tr,
  575. );
  576. break;
  577. default:
  578. ErrorDialog.show(
  579. title: Strings.error.tr,
  580. message: Strings.unableToConnectServer.tr,
  581. );
  582. }
  583. } else {
  584. ErrorDialog.show(title: Strings.error.tr, message: error.toString());
  585. }
  586. }
  587. // 创建一条加速日志
  588. Future<void> createBoostLog() async {
  589. await initLog();
  590. await setSessionInfoLog();
  591. await setTargetInfoLog();
  592. }
  593. // 初始化日志
  594. Future<void> initLog() async {
  595. await BoostReportManager().init();
  596. }
  597. // 读取历史日志
  598. Future<void> readHistoryLog() async {
  599. await BoostReportManager().readHistoryLog();
  600. }
  601. // 初始化会话日志
  602. Future<void> setSessionInfoLog() async {
  603. final deviceInfoPlugin = DeviceInfoPlugin();
  604. final appVersion = await PackageInfo.fromPlatform().then(
  605. (value) => value.version,
  606. );
  607. final networkType = await NetworkHelper.instance.getNetworkType();
  608. Map<String, String> deviceInfo = {};
  609. if (Platform.isIOS) {
  610. final iosOsInfo = await deviceInfoPlugin.iosInfo;
  611. deviceInfo = {
  612. 'deviceModel': iosOsInfo.model,
  613. 'osVersion': iosOsInfo.systemVersion,
  614. 'appVersion': appVersion,
  615. 'networkType': networkType,
  616. 'deviceBrand': iosOsInfo.utsname.machine,
  617. };
  618. } else if (Platform.isAndroid) {
  619. final androidOsInfo = await deviceInfoPlugin.androidInfo;
  620. deviceInfo = {
  621. 'deviceModel': androidOsInfo.model,
  622. 'osVersion': androidOsInfo.version.release,
  623. 'appVersion': appVersion,
  624. 'networkType': networkType,
  625. 'deviceBrand': androidOsInfo.brand,
  626. };
  627. }
  628. final boostSessionId = Uuid().v4();
  629. await BoostReportManager().initSessionInfo(
  630. appSessionId: _globalUuid,
  631. boostSessionId: boostSessionId,
  632. deviceInfo: deviceInfo,
  633. );
  634. }
  635. // 初始化目标信息
  636. Future<void> setTargetInfoLog() async {
  637. await BoostReportManager().addTargetInfo(
  638. locationSelectionType: locationSelectionType,
  639. location: IXSP.getSelectedLocation(),
  640. );
  641. }
  642. }