import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:logger/logger.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import '../models/channel_app_model.dart'; import 'network/api.dart'; import 'dart:math' as math; /// 版本更新服务类 class VersionUpdateService extends GetxService { static VersionUpdateService get to => Get.find(); // 静态应用信息(内存缓存) static String? _appVersion = ""; //应用版本号 static String? _buildNumber = ""; //构建号 static String? _platform = ""; //平台类型 static String? _deviceBrand = ""; //设备品牌 static UserChannel? _channel; //渠道 static String? _latestVersion = ""; //最新版本号+构建号 static bool? _hasUpdate = false; //是否有更新 static bool? _isForceUpdate = false; //是否强制更新 static String? _updateUrl = ""; //更新链接 static bool? _isShowTourists = false; //是否显示游客登录 static DateTime? _lastCheckTime; //上次检查时间 static const int _cacheIntervalMinutes = 10; // 可配置化 // 添加 getter 方法来访问缓存的静态数据 /// 获取缓存的应用版本 String get cachedAppVersion => _appVersion ?? ''; /// 获取缓存的构建号 String get cachedBuildNumber => _buildNumber ?? ''; /// 获取缓存的平台信息 String get cachedPlatform => _platform ?? ''; /// 获取缓存的设备品牌 String get cachedDeviceBrand => _deviceBrand ?? ''; /// 获取缓存的渠道信息 UserChannel get cachedChannel => _channel ?? UserChannel.UNKNOWN; /// 获取缓存的最新版本 String get cachedLatestVersion => _latestVersion ?? ''; /// 获取缓存的是否有更新 bool get cachedHasUpdate => _hasUpdate ?? false; /// 获取缓存的是否强制更新 bool get cachedIsForceUpdate => _isForceUpdate ?? false; /// 获取缓存的更新地址 String get cachedUpdateUrl => _updateUrl ?? ''; /// 获取缓存的游客登录状态 bool get cachedShowTourists => _isShowTourists ?? false; /// 获取上次检查时间 DateTime? get lastCheckTime => _lastCheckTime; final Logger _logger = Logger(); /// 获取当前应用版本信息 Future getCurrentVersion() async { try { final packageInfo = await PackageInfo.fromPlatform(); _appVersion = packageInfo.version; _buildNumber = packageInfo.buildNumber; return '${packageInfo.version}+${packageInfo.buildNumber}'; } catch (e) { _logger.e('获取当前版本信息失败: $e'); return '1.0.0'; } } /// 获取当前平台信息 Future getCurrentPlatformInfo() async { if (Platform.isIOS) { return const PlatformInfo( platform: 'ios', storeType: AppStoreType.appStore, channel: UserChannel.GLOBAL_APPLE, ); } if (Platform.isAndroid) { // 根据设备品牌判断应用商店类型 return await getAndroidStoreInfoByBrand(); } return const PlatformInfo( platform: 'unknown', storeType: AppStoreType.unknown, channel: UserChannel.UNKNOWN, ); } /// 根据设备品牌获取应用商店信息 Future getAndroidStoreInfoByBrand() async { try { final deviceInfo = DeviceInfoPlugin(); final androidInfo = await deviceInfo.androidInfo; final brand = androidInfo.brand.toLowerCase(); _deviceBrand = brand; String channelFromEnv = dotenv.env['Channel'] ?? 'OFFICIAL'; _channel = UserChannel.fromName(channelFromEnv); return PlatformInfo( platform: 'android', storeType: AppStoreType.official, channel: _channel ?? UserChannel.OFFICIAL, ); // switch (brand) { // case 'huawei': // case 'honor': // return PlatformInfo( // platform: 'android', // storeType: // brand == 'huawei' ? AppStoreType.huawei : AppStoreType.honor, // channel: brand == 'huawei' ? '华为应用市场' : '荣耀应用市场', // ); // case 'xiaomi': // case 'redmi': // return const PlatformInfo( // platform: 'android', // storeType: AppStoreType.xiaomi, // channel: '小米应用商店', // ); // case 'oppo': // case 'oneplus': // return const PlatformInfo( // platform: 'android', // storeType: AppStoreType.oppo, // channel: 'OPPO软件商店', // ); // case 'vivo': // case 'iqoo': // return const PlatformInfo( // platform: 'android', // storeType: AppStoreType.vivo, // channel: 'vivo应用商店', // ); // default: // return const PlatformInfo( // platform: 'android', // storeType: AppStoreType.googlePlay, // channel: 'Google Play', // ); // } } catch (e) { _logger.e('获取Android设备信息失败: $e'); return const PlatformInfo( platform: 'android', storeType: AppStoreType.googlePlay, channel: UserChannel.UNKNOWN, ); } } /// 检查版本更新 Future checkForUpdate() async { if (_lastCheckTime != null && DateTime.now().difference(_lastCheckTime!).inMinutes < _cacheIntervalMinutes) { return VersionUpdateInfo( hasUpdate: _hasUpdate ?? false, currentVersion: _appVersion ?? '1.0.0', latestVersion: (_latestVersion ?? '1.0.0').split('+')[0], updateType: _hasUpdate! ? (_isForceUpdate! ? UpdateType.force : UpdateType.optional) : UpdateType.none, ); } try { final currentVersion = await getCurrentVersion(); final platformInfo = await getCurrentPlatformInfo(); _platform = platformInfo.platform; _channel = platformInfo.channel; _lastCheckTime = DateTime.now(); // 调用后端接口获取最新版本信息 final response = await Api.getChannelApp({'channel': platformInfo.channel.value}); _logger.d('获取渠道包信息:$response'); if (response == null || !response.containsKey('app')) { return VersionUpdateInfo( hasUpdate: false, currentVersion: currentVersion, latestVersion: currentVersion, updateType: UpdateType.none, ); } //final channelAppResponse = ChannelAppResponse.fromJson(response); // 直接从response中获取app信息 final appInfo = AppInfo.fromJson(response['app']); _logger.d('获取到的最新版本信息: ${appInfo.toJson()}'); _latestVersion = appInfo.version; _updateUrl = appInfo.address; // 设置游客登录显示状态 _isShowTourists = appInfo.tourists; _logger.d('从服务器获取游客登录配置: ${appInfo.tourists}'); // if (channelAppResponse.code != 0 || channelAppResponse.data == null) { // _logger.w('获取版本信息失败: ${channelAppResponse.msg}'); // return VersionUpdateInfo( // hasUpdate: false, // currentVersion: currentVersion, // latestVersion: currentVersion, // updateType: UpdateType.none, // ); // } // final appInfo = channelAppResponse.data!.app; _hasUpdate = _compareVersions(currentVersion, appInfo.version); // 判断更新类型:如果主版本号不同则强制更新 UpdateType updateType = UpdateType.none; if (_hasUpdate!) { _isForceUpdate = _shouldForceUpdate(currentVersion, appInfo.version); updateType = _isForceUpdate! ? UpdateType.force : UpdateType.optional; } return VersionUpdateInfo( hasUpdate: _hasUpdate!, currentVersion: currentVersion.split('+')[0], latestVersion: appInfo.version.split('+')[0], appInfo: appInfo, updateType: updateType, ); } catch (e) { _logger.e('检查版本更新失败: $e'); // 发生错误时,保持默认值 false _isShowTourists = false; final currentVersion = await getCurrentVersion(); return VersionUpdateInfo( hasUpdate: false, currentVersion: currentVersion, latestVersion: currentVersion, updateType: UpdateType.none, ); } } /// 判断是否需要强制更新 /// 当主版本号(第一位数字)不同时返回true bool _shouldForceUpdate(String current, String latest) { try { // 拆分版本号与构建号 final currentParts = current.split('+'); final latestParts = latest.split('+'); // 解析版本号 (major.minor.patch) final currentVersions = currentParts[0].split('.').map(int.parse).toList(); final latestVersions = latestParts[0].split('.').map(int.parse).toList(); // 比较主版本号(第一位) if (currentVersions.isNotEmpty && latestVersions.isNotEmpty) { if (currentVersions[0] != latestVersions[0]) { return true; } } // 检查是否有两个或更多的 + 号,如果有则强制更新 if (latest.split('+').length > 2) { return true; } return false; } catch (e) { _logger.e('判断强制更新失败: $e'); return false; } } /// 比较版本号 /// 返回true表示需要更新(远程版本更高) bool _compareVersions(String current, String latest) { // 拆分版本号与构建号 final currentParts = current.split('+')[0]; final latestParts = latest.split('+')[0]; // 解析版本号 (major.minor.patch) final currentVersions = currentParts.split('.').map(int.parse).toList(); final latestVersions = latestParts.split('.').map(int.parse).toList(); // 使用较小的长度进行比较,避免索引越界 final minLength = math.min(currentVersions.length, latestVersions.length); // 逐级比较版本号 for (var i = 0; i < minLength; i++) { if (latestVersions[i] > currentVersions[i]) return true; if (latestVersions[i] < currentVersions[i]) return false; } // 如果前面的版本号都相同,比较长度 // 更长的版本号被认为是更新的版本(如 1.0.1 > 1.0) return latestVersions.length > currentVersions.length; } /// 解析版本号字符串为数字数组 List _parseVersion(String version) { final parts = version.split('.'); final result = []; for (int i = 0; i < 3; i++) { if (i < parts.length) { result.add(int.tryParse(parts[i]) ?? 0); } else { result.add(0); } } return result; } /// 执行更新操作 Future performUpdate(VersionUpdateInfo updateInfo) async { if (!updateInfo.hasUpdate || updateInfo.appInfo == null) { return false; } try { return await _openDownloadUrl(updateInfo.appInfo!.address!); } catch (e) { _logger.e('执行更新失败: $e'); return false; } } /// 打开下载链接 Future _openDownloadUrl(String downloadUrl) async { return await _launchUrl(downloadUrl); } /// 启动URL Future _launchUrl(String url) async { try { final uri = Uri.parse(url); if (await canLaunchUrl(uri)) { return await launchUrl(uri, mode: LaunchMode.externalApplication); } return false; } catch (e) { _logger.e('启动URL失败: $e'); return false; } } }