api_controller.dart 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'package:device_info_plus/device_info_plus.dart';
  4. import 'package:dio/dio.dart';
  5. import 'package:get/get.dart';
  6. import 'package:nomo/app/api/router/api_router.dart';
  7. import 'package:nomo/app/data/sp/ix_sp.dart';
  8. import 'package:package_info_plus/package_info_plus.dart';
  9. import 'package:play_install_referrer/play_install_referrer.dart';
  10. import '../../config/translations/localization_service.dart';
  11. import '../../config/translations/strings_enum.dart';
  12. import '../../pigeons/core_api.g.dart';
  13. import '../../utils/device_manager.dart';
  14. import '../../utils/geo_downloader.dart';
  15. import '../../utils/log/logger.dart';
  16. import '../../utils/network_helper.dart';
  17. import '../api/core/api_core.dart';
  18. import '../components/country_restricted_overlay.dart';
  19. import '../components/ix_snackbar.dart';
  20. import '../constants/api_domains.dart';
  21. import '../constants/configs.dart';
  22. import '../constants/enums.dart';
  23. import '../constants/errors.dart';
  24. import '../constants/platforms.dart';
  25. import '../data/models/api_exception.dart';
  26. import '../data/models/channelplan/channel_plan_list.dart';
  27. import '../data/models/failure.dart';
  28. import '../data/models/fingerprint.dart';
  29. import '../data/models/launch/groups.dart';
  30. import '../data/models/launch/launch.dart';
  31. import '../dialog/all_dialog.dart';
  32. class ApiController extends GetxService {
  33. final TAG = 'ApiController';
  34. // 记录是否已经显示禁用弹窗
  35. bool isShowDisabled = false;
  36. //是否是游客
  37. final _isGuest = false.obs;
  38. bool get isGuest => _isGuest.value;
  39. set isGuest(bool value) => _isGuest.value = value;
  40. //全部节点列表
  41. final _nodesList = <LocationList>[].obs;
  42. List<LocationList> get nodesList => _nodesList.value;
  43. set nodesList(List<LocationList> value) => _nodesList.value = value;
  44. //初始化fingerprint
  45. Fingerprint fp = Fingerprint.empty();
  46. Future<Fingerprint> initFingerprint() async {
  47. // 读取app发布渠道
  48. if (Platform.isIOS) {
  49. fp.channel = 'apple';
  50. } else if (Platform.isAndroid) {
  51. try {
  52. final channel = await CoreApi().getChannel();
  53. fp.channel = channel ?? 'unknown';
  54. } catch (e) {
  55. log(TAG, 'read app channel error: $e');
  56. fp.channel = '';
  57. }
  58. try {
  59. final advertisingId = await CoreApi().getAdvertisingId();
  60. fp.googleId = advertisingId ?? '';
  61. } catch (e) {
  62. log(TAG, 'read app googleId error: $e');
  63. fp.googleId = '';
  64. }
  65. try {
  66. ReferrerDetails referrerDetails =
  67. await PlayInstallReferrer.installReferrer;
  68. fp.refer = referrerDetails.installReferrer ?? '';
  69. } catch (e) {
  70. log(TAG, 'get install referrer error: $e');
  71. fp.refer = '';
  72. }
  73. }
  74. // 读取应用信息
  75. final info = await PackageInfo.fromPlatform();
  76. fp.appVersionCode = int.tryParse(info.buildNumber) ?? 0;
  77. fp.appVersionName = info.version;
  78. // 读取设备信息
  79. final deviceInfo = DeviceInfoPlugin();
  80. if (Platform.isIOS) {
  81. fp.platform = Platforms.iOS;
  82. final iosOsInfo = await deviceInfo.iosInfo;
  83. fp.deviceModel = iosOsInfo.model;
  84. fp.deviceOs = iosOsInfo.systemVersion;
  85. fp.deviceBrand = iosOsInfo.utsname.machine;
  86. } else if (Platform.isAndroid) {
  87. fp.platform = Platforms.android;
  88. final androidOsInfo = await deviceInfo.androidInfo;
  89. fp.deviceModel = androidOsInfo.model;
  90. fp.deviceOs = androidOsInfo.version.release;
  91. fp.deviceBrand = androidOsInfo.brand;
  92. fp.androidId = androidOsInfo.id;
  93. }
  94. //获取设备尺寸
  95. fp.deviceHeight = Get.height.toInt();
  96. fp.deviceWidth = Get.width.toInt();
  97. // 读取设备ID
  98. fp.deviceId = DeviceManager.getCacheDeviceId();
  99. fp.isNewInstall = IXSP.getIsNewInstall();
  100. await updateFingerprintData();
  101. return fp;
  102. }
  103. // 更新部分数据
  104. Future<void> updateFingerprintData() async {
  105. fp.lang = IXSP.getCurrentLocal().languageCode;
  106. fp.phoneCountryIso = LocalizationService.getSystemCountry();
  107. fp.isVpn = await CoreApi().isConnected() ?? false;
  108. if (!fp.isVpn) {
  109. fp.isConnectedVpn = false;
  110. }
  111. try {
  112. final simInfo = await CoreApi().getSimInfo();
  113. // 解析sim
  114. final sim = jsonDecode(simInfo ?? '{}');
  115. fp.simReady = sim['simReady'];
  116. fp.carrierName = sim['carrierName'];
  117. fp.mcc = sim['mcc'];
  118. fp.mnc = sim['mnc'];
  119. fp.countryIso = sim['countryIso'];
  120. fp.networkCarrierName = sim['networkCarrierName'];
  121. fp.networkMcc = sim['networkMcc'];
  122. fp.networkMnc = sim['networkMnc'];
  123. fp.networkCountryIso = sim['networkCountryIso'];
  124. } catch (e) {
  125. log(TAG, 'read app sim error: $e');
  126. }
  127. }
  128. Future<void> initData(Launch? launch) async {
  129. // 初始化是否第一次安装
  130. IXSP.setIsNewInstall(false);
  131. fp.userUuid = '';
  132. fp.isNewInstall = false;
  133. await initLaunch(launch);
  134. }
  135. Future<void> initLaunch(Launch? launch) async {
  136. try {
  137. if (launch != null) {
  138. // 初始化用户状态
  139. isGuest = launch.userConfig?.memberLevel == MemberLevel.guest.level;
  140. // 设置路由和节点
  141. nodesList = launch.groups?.normal?.list ?? [];
  142. // 设置资源url
  143. if (launch.appConfig?.assetUrls != null &&
  144. launch.appConfig!.assetUrls!.isNotEmpty) {
  145. Configs.assetUrl = launch.appConfig!.assetUrls![0];
  146. }
  147. // 设置官网url
  148. if (launch.appConfig?.websiteUrl != null &&
  149. launch.appConfig!.websiteUrl!.isNotEmpty) {
  150. Configs.websiteUrl = launch.appConfig!.websiteUrl!;
  151. }
  152. }
  153. } catch (e) {
  154. log(TAG, 'initLaunch error: $e');
  155. }
  156. }
  157. // 发送分析事件, 后续可以发送到firebase
  158. Future<void> sendAnalytics(FirebaseEvent event) async {
  159. try {} catch (e) {
  160. log('sendAnalytics error: $e');
  161. }
  162. }
  163. Future<Launch> launch({bool isCache = false}) async {
  164. sendAnalytics(isCache ? FirebaseEvent.launchCache : FirebaseEvent.launch);
  165. while (true) {
  166. try {
  167. ApiCore().setbaseUrl(ApiDomains.instance.getApiUrl());
  168. final request = fp.toJson();
  169. if (IXSP.getDisconnectDomains().isNotEmpty) {
  170. final disconnectDomainList = IXSP
  171. .getDisconnectDomains()
  172. .map((e) => e.toJson())
  173. .toList();
  174. request['disconnectDomainList'] = disconnectDomainList;
  175. }
  176. final result = await ApiCore().launch(request);
  177. if (!result.success) {
  178. throw Failure(
  179. code: result.errorCode ?? '',
  180. message: result.errorMessage ?? '',
  181. );
  182. }
  183. sendAnalytics(
  184. isCache
  185. ? FirebaseEvent.launchCacheSuccess
  186. : FirebaseEvent.launchSuccess,
  187. );
  188. if (IXSP.getDisconnectDomains().isNotEmpty) {
  189. IXSP.clearDisconnectDomains();
  190. }
  191. // 重置禁用状态
  192. IXSP.setLastIsRegionDisabled(false);
  193. IXSP.setLastIsUserDisabled(false);
  194. final launchData = Launch.fromJson(result.data);
  195. // 设置扩展数据
  196. fp.exData = launchData.exData;
  197. // 更新URL列表
  198. await ApiDomains.instance.updateFromLaunch(launchData);
  199. // 保存Launch数据
  200. await IXSP.saveLaunch(launchData);
  201. // 初始化Launch
  202. await initData(launchData);
  203. return launchData;
  204. } on ApiException catch (e) {
  205. final url = await ApiDomains.instance.getNextApiUrl();
  206. log(TAG, 'Launch request failed for URL $url: $e');
  207. if (url.isEmpty) {
  208. rethrow;
  209. }
  210. ApiCore().setbaseUrl(url);
  211. } on Failure catch (_) {
  212. rethrow;
  213. } on DioException catch (e) {
  214. if (e.response?.statusCode == Errors.eRegionNotAvailable ||
  215. e.response?.statusCode == Errors.eUserDisabled ||
  216. e.response?.statusCode == Errors.eTokenExpired) {
  217. rethrow;
  218. } else {
  219. if (await NetworkHelper.instance.isNetworkAvailable()) {
  220. final url = await ApiDomains.instance.getNextApiUrl();
  221. log(TAG, 'Launch request failed for URL $url: $e');
  222. if (url.isEmpty) {
  223. rethrow;
  224. }
  225. ApiCore().setbaseUrl(url);
  226. } else {
  227. rethrow;
  228. }
  229. }
  230. } catch (e) {
  231. final url = await ApiDomains.instance.getNextApiUrl();
  232. log(TAG, 'Launch request failed for URL $url: $e');
  233. if (url.isEmpty) {
  234. rethrow;
  235. }
  236. ApiCore().setbaseUrl(url);
  237. }
  238. }
  239. }
  240. Future<void> asyncHandleLaunch() async {
  241. try {
  242. final data = await launch(isCache: true);
  243. final isVpnRunning = await CoreApi().isConnected() ?? false;
  244. if (!isVpnRunning) {
  245. await checkUpdate();
  246. // 下载smartgeo文件
  247. GeoDownloader().downloadSmartGeo(smartGeo: data.appConfig!.smartGeo!);
  248. }
  249. } catch (e, s) {
  250. if (IXSP.getLastIsUserDisabled()) {
  251. if (!isShowDisabled) {
  252. Get.offAll(
  253. () => CountryRestrictedOverlay(
  254. type: RestrictedType.user,
  255. onPressed: () async {
  256. // 清除LaunchData
  257. await IXSP.clearLaunchData();
  258. // 清除禁用状态
  259. IXSP.setLastIsUserDisabled(false);
  260. // 发送事件
  261. },
  262. ),
  263. transition: Transition.fadeIn,
  264. );
  265. }
  266. return;
  267. } else if (IXSP.getLastIsRegionDisabled()) {
  268. if (!isShowDisabled) {
  269. Get.offAll(
  270. () => const CountryRestrictedOverlay(type: RestrictedType.region),
  271. transition: Transition.fadeIn,
  272. );
  273. }
  274. return;
  275. } else if (IXSP.getLastIsDeviceDisabled()) {
  276. if (!isShowDisabled) {
  277. Get.offAll(
  278. () => const CountryRestrictedOverlay(type: RestrictedType.device),
  279. transition: Transition.fadeIn,
  280. );
  281. }
  282. return;
  283. }
  284. final isVpnRunning = await CoreApi().isConnected() ?? false;
  285. if (!isVpnRunning) {
  286. await checkUpdate();
  287. }
  288. handleSnackBarError(e, s);
  289. }
  290. }
  291. void handleSnackBarError(dynamic error, StackTrace stackTrace) {
  292. if (error is ApiException) {
  293. IXSnackBar.showIXErrorSnackBar(
  294. title: Strings.error.tr,
  295. message: error.message,
  296. );
  297. } else if (error is Failure) {
  298. IXSnackBar.showIXErrorSnackBar(
  299. title: Strings.error.tr,
  300. message: error.message ?? Strings.unknownError.tr,
  301. );
  302. } else if (error is DioException) {
  303. switch (error.type) {
  304. case DioExceptionType.connectionError:
  305. case DioExceptionType.connectionTimeout:
  306. case DioExceptionType.receiveTimeout:
  307. case DioExceptionType.sendTimeout:
  308. IXSnackBar.showIXErrorSnackBar(
  309. title: Strings.error.tr,
  310. message: Strings.unableToConnectNetwork.tr,
  311. );
  312. break;
  313. default:
  314. IXSnackBar.showIXErrorSnackBar(
  315. title: Strings.error.tr,
  316. message: Strings.unableToConnectServer.tr,
  317. );
  318. }
  319. } else {
  320. IXSnackBar.showIXErrorSnackBar(
  321. title: Strings.error.tr,
  322. message: error.toString(),
  323. );
  324. }
  325. }
  326. // 更新检查 - 智能时间控制版本
  327. Future<bool> checkUpdate({bool isClickCheck = false}) async {
  328. try {
  329. final upgrade = IXSP.getUpgrade();
  330. var hasUpdate = false;
  331. var hasForceUpdate = false;
  332. if (upgrade != null) {
  333. if (upgrade.upgradeType == 1) {
  334. hasUpdate = true;
  335. }
  336. if (upgrade.forced == true) {
  337. hasForceUpdate = true;
  338. }
  339. }
  340. if (hasUpdate) {
  341. AllDialog.showUpdate(hasForceUpdate: hasForceUpdate);
  342. }
  343. return hasUpdate;
  344. } catch (e) {
  345. log(TAG, 'checkUpdate error: $e');
  346. }
  347. return false;
  348. }
  349. Future<Launch> getDispatchInfo(
  350. int locationId,
  351. String locationCode, {
  352. CancelToken? cancelToken,
  353. }) async {
  354. while (true) {
  355. try {
  356. ApiRouter().setbaseUrl(ApiDomains.instance.getRouterUrl());
  357. final request = fp.toJson();
  358. if (IXSP.getDisconnectDomains().isNotEmpty) {
  359. final disconnectDomainList = IXSP
  360. .getDisconnectDomains()
  361. .map((e) => e.toJson())
  362. .toList();
  363. request['disconnectDomainList'] = disconnectDomainList;
  364. }
  365. request['locationId'] = locationId;
  366. request['locationCode'] = locationCode;
  367. final result = await ApiRouter().getDispatchInfo(
  368. request,
  369. cancelToken: cancelToken,
  370. );
  371. if (!result.success) {
  372. throw Failure(
  373. code: result.errorCode ?? '',
  374. message: result.errorMessage ?? '',
  375. );
  376. }
  377. if (IXSP.getDisconnectDomains().isNotEmpty) {
  378. IXSP.clearDisconnectDomains();
  379. }
  380. // 重置禁用状态
  381. IXSP.setLastIsRegionDisabled(false);
  382. IXSP.setLastIsUserDisabled(false);
  383. final launchData = Launch.fromJson(result.data);
  384. // 更新URL列表
  385. await ApiDomains.instance.updateFromLaunch(launchData);
  386. // 保存app配置
  387. await IXSP.saveAppConfig(launchData.appConfig!);
  388. return launchData;
  389. } on ApiException catch (_) {
  390. rethrow;
  391. } on Failure catch (_) {
  392. rethrow;
  393. } on DioException catch (e) {
  394. if (e.response?.statusCode == Errors.eRegionNotAvailable ||
  395. e.response?.statusCode == Errors.eUserDisabled ||
  396. e.response?.statusCode == Errors.eTokenExpired) {
  397. rethrow;
  398. } else {
  399. if (await NetworkHelper.instance.isNetworkAvailable()) {
  400. final url = await ApiDomains.instance.getNextRouterUrl();
  401. log(TAG, 'getDispatchInfo request failed for URL $url: $e');
  402. if (url.isEmpty) {
  403. rethrow;
  404. }
  405. ApiRouter().setbaseUrl(url);
  406. } else {
  407. rethrow;
  408. }
  409. }
  410. } catch (e) {
  411. final url = await ApiDomains.instance.getNextRouterUrl();
  412. log(TAG, 'getDispatchInfo request failed for URL $url: $e');
  413. if (url.isEmpty) {
  414. rethrow;
  415. }
  416. ApiRouter().setbaseUrl(url);
  417. }
  418. }
  419. }
  420. Future<Launch> register(Map<String, dynamic> params) async {
  421. while (true) {
  422. try {
  423. ApiCore().setbaseUrl(ApiDomains.instance.getApiUrl());
  424. final request = fp.toJson();
  425. request.addAll(params);
  426. final result = await ApiCore().register(request);
  427. if (!result.success) {
  428. throw Failure(
  429. code: result.errorCode ?? '',
  430. message: result.errorMessage ?? '',
  431. );
  432. }
  433. final launchData = Launch.fromJson(result.data);
  434. // 注册成功后上报firebase注册事件
  435. sendAnalytics(FirebaseEvent.register);
  436. // 保存 Launch 数据
  437. await IXSP.saveLaunch(launchData);
  438. // 初始化Launch
  439. await initData(launchData);
  440. return launchData;
  441. } on ApiException catch (_) {
  442. rethrow;
  443. } on Failure catch (_) {
  444. rethrow;
  445. } on DioException catch (e) {
  446. if (e.response?.statusCode == Errors.eRegionNotAvailable ||
  447. e.response?.statusCode == Errors.eUserDisabled ||
  448. e.response?.statusCode == Errors.eTokenExpired) {
  449. rethrow;
  450. } else {
  451. if (await NetworkHelper.instance.isNetworkAvailable()) {
  452. final url = await ApiDomains.instance.getNextApiUrl();
  453. log(TAG, 'Register request failed for URL $url: $e');
  454. if (url.isEmpty) {
  455. rethrow;
  456. }
  457. ApiCore().setbaseUrl(url);
  458. } else {
  459. rethrow;
  460. }
  461. }
  462. } catch (e) {
  463. final url = await ApiDomains.instance.getNextApiUrl();
  464. log(TAG, 'Register request failed for URL $url: $e');
  465. if (url.isEmpty) {
  466. rethrow;
  467. }
  468. ApiCore().setbaseUrl(url);
  469. }
  470. }
  471. }
  472. Future<Launch> login(Map<String, dynamic> params) async {
  473. while (true) {
  474. try {
  475. ApiCore().setbaseUrl(ApiDomains.instance.getApiUrl());
  476. final request = fp.toJson();
  477. request.addAll(params);
  478. final result = await ApiCore().login(request);
  479. if (!result.success) {
  480. throw Failure(
  481. code: result.errorCode ?? '',
  482. message: result.errorMessage ?? '',
  483. );
  484. }
  485. final launchData = Launch.fromJson(result.data);
  486. // 注册成功后上报firebase注册事件
  487. sendAnalytics(FirebaseEvent.login);
  488. // 保存 Launch 数据
  489. await IXSP.saveLaunch(launchData);
  490. // 初始化Launch
  491. await initData(launchData);
  492. return launchData;
  493. } on ApiException catch (_) {
  494. rethrow;
  495. } on Failure catch (_) {
  496. rethrow;
  497. } on DioException catch (e) {
  498. if (e.response?.statusCode == Errors.eRegionNotAvailable ||
  499. e.response?.statusCode == Errors.eUserDisabled ||
  500. e.response?.statusCode == Errors.eTokenExpired) {
  501. rethrow;
  502. } else {
  503. if (await NetworkHelper.instance.isNetworkAvailable()) {
  504. final url = await ApiDomains.instance.getNextApiUrl();
  505. log(TAG, 'Login request failed for URL $url: $e');
  506. if (url.isEmpty) {
  507. rethrow;
  508. }
  509. ApiCore().setbaseUrl(url);
  510. } else {
  511. rethrow;
  512. }
  513. }
  514. } catch (e) {
  515. final url = await ApiDomains.instance.getNextApiUrl();
  516. log(TAG, 'Login request failed for URL $url: $e');
  517. if (url.isEmpty) {
  518. rethrow;
  519. }
  520. ApiCore().setbaseUrl(url);
  521. }
  522. }
  523. }
  524. Future<Launch> logout() async {
  525. try {
  526. final request = fp.toJson();
  527. final result = await ApiCore().logout(request);
  528. if (!result.success) {
  529. throw Failure(
  530. code: result.errorCode ?? '',
  531. message: result.errorMessage ?? '',
  532. );
  533. }
  534. final launchData = Launch.fromJson(result.data);
  535. // 登出成功后上报firebase登出事件
  536. sendAnalytics(FirebaseEvent.logout);
  537. // 保存 Launch 数据
  538. await IXSP.saveLaunch(launchData);
  539. return launchData;
  540. } catch (e) {
  541. rethrow;
  542. }
  543. }
  544. Future<Launch> deleteAccount() async {
  545. try {
  546. final request = fp.toJson();
  547. final result = await ApiCore().deleteAccount(request);
  548. if (!result.success) {
  549. throw Failure(
  550. code: result.errorCode ?? '',
  551. message: result.errorMessage ?? '',
  552. );
  553. }
  554. final launchData = Launch.fromJson(result.data);
  555. // 登出成功后上报firebase登出事件
  556. sendAnalytics(FirebaseEvent.deleteAccount);
  557. // 保存 Launch 数据
  558. await IXSP.saveLaunch(launchData);
  559. return launchData;
  560. } catch (e) {
  561. rethrow;
  562. }
  563. }
  564. Future<String> changePassword(Map<String, dynamic> params) async {
  565. try {
  566. final request = fp.toJson();
  567. request.addAll(params);
  568. final result = await ApiCore().changePassword(request);
  569. if (!result.success) {
  570. throw Failure(
  571. code: result.errorCode ?? '',
  572. message: result.errorMessage ?? '',
  573. );
  574. }
  575. return result.errorMessage ?? '';
  576. } catch (e) {
  577. rethrow;
  578. }
  579. }
  580. Future<Groups> getLocations() async {
  581. while (true) {
  582. try {
  583. ApiCore().setbaseUrl(ApiDomains.instance.getApiUrl());
  584. final request = fp.toJson();
  585. final result = await ApiCore().getLocations(request);
  586. if (!result.success) {
  587. throw Failure(
  588. code: result.errorCode ?? '',
  589. message: result.errorMessage ?? '',
  590. );
  591. }
  592. final groups = Groups.fromJson(result.data);
  593. await IXSP.saveGroups(groups);
  594. return groups;
  595. } on ApiException catch (_) {
  596. rethrow;
  597. } on Failure catch (_) {
  598. rethrow;
  599. } on DioException catch (e) {
  600. if (e.response?.statusCode == Errors.eRegionNotAvailable ||
  601. e.response?.statusCode == Errors.eUserDisabled ||
  602. e.response?.statusCode == Errors.eTokenExpired) {
  603. rethrow;
  604. } else {
  605. if (await NetworkHelper.instance.isNetworkAvailable()) {
  606. final url = await ApiDomains.instance.getNextApiUrl();
  607. log(TAG, 'getLocations request failed for URL $url: $e');
  608. if (url.isEmpty) {
  609. rethrow;
  610. }
  611. ApiCore().setbaseUrl(url);
  612. } else {
  613. rethrow;
  614. }
  615. }
  616. } catch (e) {
  617. final url = await ApiDomains.instance.getNextApiUrl();
  618. log(TAG, 'getLocations request failed for URL $url: $e');
  619. if (url.isEmpty) {
  620. rethrow;
  621. }
  622. ApiCore().setbaseUrl(url);
  623. }
  624. }
  625. }
  626. Future<List<ChannelPlan>> getChannelPlanList() async {
  627. try {
  628. final request = fp.toJson();
  629. final result = await ApiCore().getChannelPlanList(request);
  630. if (!result.success) {
  631. throw Failure(
  632. code: result.errorCode ?? '',
  633. message: result.errorMessage ?? '',
  634. );
  635. }
  636. final channelPlanList = ChannelPlanList.fromJson(result.data);
  637. return channelPlanList.list ?? [];
  638. } catch (e) {
  639. rethrow;
  640. }
  641. }
  642. Future<Launch> subscribe(Map<String, dynamic> params) async {
  643. try {
  644. final request = fp.toJson();
  645. request.addAll(params);
  646. final result = await ApiCore().subscribe(request);
  647. if (!result.success) {
  648. throw Failure(
  649. code: result.errorCode ?? '',
  650. message: result.errorMessage ?? '',
  651. );
  652. }
  653. final launchData = Launch.fromJson(result.data);
  654. // 登出成功后上报firebase登出事件
  655. sendAnalytics(FirebaseEvent.subscribe);
  656. // 保存 Launch 数据
  657. await IXSP.saveLaunch(launchData);
  658. return launchData;
  659. } catch (e) {
  660. rethrow;
  661. }
  662. }
  663. Future<Launch> restore() async {
  664. try {
  665. final request = fp.toJson();
  666. final result = await ApiCore().restore(request);
  667. if (!result.success) {
  668. throw Failure(
  669. code: result.errorCode ?? '',
  670. message: result.errorMessage ?? '',
  671. );
  672. }
  673. final launchData = Launch.fromJson(result.data);
  674. // 登出成功后上报firebase登出事件
  675. sendAnalytics(FirebaseEvent.restore);
  676. // 保存 Launch 数据
  677. await IXSP.saveLaunch(launchData);
  678. return launchData;
  679. } catch (e) {
  680. rethrow;
  681. }
  682. }
  683. }