Browse Source

refactor(version_update): 重构版本更新服务并添加内存缓存

将版本更新服务重构为使用静态变量缓存应用信息,减少重复获取
添加 UserChannel.fromName 方法支持从字符串创建枚举
移除重复的 UserChannel 定义并统一使用 channel_app_model
优化游客登录状态检查逻辑,直接使用缓存值
weicu
lxm 1 year ago
parent
commit
df9548289c
  1. 24
      lib/data/models/channel_app_model.dart
  2. 178
      lib/data/services/version_update_service.dart
  3. 62
      lib/modules/login/controllers/login_controller.dart
  4. 7
      lib/modules/settings/views/settings_view.dart

24
lib/data/models/channel_app_model.dart

@ -177,6 +177,30 @@ enum UserChannel {
); );
} }
// 从字符串名称创建枚举
static UserChannel fromName(String name) {
switch (name.toUpperCase()) {
case 'CHINA_HUAWEI':
return UserChannel.CHINA_HUAWEI;
case 'CHINA_XIAOMI':
return UserChannel.CHINA_XIAOMI;
case 'CHINA_OPPO':
return UserChannel.CHINA_OPPO;
case 'CHINA_VIVO':
return UserChannel.CHINA_VIVO;
case 'CHINA_HONOR':
return UserChannel.CHINA_HONOR;
case 'OFFICIAL':
return UserChannel.OFFICIAL;
case 'GLOBAL_APPLE':
return UserChannel.GLOBAL_APPLE;
case 'GLOBAL_GOOGLE':
return UserChannel.GLOBAL_GOOGLE;
default:
return UserChannel.UNKNOWN;
}
}
// JSON 序列化时返回数字值 // JSON 序列化时返回数字值
int toJson() => value; int toJson() => value;

178
lib/data/services/version_update_service.dart

