diff --git a/packages/web_shell_core/lib/src/services/upgrade_service.dart b/packages/web_shell_core/lib/src/services/upgrade_service.dart index f232801..5526ab9 100644 --- a/packages/web_shell_core/lib/src/services/upgrade_service.dart +++ b/packages/web_shell_core/lib/src/services/upgrade_service.dart @@ -29,6 +29,7 @@ class ShellUpgradeReleaseConfig { ); } + /// 兼容已经解码好的 Map,或 `data.config.upgrade` 这种 JSON 字符串。 static ShellUpgradeReleaseConfig? fromDynamic(dynamic value) { if (value == null) { return null; @@ -67,7 +68,12 @@ class ShellUpgradeReleaseConfig { } } -/// 远程升级配置模型,对应顶层升级 JSON。 +/// 远程升级配置模型,对应升级接口的顶层 JSON。 +/// +/// 当前仅解析新接口结构: +/// 1. 顶层包含 `success/code/msg/data`; +/// 2. 升级与启动配置都放在 `data.config` 这个 JSON 字符串中; +/// 3. `data.config` 解开后,内部再拆为 `upgrade` 和 `config` 两部分。 class ShellUpgradeConfig { final bool? success; final String? responseCode; @@ -132,6 +138,10 @@ class ShellUpgradeConfig { bool get hasStructuredPayload => upgrade != null || config != null; + /// 仅使用远端 `upgrade.version` 与本地 buildNumber 做整数比较。 + /// + /// 返回 `true` 表示远端版本更高,需要触发升级提示; + /// 如果远端未下发版本号,则直接视为无需升级。 bool shouldOfferUpgrade({required int localVersion}) { final remoteVersion = upgrade?.version; if (remoteVersion == null) { @@ -140,6 +150,9 @@ class ShellUpgradeConfig { return remoteVersion > localVersion; } + /// 解析接口响应,并从 `data.config` 中拆出: + /// - `upgrade`:升级弹窗所需信息 + /// - `config`:启动期运行时配置,如 initialUrl / preferredOrientations factory ShellUpgradeConfig.fromJson(Map json) { final data = json['data']; final dataMap = data is Map @@ -227,6 +240,7 @@ bool? _readShellUpgradeBool(dynamic value) { return null; } +/// 解析 `data.config` 这个嵌套 JSON 字符串。 Map? _readShellUpgradeEmbeddedConfig(String? value) { if (value == null || value.isEmpty) { return null; @@ -255,11 +269,17 @@ class ShellUpgradeService { Future Function()? _localBuildNumberResolver; /// 注入升级配置地址。 + /// + /// 这里只保存升级接口 URL,不会立即发起网络请求。 void setupConfigUrl(String? configUrl) { _configUrl = configUrl?.trim(); } /// 检查应用版本,若配置中有更新则会弹出升级弹窗。 + /// + /// 这里仅负责“拉取升级配置 + 触发升级插件比较”。 + /// `initialUrl`、`preferredOrientations` 等运行时配置刷新, + /// 由 `core_app.dart` 中显式的 reload 方法单独处理。 Future checkVersion( BuildContext context, { bool showNoUpdateToast = false, @@ -292,11 +312,16 @@ class ShellUpgradeService { ShellUpgradeConfig remoteConfig, ) { return (int upType) async { + // 先把远端配置转换成升级插件需要的数据模型; + // 如果关键字段不完整,则直接中止本次升级检查。 final upgradeVersion = _convertToAppUpgradeVersion(remoteConfig); if (upgradeVersion == null) { return null; } + // 先用 WebShell 自己的版本比较逻辑做一次前置过滤, + // 避免远端版本不高时仍然进入插件弹窗流程。 + // 若本地 buildNumber 读取失败,则回退给升级插件做内部比较。 final localBuildNumber = await _resolveLocalBuildNumber(); if (localBuildNumber == null) { debugPrint('获取 WebShell 本地版本号失败,回退到升级插件内部版本比较'); @@ -312,6 +337,7 @@ class ShellUpgradeService { }; } + /// 优先使用测试注入的 resolver;否则回退到升级插件读取本地 buildNumber。 Future _resolveLocalBuildNumber() async { final resolver = _localBuildNumberResolver; if (resolver != null) { @@ -332,6 +358,7 @@ class ShellUpgradeService { _localBuildNumberResolver = resolver; } + /// 从升级接口拉取原始 JSON,并交给统一解析器处理。 Future _fetchConfig(String url) async { try { final uri = Uri.tryParse(url); @@ -352,6 +379,10 @@ class ShellUpgradeService { } } + /// 解析接口返回字符串。 + /// + /// 只有当响应中至少成功解析出 `upgrade` 或 `config` 任一结构时, + /// 才认为这是有效的升级配置。 ShellUpgradeConfig? _parseConfigString(String content) { try { final dynamic jsonMap = jsonDecode(content); @@ -372,6 +403,14 @@ class ShellUpgradeService { } /// 将远程 JSON 配置转换为升级弹窗所需的数据模型。 + /// + /// 这里会把: + /// - `upgrade.versionName` -> `versionName` + /// - `upgrade.version` -> `versionBuildNumber` + /// - `upgrade.isForce` -> `isForce` + /// - `describe/upgrade.remark` -> `updateContent` + /// - `installOssUrl/upgrade.filePath` -> 下载地址 + /// - `upgrade.fileSize`(KB) -> `apkSize`(Byte) AppUpgradeVersion? _convertToAppUpgradeVersion(ShellUpgradeConfig config) { if (config.version == null || config.versionName == null) { return null;