import 'dart:developer' as developer; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../core/config/app_config.dart'; import '../core/network/dio_client.dart'; import '../data/models/version/app_version.dart'; import '../data/services/version_service.dart'; // SharedPreferences keys for cached version data const _kCachedLowestVersion = 'version_cached_lowest'; const _kCachedNewVersion = 'version_cached_new'; const _kCachedDownloadUrl = 'version_cached_download_url'; const _kCachedUpdateDesc = 'version_cached_update_desc'; /// 版本检查结果 class VersionCheckResult { final AppVersion version; final String currentVersion; final bool hasUpdate; final bool isForce; const VersionCheckResult({ required this.version, required this.currentVersion, this.hasUpdate = false, this.isForce = false, }); } /// 版本检查 Provider /// 返回 [VersionCheckResult],null 表示无需更新或检查失败 /// 网络失败时回退到本地缓存,防止关网绕过强制更新 final appVersionProvider = FutureProvider.autoDispose((ref) async { final currentVersion = AppConfig.appVersion; AppVersion? version; try { final dio = ref.read(dioClientProvider); version = await VersionService(dio).getLatestVersion(); developer.log( 'Version API response: newVersion=${version?.newVersion}, ' 'lowestVersion=${version?.lowestVersion}, ' 'downloadUrl=${version?.downloadUrl}', name: 'VersionCheck', ); if (version != null && version.newVersion.isNotEmpty) { // 成功后写入缓存,供断网时使用 final prefs = await SharedPreferences.getInstance(); await prefs.setString(_kCachedLowestVersion, version.lowestVersion); await prefs.setString(_kCachedNewVersion, version.newVersion); await prefs.setString(_kCachedDownloadUrl, version.downloadUrl); await prefs.setString(_kCachedUpdateDesc, version.updateDescription); } } catch (e, st) { developer.log( 'Version check failed, falling back to cache: $e', name: 'VersionCheck', error: e, stackTrace: st, ); // 网络失败时读缓存 try { final prefs = await SharedPreferences.getInstance(); final cachedLowest = prefs.getString(_kCachedLowestVersion) ?? ''; if (cachedLowest.isNotEmpty) { version = AppVersion( lowestVersion: cachedLowest, newVersion: prefs.getString(_kCachedNewVersion) ?? '', downloadUrl: prefs.getString(_kCachedDownloadUrl) ?? '', updateDescription: prefs.getString(_kCachedUpdateDesc) ?? '', ); developer.log( 'Using cached version: lowestVersion=$cachedLowest', name: 'VersionCheck', ); } } catch (_) {} } if (version == null || version.newVersion.isEmpty) { // 缓存也没有,只检查 lowestVersion(断网首次启动的兜底) if (version == null) return null; } final hasUpdate = version.hasNewVersion(currentVersion); final isForce = version.isForceUpdate(currentVersion); developer.log( 'Current=$currentVersion, latest=${version.newVersion}, ' 'hasUpdate=$hasUpdate, isForce=$isForce', name: 'VersionCheck', ); // 即使 newVersion 为空(纯缓存 lowestVersion 场景),只要需要强制更新也弹窗 if (!hasUpdate && !isForce) return null; return VersionCheckResult( version: version, currentVersion: currentVersion, hasUpdate: hasUpdate || isForce, isForce: isForce, ); });