@ -5,6 +5,7 @@ import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:logger/logger.dart'; import 'package:logger/logger.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import '../models/channel_app_model.dart'; import '../models/channel_app_model.dart';
import 'network/api.dart'; import 'network/api.dart';
import 'dart:math' as math; import 'dart:math' as math;
@ -13,15 +14,62 @@ import 'dart:math' as math;
class VersionUpdateService extends GetxService { class VersionUpdateService extends GetxService {
static VersionUpdateService get to => Get.find(); 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 { Future<String> getCurrentVersion() async {
try { try {
final packageInfo = await PackageInfo.fromPlatform(); final packageInfo = await PackageInfo.fromPlatform();
_appVersion = packageInfo.version;
_buildNumber = packageInfo.buildNumber;
return '${packageInfo.version}+${packageInfo.buildNumber}'; return '${packageInfo.version}+${packageInfo.buildNumber}';
} catch (e) { } catch (e) {
_logger.e('获取当前版本信息失败: $e'); _logger.e('获取当前版本信息失败: $e');
@ -31,14 +79,6 @@ class VersionUpdateService extends GetxService {
/// 获取当前平台信息 /// 获取当前平台信息
Future<PlatformInfo> getCurrentPlatformInfo() async { Future<PlatformInfo> getCurrentPlatformInfo() async {
if (kIsWeb) {
return const PlatformInfo(
platform: 'web',
storeType: AppStoreType.official,
channel: UserChannel.OFFICIAL,
);
}
if (Platform.isIOS) { if (Platform.isIOS) {
return const PlatformInfo( return const PlatformInfo(
platform: 'ios', platform: 'ios',
@ -66,10 +106,14 @@ class VersionUpdateService extends GetxService {
final androidInfo = await deviceInfo.androidInfo; final androidInfo = await deviceInfo.androidInfo;
final brand = androidInfo.brand.toLowerCase(); final brand = androidInfo.brand.toLowerCase();
return const PlatformInfo( _deviceBrand = brand;
String channelFromEnv = dotenv.env['Channel'] ?? 'OFFICIAL';
_channel = UserChannel.fromName(channelFromEnv);
return PlatformInfo(
platform: 'android', platform: 'android',
storeType: AppStoreType.official, storeType: AppStoreType.official,
channel: UserChannel.OFFICIAL, channel: _channel ?? UserChannel.OFFICIAL,
); );
// switch (brand) { // switch (brand) {
@ -121,10 +165,27 @@ class VersionUpdateService extends GetxService {
/// 检查版本更新 /// 检查版本更新
Future<VersionUpdateInfo> checkForUpdate() async { 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 { try {
final currentVersion = await getCurrentVersion(); final currentVersion = await getCurrentVersion();
final platformInfo = await getCurrentPlatformInfo(); final platformInfo = await getCurrentPlatformInfo();
_platform = platformInfo.platform;
_channel = platformInfo.channel;
_lastCheckTime = DateTime.now();
// 调用后端接口获取最新版本信息 // 调用后端接口获取最新版本信息
final response = final response =
await Api.getChannelApp({'channel': platformInfo.channel.value}); await Api.getChannelApp({'channel': platformInfo.channel.value});
@ -144,9 +205,11 @@ class VersionUpdateService extends GetxService {
// 直接从response中获取app信息 // 直接从response中获取app信息
final appInfo = AppInfo.fromJson(response['app']); final appInfo = AppInfo.fromJson(response['app']);
_logger.d('获取到的最新版本信息: ${appInfo.toJson()}'); _logger.d('获取到的最新版本信息: ${appInfo.toJson()}');
_latestVersion = appInfo.version;
_updateUrl = appInfo.address;
// 设置游客登录显示状态 // 设置游客登录显示状态
isShowTourists.value = appInfo.tourists; _isShowTourists = appInfo.tourists;
_logger.d('从服务器获取游客登录配置: ${appInfo.tourists}'); _logger.d('从服务器获取游客登录配置: ${appInfo.tourists}');
// if (channelAppResponse.code != 0 || channelAppResponse.data == null) { // if (channelAppResponse.code != 0 || channelAppResponse.data == null) {
@ -160,18 +223,17 @@ class VersionUpdateService extends GetxService {
// } // }
// final appInfo = channelAppResponse.data!.app; // final appInfo = channelAppResponse.data!.app;
final hasUpdate = _compareVersions(currentVersion, appInfo.version); _hasUpdate = _compareVersions(currentVersion, appInfo.version);
// 判断更新类型:如果主版本号不同则强制更新 // 判断更新类型:如果主版本号不同则强制更新
UpdateType updateType = UpdateType.none; UpdateType updateType = UpdateType.none;
if (hasUpdate) { if (_hasUpdate!) {
final isForceUpdate = _isForceUpdate = _shouldForceUpdate(currentVersion, appInfo.version);
_shouldForceUpdate(currentVersion, appInfo.version); updateType = _isForceUpdate! ? UpdateType.force : UpdateType.optional;
updateType = isForceUpdate ? UpdateType.force : UpdateType.optional;
} }
return VersionUpdateInfo( return VersionUpdateInfo(
hasUpdate: hasUpdate, hasUpdate: _hasUpdate!,
currentVersion: currentVersion.split('+')[0], currentVersion: currentVersion.split('+')[0],
latestVersion: appInfo.version.split('+')[0], latestVersion: appInfo.version.split('+')[0],
appInfo: appInfo, appInfo: appInfo,
@ -180,7 +242,7 @@ class VersionUpdateService extends GetxService {
} catch (e) { } catch (e) {
_logger.e('检查版本更新失败: $e'); _logger.e('检查版本更新失败: $e');
// 发生错误时,保持默认值 false // 发生错误时,保持默认值 false
isShowTourists.value = false; _isShowTourists = false;
final currentVersion = await getCurrentVersion(); final currentVersion = await getCurrentVersion();
return VersionUpdateInfo( return VersionUpdateInfo(
hasUpdate: false, hasUpdate: false,
@ -270,84 +332,16 @@ class VersionUpdateService extends GetxService {
return false; return false;
} }
//final platformInfo = await getCurrentPlatformInfo();
try { try {
// switch (platformInfo.storeType) { return await _openDownloadUrl(updateInfo.appInfo!.address!);
// 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!);
// }
} catch (e) { } catch (e) {
_logger.e('执行更新失败: $e'); _logger.e('执行更新失败: $e');
return false; return false;
} }
} }
/// 打开iOS App Store /// 打开下载链接
Future<bool> _openAppStore() async { Future<bool> _openDownloadUrl(String downloadUrl) 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 {
return await _launchUrl(downloadUrl); return await _launchUrl(downloadUrl);
} }

62
lib/modules/login/controllers/login_controller.dart

@ -1,23 +1,23 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import '../../../data/models/appconfig.dart';
import '../../../data/models/appconfig_model.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:logger/web.dart'; import 'package:logger/web.dart';
import '../../../routes/app_routes.dart'; import 'package:get_storage/get_storage.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'dart:convert'; import 'dart:convert';
import 'facebookLogin.dart'; import 'facebookLogin.dart';
import 'googleLogin.dart'; import 'googleLogin.dart';
import 'weixinLogin.dart'; import 'weixinLogin.dart';
import 'appleLogin.dart'; import 'appleLogin.dart';
import '../../../routes/app_routes.dart';
import '../../../data/models/appconfig.dart';
import '../../../data/models/appconfig_model.dart';
import '../../../data/services/network/api.dart'; import '../../../data/services/network/api.dart';
import '../../../../data/models/user_Info.dart'; import '../../../../data/models/user_Info.dart';
import 'package:get_storage/get_storage.dart'; import '../../../data/models/channel_app_model.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'dart:io';
import 'package:package_info_plus/package_info_plus.dart';
import '../../../data/services/version_update_service.dart'; import '../../../data/services/version_update_service.dart';
import '../../../modules/common/widgets/privacy_policy_dialog.dart'; import '../../../modules/common/widgets/privacy_policy_dialog.dart';
@ -27,20 +27,20 @@ enum LoginViewState {
} }
// 用户渠道枚举 // 用户渠道枚举
enum UserChannel { // enum UserChannel {
UNKNOWN(0), // 未知渠道 // UNKNOWN(0), // 未知渠道
CHINA_HUAWEI(1), // 中国-华为 // CHINA_HUAWEI(1), // 中国-华为
CHINA_XIAOMI(2), // 中国-小米 // CHINA_XIAOMI(2), // 中国-小米
CHINA_OPPO(3), // 中国-OPPO // CHINA_OPPO(3), // 中国-OPPO
CHINA_VIVO(4), // 中国-VIVO // CHINA_VIVO(4), // 中国-VIVO
CHINA_HONOR(5), // 中国-荣耀 // CHINA_HONOR(5), // 中国-荣耀
OFFICIAL(100), // 官方渠道 // OFFICIAL(100), // 官方渠道
GLOBAL_APPLE(101), // 全球-苹果 // GLOBAL_APPLE(101), // 全球-苹果
GLOBAL_GOOGLE(102); // 全球-谷歌 // GLOBAL_GOOGLE(102); // 全球-谷歌
const UserChannel(this.value); // const UserChannel(this.value);
final int value; // final int value;
} // }
class LoginController extends GetxController { class LoginController extends GetxController {
static LoginController get to => Get.find(); static LoginController get to => Get.find();
@ -212,6 +212,7 @@ class LoginController extends GetxController {
String get contactValue => _contactValue.value; String get contactValue => _contactValue.value;
String get displayContact => _displayContact.value; String get displayContact => _displayContact.value;
List<String> get verificationCode => _verificationCode; List<String> get verificationCode => _verificationCode;
final versionService = VersionUpdateService.to;
// 文本控制器 // 文本控制器
TextEditingController contactController = TextEditingController(); TextEditingController contactController = TextEditingController();
@ -246,20 +247,9 @@ class LoginController extends GetxController {
// 检查游客登录配置 // 检查游客登录配置
Future<void> _checkGuestLoginConfig() async { Future<void> _checkGuestLoginConfig() async {
try { try {
final versionService = VersionUpdateService.to; _isGuestLoginVisible.value = versionService.cachedShowTourists;
// 先检查版本更新,这会同时设置 isShowTourists 的值
await versionService.checkForUpdate();
// 直接使用 VersionUpdateService 中的 isShowTourists 值
_isGuestLoginVisible.value = versionService.isShowTourists.value;
Logger().d('游客登录显示状态: ${_isGuestLoginVisible.value}'); Logger().d('游客登录显示状态: ${_isGuestLoginVisible.value}');
// 监听 isShowTourists 的变化
versionService.isShowTourists.listen((value) {
_isGuestLoginVisible.value = value;
Logger().d('游客登录显示状态更新: $value');
});
} catch (e) { } catch (e) {
Logger().e('检查游客登录配置失败: $e'); Logger().e('检查游客登录配置失败: $e');
// 默认不显示游客登录 // 默认不显示游客登录
@ -301,9 +291,7 @@ class LoginController extends GetxController {
// 新增:初始化APP信息(版本号、渠道、国家代码) // 新增:初始化APP信息(版本号、渠道、国家代码)
Future<void> _initAppInfo() async { Future<void> _initAppInfo() async {
try { try {
// 获取APP版本号 _appVersion = versionService.cachedAppVersion;
final packageInfo = await PackageInfo.fromPlatform();
_appVersion = '${packageInfo.version}+${packageInfo.buildNumber}';
Logger().d('appVersion: $_appVersion'); Logger().d('appVersion: $_appVersion');
// 获取国家代码 // 获取国家代码
@ -311,7 +299,7 @@ class LoginController extends GetxController {
Logger().d('countryCode: $_countryCode'); Logger().d('countryCode: $_countryCode');
// 获取用户渠道(根据平台和设备信息确定) // 获取用户渠道(根据平台和设备信息确定)
_userChannel = UserChannel.OFFICIAL; _userChannel = versionService.cachedChannel;
Logger().d('userChannel: ${_userChannel.value}'); Logger().d('userChannel: ${_userChannel.value}');
} catch (e) { } catch (e) {
Logger().e('获取APP信息失败: $e'); Logger().e('获取APP信息失败: $e');

7
lib/modules/settings/views/settings_view.dart

@ -16,13 +16,6 @@ import '../../profile/views/unified_avatar.dart';
class SettingsView extends GetView<SettingsController> { class SettingsView extends GetView<SettingsController> {
const SettingsView({Key? key}) : super(key: key); const SettingsView({Key? key}) : super(key: key);
// 正确获取用户名方式
// String get userName => User.getname();
// String get deviceInfo => User.getdeviceInfo();
// String get userId => User.getuserId();
// String get standing => User.getstanding();
// String get avatar => User.getnavatar();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// 直接使用 Theme.of(context) 获取当前主题 // 直接使用 Theme.of(context) 获取当前主题

Loading…
Cancel
Save