From c10c89c94fa557d88ecd867af552ff2bb2818099 Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Fri, 20 Jun 2025 10:59:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=89=88=E6=9C=AC=E6=9B=B4=E6=96=B0):=20?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=BA=94=E7=94=A8=E7=89=88=E6=9C=AC=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E4=B8=8E=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加版本更新服务及相关组件,包括: 1. 新增 VersionUpdateService 处理版本检查逻辑 2. 添加版本更新对话框组件 VersionUpdateDialog 3. 实现渠道包信息获取 API 接口 4. 在设置和启动页集成版本检查功能 5. 添加 url_launcher 依赖用于应用商店跳转 --- android/app/build.gradle.kts | 4 +- ios/Runner/Info.plist | 2 +- lib/core/bindings/initial_binding.dart | 4 + lib/data/models/appconfig_model.g.dart | 2 +- lib/data/models/channel_app_model.dart | 151 +++++++++ lib/data/models/channel_app_model.g.dart | 47 +++ lib/data/services/account_service.dart | 17 +- lib/data/services/network/api.dart | 9 + lib/data/services/version_update_service.dart | 312 ++++++++++++++++++ .../common/widgets/version_update_dialog.dart | 226 +++++++++++++ .../controllers/settings_controller.dart | 48 +++ lib/modules/settings/views/settings_view.dart | 3 +- .../splash/controllers/splash_controller.dart | 24 ++ pubspec.yaml | 1 + 14 files changed, 843 insertions(+), 7 deletions(-) create mode 100644 lib/data/models/channel_app_model.dart create mode 100644 lib/data/models/channel_app_model.g.dart create mode 100644 lib/data/services/version_update_service.dart create mode 100644 lib/modules/common/widgets/version_update_dialog.dart diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 20d5ead25..cbb9afd88 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -69,8 +69,8 @@ android { // For more information, see: https://flutter.dev/to/review-gradle-config. minSdk = 26 // 更新为26以满足ble_service库的要求 targetSdk = 34 // 设置为 Android 13 (API 33),以匹配 FOREGROUND_SERVICE_MEDIA_PLAYBACK 权限的要求 - versionCode = flutter.versionCode - versionName = flutter.versionName + versionCode = flutter.versionCode // 对应构建号,自动同步flutter构建号 + versionName = flutter.versionName // 对应版本号,自动同步flutter版本号 } signingConfigs { diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index bc3f4a793..5be33da0e 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -39,7 +39,7 @@ - CFBundleVersion + CFBundleVersion $(FLUTTER_BUILD_NUMBER) FacebookAdvertiserIDCollectionEnabled diff --git a/lib/core/bindings/initial_binding.dart b/lib/core/bindings/initial_binding.dart index 08bb41500..c372b985a 100644 --- a/lib/core/bindings/initial_binding.dart +++ b/lib/core/bindings/initial_binding.dart @@ -10,6 +10,7 @@ import '../../core/utils/logger.dart'; import '../../data/services/bluetooth_manager.dart'; import '../../data/services/ble_manager.dart'; import '../../data/services/account_service.dart'; +import '../../data/services/version_update_service.dart'; /// 初始绑定,用于管理全局依赖 class InitialBinding extends Bindings { @@ -46,6 +47,9 @@ class InitialBinding extends Bindings { // 账号管理服务 Get.lazyPut(() => AccountService(), fenix: true); + // 版本更新服务 + Get.lazyPut(() => VersionUpdateService(), fenix: true); + // 杰理蓝牙服务 // // 语言管理器(需要最先初始化) diff --git a/lib/data/models/appconfig_model.g.dart b/lib/data/models/appconfig_model.g.dart index c4ac4cc90..ffb7f58b8 100644 --- a/lib/data/models/appconfig_model.g.dart +++ b/lib/data/models/appconfig_model.g.dart @@ -57,7 +57,7 @@ Map _$DBAgentToJson(DBAgent instance) => { DBMCPServer _$DBMCPServerFromJson(Map json) => DBMCPServer( servername: json['servername'] as String, url: json['url'] as String, - tools: json['tools'] as String? ?? '', + tools: json['tools'] as String, ); Map _$DBMCPServerToJson(DBMCPServer instance) => diff --git a/lib/data/models/channel_app_model.dart b/lib/data/models/channel_app_model.dart new file mode 100644 index 000000000..bddbf9f39 --- /dev/null +++ b/lib/data/models/channel_app_model.dart @@ -0,0 +1,151 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'channel_app_model.g.dart'; + +/// 渠道应用信息响应模型 +@JsonSerializable() +class ChannelAppResponse { + @JsonKey(name: 'code') + final int code; + + @JsonKey(name: 'data') + final ChannelAppData? data; + + @JsonKey(name: 'msg') + final String msg; + + const ChannelAppResponse({ + required this.code, + this.data, + required this.msg, + }); + + factory ChannelAppResponse.fromJson(Map json) => + _$ChannelAppResponseFromJson(json); + + Map toJson() => _$ChannelAppResponseToJson(this); +} + +/// 渠道应用数据模型 +@JsonSerializable() +class ChannelAppData { + @JsonKey(name: 'app') + final AppInfo app; + + const ChannelAppData({ + required this.app, + }); + + factory ChannelAppData.fromJson(Map json) => + _$ChannelAppDataFromJson(json); + + Map toJson() => _$ChannelAppDataToJson(this); +} + +/// 应用信息模型 +@JsonSerializable() +class AppInfo { + /// 下载地址 + @JsonKey(name: 'address') + final String address; + + /// 渠道标识 + @JsonKey(name: 'channel') + final String channel; + + /// 应用描述 + @JsonKey(name: 'description') + final String description; + + /// 最新版本号 + @JsonKey(name: 'version') + final String version; + + const AppInfo({ + required this.address, + required this.channel, + required this.description, + required this.version, + }); + + factory AppInfo.fromJson(Map json) => + _$AppInfoFromJson(json); + + Map toJson() => _$AppInfoToJson(this); +} + +/// 版本更新信息模型 +class VersionUpdateInfo { + /// 是否有新版本 + final bool hasUpdate; + + /// 当前版本 + final String currentVersion; + + /// 最新版本 + final String latestVersion; + + /// 应用信息 + final AppInfo? appInfo; + + /// 更新类型 + final UpdateType updateType; + + const VersionUpdateInfo({ + required this.hasUpdate, + required this.currentVersion, + required this.latestVersion, + this.appInfo, + required this.updateType, + }); +} + +/// 更新类型枚举 +enum UpdateType { + /// 无需更新 + none, + /// 可选更新 + optional, + /// 强制更新 + force, +} + +/// 应用商店类型枚举 +enum AppStoreType { + /// iOS App Store + appStore, + /// Google Play + googlePlay, + /// 华为应用市场 + huawei, + /// 小米应用商店 + xiaomi, + /// OPPO软件商店 + oppo, + /// vivo应用商店 + vivo, + /// 荣耀应用市场 + honor, + /// 官网下载 + official, + /// 未知 + unknown, +} + +/// 平台信息模型 +class PlatformInfo { + /// 平台类型 + final String platform; + + /// 应用商店类型 + final AppStoreType storeType; + + /// 渠道标识 + final String channel; + + const PlatformInfo({ + required this.platform, + required this.storeType, + required this.channel, + }); +} diff --git a/lib/data/models/channel_app_model.g.dart b/lib/data/models/channel_app_model.g.dart new file mode 100644 index 000000000..7d5e6aa6b --- /dev/null +++ b/lib/data/models/channel_app_model.g.dart @@ -0,0 +1,47 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'channel_app_model.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ChannelAppResponse _$ChannelAppResponseFromJson(Map json) => + ChannelAppResponse( + code: (json['code'] as num).toInt(), + data: json['data'] == null + ? null + : ChannelAppData.fromJson(json['data'] as Map), + msg: json['msg'] as String, + ); + +Map _$ChannelAppResponseToJson(ChannelAppResponse instance) => + { + 'code': instance.code, + 'data': instance.data, + 'msg': instance.msg, + }; + +ChannelAppData _$ChannelAppDataFromJson(Map json) => + ChannelAppData( + app: AppInfo.fromJson(json['app'] as Map), + ); + +Map _$ChannelAppDataToJson(ChannelAppData instance) => + { + 'app': instance.app, + }; + +AppInfo _$AppInfoFromJson(Map json) => AppInfo( + address: json['address'] as String, + channel: json['channel'] as String, + description: json['description'] as String, + version: json['version'] as String, + ); + +Map _$AppInfoToJson(AppInfo instance) => { + 'address': instance.address, + 'channel': instance.channel, + 'description': instance.description, + 'version': instance.version, + }; diff --git a/lib/data/services/account_service.dart b/lib/data/services/account_service.dart index 6c01ac65c..cbbe49de1 100644 --- a/lib/data/services/account_service.dart +++ b/lib/data/services/account_service.dart @@ -25,7 +25,7 @@ class AccountService extends GetxService { Future clearUserData() async { try { // 清理所有存储 - await _storage.erase(); + //await _storage.erase(); // 或者逐个清理关键存储项 await _storage.write("logintoken", null); await _storage.write("user_info", null); @@ -38,6 +38,18 @@ class AccountService extends GetxService { } } + Future clearAllUserData() async { + // 清理所有用户数据 + try { + await _storage.erase(); + logger.d('所有用户数据清理成功'); + return true; + } catch (e) { + logger.e('用户数据清理失败: $e'); + return false; + } + } + /// 退出第三方登录 /// /// 返回操作是否成功 @@ -105,7 +117,8 @@ class AccountService extends GetxService { } // 清理本地数据 - final dataCleaned = await clearUserData(); + final dataCleaned = await clearAllUserData(); // 一次性清除所有数据 + if (!dataCleaned) { return AccountOperationResult( success: false, diff --git a/lib/data/services/network/api.dart b/lib/data/services/network/api.dart index b2f43ac10..56eebceab 100644 --- a/lib/data/services/network/api.dart +++ b/lib/data/services/network/api.dart @@ -107,4 +107,13 @@ class Api { params: params, ); } + + //获取渠道包信息 + static getChannelApp([params]) { + return DioManager().request( + NWMethod.post, + '/api/home/user_getchannelapp', + params: params, + ); + } } diff --git a/lib/data/services/version_update_service.dart b/lib/data/services/version_update_service.dart new file mode 100644 index 000000000..5c62c0313 --- /dev/null +++ b/lib/data/services/version_update_service.dart @@ -0,0 +1,312 @@ +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 '../models/channel_app_model.dart'; +import 'network/api.dart'; + +/// 版本更新服务类 +class VersionUpdateService extends GetxService { + static VersionUpdateService get to => Get.find(); + + final Logger _logger = Logger(); + + /// 获取当前应用版本信息 + Future getCurrentVersion() async { + try { + final packageInfo = await PackageInfo.fromPlatform(); + return '${packageInfo.version}+${packageInfo.buildNumber}'; + } catch (e) { + _logger.e('获取当前版本信息失败: $e'); + return '1.0.0'; + } + } + + /// 获取当前平台信息 + Future getCurrentPlatformInfo() async { + if (kIsWeb) { + return const PlatformInfo( + platform: 'web', + storeType: AppStoreType.official, + channel: '官方网站', + ); + } + + if (Platform.isIOS) { + return const PlatformInfo( + platform: 'ios', + storeType: AppStoreType.appStore, + channel: 'App Store', + ); + } + + if (Platform.isAndroid) { + // 根据设备品牌判断应用商店类型 + return await getAndroidStoreInfoByBrand(); + } + + return const PlatformInfo( + platform: 'unknown', + storeType: AppStoreType.unknown, + channel: '未知', + ); + } + + /// 根据设备品牌获取应用商店信息 + Future getAndroidStoreInfoByBrand() async { + try { + final deviceInfo = DeviceInfoPlugin(); + final androidInfo = await deviceInfo.androidInfo; + final brand = androidInfo.brand.toLowerCase(); + + return const PlatformInfo( + platform: 'android', + storeType: AppStoreType.official, + channel: '官方内测', + ); + + // 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: 'Google Play', + ); + } + } + + /// 检查版本更新 + Future checkForUpdate() async { + try { + final currentVersion = await getCurrentVersion(); + final platformInfo = await getCurrentPlatformInfo(); + + // 调用后端接口获取最新版本信息 + final response = + await Api.getChannelApp({'channel': platformInfo.channel}); + + print('获取渠道包信息:$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']); + + // 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; + final hasUpdate = _compareVersions(currentVersion, appInfo.version); + + return VersionUpdateInfo( + hasUpdate: hasUpdate, + currentVersion: currentVersion, + latestVersion: appInfo.version, + appInfo: appInfo, + updateType: hasUpdate ? UpdateType.optional : UpdateType.none, + ); + } catch (e) { + _logger.e('检查版本更新失败: $e'); + final currentVersion = await getCurrentVersion(); + return VersionUpdateInfo( + hasUpdate: false, + currentVersion: currentVersion, + latestVersion: currentVersion, + updateType: UpdateType.none, + ); + } + } + + /// 比较版本号 + /// 返回true表示需要更新(远程版本更高) + bool _compareVersions(String currentVersion, String remoteVersion) { + try { + final current = _parseVersion(currentVersion); + final remote = _parseVersion(remoteVersion); + + for (int i = 0; i < 3; i++) { + if (remote[i] > current[i]) { + return true; + } else if (remote[i] < current[i]) { + return false; + } + } + return false; // 版本相同 + } catch (e) { + _logger.e('版本比较失败: $e'); + return false; + } + } + + /// 解析版本号字符串为数字数组 + 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; + } + + 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); + } + } catch (e) { + _logger.e('执行更新失败: $e'); + return false; + } + } + + /// 打开iOS App Store + Future _openAppStore() async { + // 这里需要替换为实际的App Store ID + const appStoreUrl = 'https://apps.apple.com/app/id你的应用ID'; + return await _launchUrl(appStoreUrl); + } + + /// 打开Google Play + Future _openGooglePlay() async { + // 这里需要替换为实际的包名 + const packageName = 'com.yourcompany.deepvoice'; + const playStoreUrl = + 'https://play.google.com/store/apps/details?id=$packageName'; + return await _launchUrl(playStoreUrl); + } + + /// 打开华为应用市场 + Future _openHuaweiStore() async { + const huaweiStoreUrl = 'appmarket://details?id=com.yourcompany.deepvoice'; + return await _launchUrl(huaweiStoreUrl); + } + + /// 打开小米应用商店 + Future _openXiaomiStore() async { + const xiaomiStoreUrl = 'mimarket://details?id=com.yourcompany.deepvoice'; + return await _launchUrl(xiaomiStoreUrl); + } + + /// 打开OPPO软件商店 + Future _openOppoStore() async { + const oppoStoreUrl = + 'oppomarket://details?packagename=com.yourcompany.deepvoice'; + return await _launchUrl(oppoStoreUrl); + } + + /// 打开vivo应用商店 + Future _openVivoStore() async { + const vivoStoreUrl = 'vivomarket://details?id=com.yourcompany.deepvoice'; + return await _launchUrl(vivoStoreUrl); + } + + /// 打开荣耀应用市场 + Future _openHonorStore() async { + const honorStoreUrl = 'honormarket://details?id=com.yourcompany.deepvoice'; + return await _launchUrl(honorStoreUrl); + } + + /// 打开官网下载 + Future _openOfficialDownload(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; + } + } +} diff --git a/lib/modules/common/widgets/version_update_dialog.dart b/lib/modules/common/widgets/version_update_dialog.dart new file mode 100644 index 000000000..a52077bdf --- /dev/null +++ b/lib/modules/common/widgets/version_update_dialog.dart @@ -0,0 +1,226 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:get/get.dart'; +import '../../../data/models/channel_app_model.dart'; +import '../../../data/services/version_update_service.dart'; + +/// 版本更新提示对话框 +class VersionUpdateDialog extends StatelessWidget { + final VersionUpdateInfo updateInfo; + final VoidCallback? onCancel; + final VoidCallback? onUpdate; + + const VersionUpdateDialog({ + super.key, + required this.updateInfo, + this.onCancel, + this.onUpdate, + }); + + @override + Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + + return Dialog( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.r), + ), + child: Container( + width: 320.w, + padding: EdgeInsets.all(24.w), + decoration: BoxDecoration( + color: isDarkMode ? Colors.grey[900] : Colors.white, + borderRadius: BorderRadius.circular(16.r), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + // 标题图标 + Container( + width: 64.w, + height: 64.w, + decoration: BoxDecoration( + color: Colors.blue.withOpacity(0.1), + borderRadius: BorderRadius.circular(32.r), + ), + child: Icon( + Icons.system_update, + size: 32.sp, + color: Colors.blue, + ), + ), + + SizedBox(height: 16.h), + + // 标题 + Text( + '发现新版本', + style: TextStyle( + fontSize: 20.sp, + fontWeight: FontWeight.bold, + color: isDarkMode ? Colors.white : Colors.black87, + ), + ), + + SizedBox(height: 8.h), + + // 版本信息 + Text( + '${updateInfo.currentVersion} → ${updateInfo.latestVersion}', + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + ), + ), + + SizedBox(height: 16.h), + + // 更新描述 + if (updateInfo.appInfo?.description.isNotEmpty == true) ...[ + Container( + width: double.infinity, + padding: EdgeInsets.all(12.w), + decoration: BoxDecoration( + color: isDarkMode ? Colors.grey[800] : Colors.grey[100], + borderRadius: BorderRadius.circular(8.r), + ), + child: Text( + updateInfo.appInfo!.description, + style: TextStyle( + fontSize: 14.sp, + color: isDarkMode ? Colors.grey[300] : Colors.grey[700], + height: 1.4, + ), + ), + ), + SizedBox(height: 20.h), + ], + + // 按钮区域 + Row( + children: [ + // 取消按钮(仅在非强制更新时显示) + if (updateInfo.updateType != UpdateType.force) ...[ + Expanded( + child: TextButton( + onPressed: () { + Get.back(); + onCancel?.call(); + }, + style: TextButton.styleFrom( + padding: EdgeInsets.symmetric(vertical: 12.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + side: BorderSide( + color: isDarkMode ? Colors.grey[600]! : Colors.grey[300]!, + ), + ), + ), + child: Text( + '稍后提醒', + style: TextStyle( + fontSize: 16.sp, + color: isDarkMode ? Colors.grey[400] : Colors.grey[600], + ), + ), + ), + ), + SizedBox(width: 12.w), + ], + + // 更新按钮 + Expanded( + child: ElevatedButton( + onPressed: () async { + Get.back(); + await _handleUpdate(); + onUpdate?.call(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: Colors.blue, + foregroundColor: Colors.white, + padding: EdgeInsets.symmetric(vertical: 12.h), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.r), + ), + elevation: 0, + ), + child: Text( + _getUpdateButtonText(), + style: TextStyle( + fontSize: 16.sp, + fontWeight: FontWeight.w600, + ), + ), + ), + ), + ], + ), + ], + ), + ), + ); + } + + /// 获取更新按钮文本 + String _getUpdateButtonText() { + switch (updateInfo.updateType) { + case UpdateType.force: + return '立即更新'; + case UpdateType.optional: + return '立即更新'; + default: + return '检查更新'; + } + } + + /// 处理更新操作 + Future _handleUpdate() async { + try { + // 显示加载提示 + Get.dialog( + const Center( + child: CircularProgressIndicator(), + ), + barrierDismissible: false, + ); + + final versionService = VersionUpdateService.to; + final success = await versionService.performUpdate(updateInfo); + + // 关闭加载提示 + Get.back(); + + if (!success) { + Get.snackbar( + '更新失败', + '无法打开应用商店,请手动前往应用商店更新', + snackPosition: SnackPosition.TOP, + backgroundColor: Colors.red.withOpacity(0.8), + colorText: Colors.white, + ); + } + } catch (e) { + // 关闭加载提示 + if (Get.isDialogOpen == true) { + Get.back(); + } + + Get.snackbar( + '更新失败', + '更新过程中发生错误,请稍后重试', + snackPosition: SnackPosition.TOP, + backgroundColor: Colors.red.withOpacity(0.8), + colorText: Colors.white, + ); + } + } + + /// 显示版本更新对话框 + static Future show(VersionUpdateInfo updateInfo) async { + await Get.dialog( + VersionUpdateDialog(updateInfo: updateInfo), + barrierDismissible: updateInfo.updateType != UpdateType.force, + ); + } +} diff --git a/lib/modules/settings/controllers/settings_controller.dart b/lib/modules/settings/controllers/settings_controller.dart index 36fd66fe3..285f687a0 100644 --- a/lib/modules/settings/controllers/settings_controller.dart +++ b/lib/modules/settings/controllers/settings_controller.dart @@ -16,6 +16,8 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'dart:async'; import 'package:app_settings/app_settings.dart'; +import '../../../data/services/version_update_service.dart'; +import '../../common/widgets/version_update_dialog.dart'; class SettingsController extends GetxController { // 语言设置 @@ -490,4 +492,50 @@ class SettingsController extends GetxController { } } } + + /// 手动检查版本更新 + Future checkForUpdate() async { + try { + // 显示加载提示 + Get.dialog( + const Center( + child: CircularProgressIndicator(), + ), + barrierDismissible: false, + ); + + final versionService = VersionUpdateService.to; + final updateInfo = await versionService.checkForUpdate(); + + // 关闭加载提示 + Get.back(); + + if (updateInfo.hasUpdate) { + // 显示更新对话框 + await VersionUpdateDialog.show(updateInfo); + } else { + // 显示已是最新版本的提示 + Get.snackbar( + '检查更新', + '当前已是最新版本 ${updateInfo.currentVersion}', + snackPosition: SnackPosition.TOP, + backgroundColor: Colors.green.withOpacity(0.8), + colorText: Colors.white, + ); + } + } catch (e) { + // 关闭加载提示 + if (Get.isDialogOpen == true) { + Get.back(); + } + + Get.snackbar( + '检查更新失败', + '网络连接异常,请稍后重试', + snackPosition: SnackPosition.TOP, + backgroundColor: Colors.red.withOpacity(0.8), + colorText: Colors.white, + ); + } + } } diff --git a/lib/modules/settings/views/settings_view.dart b/lib/modules/settings/views/settings_view.dart index 195daf552..fb943bc36 100644 --- a/lib/modules/settings/views/settings_view.dart +++ b/lib/modules/settings/views/settings_view.dart @@ -858,7 +858,8 @@ class SettingsView extends GetView { ), InkWell( onTap: () { - // 在这里添加检查更新的逻辑 + // 调用检查更新方法 + controller.checkForUpdate(); }, child: Container( constraints: BoxConstraints( diff --git a/lib/modules/splash/controllers/splash_controller.dart b/lib/modules/splash/controllers/splash_controller.dart index e53f146dc..5bd7eb027 100644 --- a/lib/modules/splash/controllers/splash_controller.dart +++ b/lib/modules/splash/controllers/splash_controller.dart @@ -8,6 +8,8 @@ import '../../../data/models/user_Info.dart'; import '../../../routes/app_routes.dart'; import '../../../core/themes/theme_service.dart'; import '../../../data/services/network/api.dart'; +import '../../../data/services/version_update_service.dart'; +import '../../../modules/common/widgets/version_update_dialog.dart'; class SplashController extends GetxController { final GetStorage _storage = GetStorage(); @@ -73,6 +75,9 @@ class SplashController extends GetxController { // await _loadImages(); // await _initDatabase(); + // 检查版本更新(在后台进行,不阻塞启动流程) + _checkVersionUpdate(); + _isResourceLoaded.value = true; _checkNavigateCondition(); } catch (e) { @@ -151,4 +156,23 @@ class SplashController extends GetxController { return false; } } + + /// 检查版本更新(后台执行,不阻塞启动流程) + void _checkVersionUpdate() { + // 延迟执行版本检查,避免影响启动速度 + Timer(const Duration(seconds: 2), () async { + try { + final versionService = VersionUpdateService.to; + final updateInfo = await versionService.checkForUpdate(); + + if (updateInfo.hasUpdate) { + // 显示更新对话框 + await VersionUpdateDialog.show(updateInfo); + } + } catch (e) { + print('版本检查失败: $e'); + // 版本检查失败不影响用户使用,静默处理 + } + }); + } } diff --git a/pubspec.yaml b/pubspec.yaml index ccd4d7c49..ca1cc9712 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -57,6 +57,7 @@ dependencies: lottie: ^3.3.1 app_settings: 5.2.0 fluwx: ^5.4.1 + url_launcher: ^6.3.1 firebase_core: ^3.12.1 firebase_auth: ^5.5.1 google_sign_in: ^6.2.2