|
|
|
@ -5,6 +5,7 @@ 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; |
|
|
|
@ -13,15 +14,62 @@ import 'dart:math' as math; |
|
|
|
class VersionUpdateService extends GetxService { |
|
|
|
static VersionUpdateService get to => Get.find(); |
|
|
|
|
|
|
|
final Logger _logger = Logger(); |
|
|
|
// 静态应用信息(内存缓存) |
|
|
|
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; |
|
|
|
|
|
|
|
// 游客登录显示状态 |
|
|
|
final isShowTourists = false.obs; |
|
|
|
/// 获取上次检查时间 |
|
|
|
DateTime? get lastCheckTime => _lastCheckTime; |
|
|
|
|
|
|
|
final Logger _logger = Logger(); |
|
|
|
|
|
|
|
/// 获取当前应用版本信息 |
|
|
|
Future<String> getCurrentVersion() async { |
|
|
|
try { |
|
|
|
final packageInfo = await PackageInfo.fromPlatform(); |
|
|
|
_appVersion = packageInfo.version; |
|
|
|
_buildNumber = packageInfo.buildNumber; |
|
|
|
return '${packageInfo.version}+${packageInfo.buildNumber}'; |
|
|
|
} catch (e) { |
|
|
|
_logger.e('获取当前版本信息失败: $e'); |
|
|
|
@ -31,14 +79,6 @@ class VersionUpdateService extends GetxService { |
|
|
|
|
|
|
|
/// 获取当前平台信息 |
|
|
|
Future<PlatformInfo> getCurrentPlatformInfo() async { |
|
|
|
if (kIsWeb) { |
|
|
|
return const PlatformInfo( |
|
|
|
platform: 'web', |
|
|
|
storeType: AppStoreType.official, |
|
|
|
channel: UserChannel.OFFICIAL, |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
if (Platform.isIOS) { |
|
|
|
return const PlatformInfo( |
|
|
|
platform: 'ios', |
|
|
|
@ -66,10 +106,14 @@ class VersionUpdateService extends GetxService { |
|
|
|
final androidInfo = await deviceInfo.androidInfo; |
|
|
|
final brand = androidInfo.brand.toLowerCase(); |
|
|
|
|
|
|
|
return const PlatformInfo( |
|
|
|
_deviceBrand = brand; |
|
|
|
String channelFromEnv = dotenv.env['Channel'] ?? 'OFFICIAL'; |
|
|
|
_channel = UserChannel.fromName(channelFromEnv); |
|
|
|
|
|
|
|
return PlatformInfo( |
|
|
|
platform: 'android', |
|
|
|
storeType: AppStoreType.official, |
|
|
|
channel: UserChannel.OFFICIAL, |
|
|
|
channel: _channel ?? UserChannel.OFFICIAL, |
|
|
|
); |
|
|
|
|
|
|
|
// switch (brand) { |
|
|
|
@ -121,10 +165,27 @@ class VersionUpdateService extends GetxService { |
|
|
|
|
|
|
|
/// 检查版本更新 |
|
|
|
Future<VersionUpdateInfo> 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}); |
|
|
|
@ -144,9 +205,11 @@ class VersionUpdateService extends GetxService { |
|
|
|
// 直接从response中获取app信息 |
|
|
|
final appInfo = AppInfo.fromJson(response['app']); |
|
|
|
_logger.d('获取到的最新版本信息: ${appInfo.toJson()}'); |
|
|
|
_latestVersion = appInfo.version; |
|
|
|
_updateUrl = appInfo.address; |
|
|
|
|
|
|
|
// 设置游客登录显示状态 |
|
|
|
isShowTourists.value = appInfo.tourists; |
|
|
|
_isShowTourists = appInfo.tourists; |
|
|
|
_logger.d('从服务器获取游客登录配置: ${appInfo.tourists}'); |
|
|
|
|
|
|
|
// if (channelAppResponse.code != 0 || channelAppResponse.data == null) { |
|
|
|
@ -160,18 +223,17 @@ class VersionUpdateService extends GetxService { |
|
|
|
// } |
|
|
|
|
|
|
|
// final appInfo = channelAppResponse.data!.app; |
|
|
|
final hasUpdate = _compareVersions(currentVersion, appInfo.version); |
|
|
|
_hasUpdate = _compareVersions(currentVersion, appInfo.version); |
|
|
|
|
|
|
|
// 判断更新类型:如果主版本号不同则强制更新 |
|
|
|
UpdateType updateType = UpdateType.none; |
|
|
|
if (hasUpdate) { |
|
|
|
final isForceUpdate = |
|
|
|
_shouldForceUpdate(currentVersion, appInfo.version); |
|
|
|
updateType = isForceUpdate ? UpdateType.force : UpdateType.optional; |
|
|
|
if (_hasUpdate!) { |
|
|
|
_isForceUpdate = _shouldForceUpdate(currentVersion, appInfo.version); |
|
|
|
updateType = _isForceUpdate! ? UpdateType.force : UpdateType.optional; |
|
|
|
} |
|
|
|
|
|
|
|
return VersionUpdateInfo( |
|
|
|
hasUpdate: hasUpdate, |
|
|
|
hasUpdate: _hasUpdate!, |
|
|
|
currentVersion: currentVersion.split('+')[0], |
|
|
|
latestVersion: appInfo.version.split('+')[0], |
|
|
|
appInfo: appInfo, |
|
|
|
@ -180,7 +242,7 @@ class VersionUpdateService extends GetxService { |
|
|
|
} catch (e) { |
|
|
|
_logger.e('检查版本更新失败: $e'); |
|
|
|
// 发生错误时,保持默认值 false |
|
|
|
isShowTourists.value = false; |
|
|
|
_isShowTourists = false; |
|
|
|
final currentVersion = await getCurrentVersion(); |
|
|
|
return VersionUpdateInfo( |
|
|
|
hasUpdate: false, |
|
|
|
@ -270,84 +332,16 @@ class VersionUpdateService extends GetxService { |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
//final platformInfo = await getCurrentPlatformInfo(); |
|
|
|
|
|
|
|
try { |
|
|
|
// switch (platformInfo.storeType) { |
|
|
|
// case AppStoreType.appStore: |
|
|
|
// return await _openAppStore(); |
|
|
|
// case AppStoreType.googlePlay: |
|
|
|
// return await _openGooglePlay(); |
|
|
|
// case AppStoreType.huawei: |
|
|
|
// return await _openHuaweiStore(); |
|
|
|
// case AppStoreType.xiaomi: |
|
|
|
// return await _openXiaomiStore(); |
|
|
|
// case AppStoreType.oppo: |
|
|
|
// return await _openOppoStore(); |
|
|
|
// case AppStoreType.vivo: |
|
|
|
// return await _openVivoStore(); |
|
|
|
// case AppStoreType.honor: |
|
|
|
// return await _openHonorStore(); |
|
|
|
// case AppStoreType.official: |
|
|
|
// return await _openOfficialDownload(updateInfo.appInfo!.address!); |
|
|
|
// default: |
|
|
|
return await _openOfficialDownload(updateInfo.appInfo!.address!); |
|
|
|
// } |
|
|
|
return await _openDownloadUrl(updateInfo.appInfo!.address!); |
|
|
|
} catch (e) { |
|
|
|
_logger.e('执行更新失败: $e'); |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开iOS App Store |
|
|
|
Future<bool> _openAppStore() async { |
|
|
|
// 这里需要替换为实际的App Store ID |
|
|
|
const appStoreUrl = 'https://apps.apple.com/app/id你的应用ID'; |
|
|
|
return await _launchUrl(appStoreUrl); |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开Google Play |
|
|
|
Future<bool> _openGooglePlay() async { |
|
|
|
// 这里需要替换为实际的包名 |
|
|
|
const packageName = 'com.yourcompany.deepvoice'; |
|
|
|
const playStoreUrl = |
|
|
|
'https://play.google.com/store/apps/details?id=$packageName'; |
|
|
|
return await _launchUrl(playStoreUrl); |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开华为应用市场 |
|
|
|
Future<bool> _openHuaweiStore() async { |
|
|
|
const huaweiStoreUrl = 'appmarket://details?id=com.yourcompany.deepvoice'; |
|
|
|
return await _launchUrl(huaweiStoreUrl); |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开小米应用商店 |
|
|
|
Future<bool> _openXiaomiStore() async { |
|
|
|
const xiaomiStoreUrl = 'mimarket://details?id=com.yourcompany.deepvoice'; |
|
|
|
return await _launchUrl(xiaomiStoreUrl); |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开OPPO软件商店 |
|
|
|
Future<bool> _openOppoStore() async { |
|
|
|
const oppoStoreUrl = |
|
|
|
'oppomarket://details?packagename=com.yourcompany.deepvoice'; |
|
|
|
return await _launchUrl(oppoStoreUrl); |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开vivo应用商店 |
|
|
|
Future<bool> _openVivoStore() async { |
|
|
|
const vivoStoreUrl = 'vivomarket://details?id=com.yourcompany.deepvoice'; |
|
|
|
return await _launchUrl(vivoStoreUrl); |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开荣耀应用市场 |
|
|
|
Future<bool> _openHonorStore() async { |
|
|
|
const honorStoreUrl = 'honormarket://details?id=com.yourcompany.deepvoice'; |
|
|
|
return await _launchUrl(honorStoreUrl); |
|
|
|
} |
|
|
|
|
|
|
|
/// 打开官网下载 |
|
|
|
Future<bool> _openOfficialDownload(String downloadUrl) async { |
|
|
|
/// 打开下载链接 |
|
|
|
Future<bool> _openDownloadUrl(String downloadUrl) async { |
|
|
|
return await _launchUrl(downloadUrl); |
|
|
|
} |
|
|
|
|
|
|
|
|