|
|
|
@ -14,10 +14,12 @@ import '../../../data/services/network/api.dart'; |
|
|
|
import '../../../data/services/version_update_service.dart'; |
|
|
|
import '../../../modules/common/widgets/version_update_dialog.dart'; |
|
|
|
import '../../../modules/common/widgets/privacy_policy_dialog.dart'; |
|
|
|
import '../../common/webview_page.dart'; |
|
|
|
import '../../../core/utils/logger.dart'; |
|
|
|
|
|
|
|
class SplashController extends GetxController { |
|
|
|
final GetStorage _storage = GetStorage(); |
|
|
|
static const String _tag = 'SplashCtrl'; |
|
|
|
|
|
|
|
// 进度条动画控制 |
|
|
|
final _loadingProgress = 0.0.obs; |
|
|
|
double get loadingProgress => _loadingProgress.value; |
|
|
|
@ -34,6 +36,13 @@ class SplashController extends GetxController { |
|
|
|
// 主题服务 |
|
|
|
final ThemeService _themeService = ThemeService(); |
|
|
|
|
|
|
|
// 会话级别的版本检查标记(静态变量,整个应用会话期间保持) |
|
|
|
static bool _hasCheckedVersionInSession = false; |
|
|
|
|
|
|
|
// 版本检查相关常量 |
|
|
|
static const String _lastVersionCheckKey = 'last_version_check_timestamp'; |
|
|
|
static const int _versionCheckIntervalHours = 24; // 24小时间隔 |
|
|
|
|
|
|
|
@override |
|
|
|
void onInit() { |
|
|
|
super.onInit(); |
|
|
|
@ -50,10 +59,19 @@ class SplashController extends GetxController { |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
//弹出用户追中问题 |
|
|
|
WidgetsFlutterBinding.ensureInitialized().addPostFrameCallback((_) async { |
|
|
|
final status = |
|
|
|
await AppTrackingTransparency.requestTrackingAuthorization(); |
|
|
|
// 异步处理用户追踪授权,不阻塞主流程 |
|
|
|
_requestTrackingPermissionAsync(); |
|
|
|
} |
|
|
|
|
|
|
|
/// 异步请求追踪权限,不阻塞启动流程 |
|
|
|
void _requestTrackingPermissionAsync() { |
|
|
|
Future.delayed(const Duration(milliseconds: 500), () async { |
|
|
|
try { |
|
|
|
await AppTrackingTransparency.requestTrackingAuthorization(); |
|
|
|
Logger.d(_tag, '用户追踪权限请求完成'); |
|
|
|
} catch (e) { |
|
|
|
Logger.e(_tag, '用户追踪权限请求失败: $e'); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -62,10 +80,23 @@ class SplashController extends GetxController { |
|
|
|
_loadAppResources(); |
|
|
|
} |
|
|
|
|
|
|
|
/// 智能调度版本检查,在页面跳转后执行,完全不影响启动流程 |
|
|
|
void _scheduleVersionCheck() { |
|
|
|
// 在独立的微任务中执行,避免阻塞主线程 |
|
|
|
scheduleMicrotask(() async { |
|
|
|
try { |
|
|
|
Logger.d(_tag, '开始执行版本检查(后台任务)'); |
|
|
|
_checkVersionUpdateIfNeeded(); |
|
|
|
} catch (e) { |
|
|
|
Logger.e(_tag, '版本检查调度失败: $e'); |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
void _onPrivacyAccepted() { |
|
|
|
_storage.write('hasAcceptedPrivacy', true); |
|
|
|
Get.back(); // 关闭弹窗 |
|
|
|
_startNormalFlow(); // 开始正常流程 |
|
|
|
_startNormalFlow(); // 开始正常流程(已包含版本检查) |
|
|
|
} |
|
|
|
|
|
|
|
void _onPrivacyRejected() { |
|
|
|
@ -84,18 +115,6 @@ class SplashController extends GetxController { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
// 初始化地图SDK |
|
|
|
// void _initMapSDK() { |
|
|
|
// try { |
|
|
|
// AmapFlutter().initSdk( |
|
|
|
// iosKey: "a4a1394fe817c2f86a424b897b4a9af4", |
|
|
|
// androidKey: "78e7946dd602778df82c6ae143a88184", |
|
|
|
// ); |
|
|
|
// } catch (e) { |
|
|
|
// print('地图SDK初始化失败: $e'); |
|
|
|
// } |
|
|
|
// } |
|
|
|
|
|
|
|
// 进度条动画(持续2秒) |
|
|
|
void _startLoadingAnimation() { |
|
|
|
const totalDuration = 1500; // 动画总时长增加到1.5秒 |
|
|
|
@ -122,22 +141,23 @@ class SplashController extends GetxController { |
|
|
|
// await _loadImages(); |
|
|
|
// await _initDatabase(); |
|
|
|
|
|
|
|
// 检查版本更新(在后台进行,不阻塞启动流程) |
|
|
|
//_checkVersionUpdate(); |
|
|
|
|
|
|
|
_isResourceLoaded.value = true; |
|
|
|
_checkNavigateCondition(); |
|
|
|
} catch (e) { |
|
|
|
Get.snackbar('错误', '资源加载失败,请检查网络连接'); |
|
|
|
_isResourceLoaded.value = true; // 允许用户继续使用 |
|
|
|
print('资源加载错误: $e'); |
|
|
|
Logger.e(_tag, '资源加载错误: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 检查跳转条件 |
|
|
|
void _checkNavigateCondition() { |
|
|
|
void _checkNavigateCondition() async { |
|
|
|
if (_loadingProgress.value >= 1.0 && _isResourceLoaded.value) { |
|
|
|
_navigateToLogin(); |
|
|
|
// 关键改动:先执行页面跳转,并用 await 等待它完成 |
|
|
|
await _navigateToLogin(); |
|
|
|
|
|
|
|
// 页面跳转完全结束后,再安心地安排版本检查 |
|
|
|
_scheduleVersionCheck(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -145,7 +165,7 @@ class SplashController extends GetxController { |
|
|
|
Future<void> _navigateToLogin() async { |
|
|
|
bool isLoggedIn = false; |
|
|
|
final token = _storage.read('logintoken'); |
|
|
|
print('getLoginToken:进来了${token}'); |
|
|
|
Logger.d(_tag, 'getLoginToken:进来了${token}'); |
|
|
|
if (token != null && token.isNotEmpty) { |
|
|
|
isLoggedIn = await getLoginToken(); |
|
|
|
} |
|
|
|
@ -159,14 +179,14 @@ class SplashController extends GetxController { |
|
|
|
|
|
|
|
Future<bool> getLoginToken() async { |
|
|
|
try { |
|
|
|
print('getLoginToken:进来了'); |
|
|
|
Logger.d(_tag, 'getLoginToken:进来了'); |
|
|
|
//if (User.getname() != "") { |
|
|
|
final response = await Api.tokenlogin(); |
|
|
|
print('getLoginToken: $response'); |
|
|
|
Logger.d(_tag, 'getLoginToken: $response'); |
|
|
|
if (response == null) return false; |
|
|
|
|
|
|
|
if (response['user'] != '') { |
|
|
|
print('getLoginToken:进来了'); |
|
|
|
Logger.d(_tag, 'getLoginToken:进来了'); |
|
|
|
// 根据API设计调整 |
|
|
|
final user = User.fromJson(response); |
|
|
|
|
|
|
|
@ -178,21 +198,21 @@ class SplashController extends GetxController { |
|
|
|
//} |
|
|
|
return false; |
|
|
|
} catch (e) { |
|
|
|
print('Token获取失败: $e'); |
|
|
|
Logger.e(_tag, 'Token获取失败: $e'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Future<bool> getAppConfig() async { |
|
|
|
try { |
|
|
|
print('getAppConfig:进来了'); |
|
|
|
Logger.d(_tag, 'getAppConfig:进来了'); |
|
|
|
//if (User.getname() != "") { |
|
|
|
final response = await Api.getappconfig(); |
|
|
|
print('getAppConfig: $response'); |
|
|
|
Logger.d(_tag, 'getAppConfig: $response'); |
|
|
|
if (response == null) return false; |
|
|
|
// 根据API设计调整 |
|
|
|
final resp = UserGetAppConfigResp.fromJson(response); |
|
|
|
print('getAppConfig:进来了'); |
|
|
|
Logger.d(_tag, 'getAppConfig:进来了'); |
|
|
|
// 存储用户信息(示例) |
|
|
|
// _storage.write('ENV', resp.env); |
|
|
|
// _storage.write('AGENTS', resp.agents); |
|
|
|
@ -200,27 +220,116 @@ class SplashController extends GetxController { |
|
|
|
AppConfig.initialize(resp); |
|
|
|
return true; |
|
|
|
} catch (e) { |
|
|
|
print('getAppConfig 取失败: $e'); |
|
|
|
Logger.e(_tag, 'getAppConfig 取失败: $e'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 检查版本更新(后台执行,不阻塞启动流程) |
|
|
|
// void _checkVersionUpdate() { |
|
|
|
// // 延迟执行版本检查,避免影响启动速度 |
|
|
|
// Timer(const Duration(seconds: 1), () async { |
|
|
|
// try { |
|
|
|
// final versionService = VersionUpdateService.to; |
|
|
|
// final updateInfo = await versionService.checkForUpdate(); |
|
|
|
|
|
|
|
// if (updateInfo.hasUpdate) { |
|
|
|
// // 显示更新对话框 |
|
|
|
// await VersionUpdateDialog.show(updateInfo); |
|
|
|
// } |
|
|
|
// } catch (e) { |
|
|
|
// print('版本检查失败: $e'); |
|
|
|
// // 版本检查失败不影响用户使用,静默处理 |
|
|
|
// } |
|
|
|
// }); |
|
|
|
// } |
|
|
|
/// 混合检查机制:判断是否需要进行版本检查 |
|
|
|
/// 检查条件:1. 会话内未检查过 OR 2. 距离上次检查超过24小时 |
|
|
|
void _checkVersionUpdateIfNeeded() { |
|
|
|
try { |
|
|
|
final now = DateTime.now(); |
|
|
|
final lastCheckTimestamp = _storage.read(_lastVersionCheckKey); |
|
|
|
|
|
|
|
bool shouldCheck = false; |
|
|
|
String reason = ''; |
|
|
|
|
|
|
|
// 条件1:会话内未检查过 |
|
|
|
if (!_hasCheckedVersionInSession) { |
|
|
|
shouldCheck = true; |
|
|
|
reason = '会话内首次检查'; |
|
|
|
} |
|
|
|
// 条件2:距离上次检查超过24小时 |
|
|
|
else if (lastCheckTimestamp != null) { |
|
|
|
final lastCheckTime = |
|
|
|
DateTime.fromMillisecondsSinceEpoch(lastCheckTimestamp); |
|
|
|
final timeDifference = now.difference(lastCheckTime); |
|
|
|
|
|
|
|
if (timeDifference.inHours >= _versionCheckIntervalHours) { |
|
|
|
shouldCheck = true; |
|
|
|
reason = '距离上次检查已超过${_versionCheckIntervalHours}小时'; |
|
|
|
} |
|
|
|
} |
|
|
|
// 条件3:从未检查过(首次使用应用) |
|
|
|
else { |
|
|
|
shouldCheck = true; |
|
|
|
reason = '首次使用应用'; |
|
|
|
} |
|
|
|
|
|
|
|
if (shouldCheck) { |
|
|
|
Logger.i(_tag, '开始版本检查 - 原因: $reason'); |
|
|
|
_performVersionCheck(); |
|
|
|
} else { |
|
|
|
Logger.i(_tag, '跳过版本检查 - 会话内已检查且未超过时间间隔'); |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
Logger.e(_tag, '版本检查判断失败: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 执行版本检查(在后台进行,不阻塞启动流程) |
|
|
|
Future<void> _performVersionCheck() async { |
|
|
|
try { |
|
|
|
final versionService = VersionUpdateService.to; |
|
|
|
// 异步执行,不等待结果 |
|
|
|
versionService.checkForUpdate().then((updateInfo) { |
|
|
|
if (updateInfo.hasUpdate) { |
|
|
|
Logger.i(_tag, '发现新版本: ${updateInfo.latestVersion}'); |
|
|
|
// 在主线程中显示更新对话框 |
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) { |
|
|
|
VersionUpdateDialog.show(updateInfo); |
|
|
|
}); |
|
|
|
} else { |
|
|
|
Logger.i(_tag, '当前已是最新版本: ${updateInfo.currentVersion}'); |
|
|
|
} |
|
|
|
|
|
|
|
// 更新检查记录 |
|
|
|
_updateVersionCheckRecord(); |
|
|
|
}).catchError((e) { |
|
|
|
Logger.e(_tag, '版本检查失败: $e'); |
|
|
|
// 即使检查失败,也更新记录,避免频繁重试 |
|
|
|
_updateVersionCheckRecord(); |
|
|
|
}); |
|
|
|
} catch (e) { |
|
|
|
Logger.e(_tag, '版本检查失败: $e'); |
|
|
|
// 即使检查失败,也更新记录,避免频繁重试 |
|
|
|
_updateVersionCheckRecord(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 更新版本检查记录 |
|
|
|
void _updateVersionCheckRecord() { |
|
|
|
try { |
|
|
|
// 更新时间戳 |
|
|
|
final now = DateTime.now(); |
|
|
|
_storage.write(_lastVersionCheckKey, now.millisecondsSinceEpoch); |
|
|
|
|
|
|
|
// 标记本次会话已检查过版本 |
|
|
|
_hasCheckedVersionInSession = true; |
|
|
|
|
|
|
|
Logger.i(_tag, '版本检查记录已更新: ${now.toIso8601String()}'); |
|
|
|
} catch (e) { |
|
|
|
Logger.e(_tag, '更新版本检查记录失败: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 重置版本检查标记(可用于强制重新检查) |
|
|
|
/// 注意:这会清除会话标记,但不会清除时间戳记录 |
|
|
|
static void resetVersionCheckFlag() { |
|
|
|
_hasCheckedVersionInSession = false; |
|
|
|
Logger.i('SplashCtrl', '版本检查会话标记已重置'); |
|
|
|
} |
|
|
|
|
|
|
|
/// 完全重置版本检查状态(包括时间戳) |
|
|
|
/// 用于测试或特殊情况下强制重新检查 |
|
|
|
void forceResetVersionCheck() { |
|
|
|
try { |
|
|
|
_hasCheckedVersionInSession = false; |
|
|
|
_storage.remove(_lastVersionCheckKey); |
|
|
|
Logger.i(_tag, '版本检查状态已完全重置'); |
|
|
|
} catch (e) { |
|
|
|
Logger.e(_tag, '重置版本检查状态失败: $e'); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|