| | |
| | | @Transactional |
| | | public AppVersionDetailVO create(AppVersionCreateRequest request) { |
| | | AppVersionConfig latest = latest(); |
| | | String androidFileUrl = normalizeOptionalText(request.getAndroidFileUrl()); |
| | | String androidFileName = normalizeOptionalText(request.getAndroidFileName()); |
| | | String iosFileUrl = normalizeOptionalText(request.getIosFileUrl()); |
| | | String iosFileName = normalizeOptionalText(request.getIosFileName()); |
| | | validatePackageFields(androidFileUrl, androidFileName, iosFileUrl, iosFileName); |
| | | AppVersionConfig item = new AppVersionConfig(); |
| | | item.setVersionNo(request.getVersionNo().trim()); |
| | | item.setVersionCode(latest == null ? 1 : defaultNumber(latest.getVersionCode()) + 1); |
| | | item.setAndroidFileUrl(request.getAndroidFileUrl().trim()); |
| | | item.setAndroidFileName(request.getAndroidFileName().trim()); |
| | | item.setIosFileUrl(request.getIosFileUrl().trim()); |
| | | item.setIosFileName(request.getIosFileName().trim()); |
| | | item.setAndroidFileUrl(androidFileUrl); |
| | | item.setAndroidFileName(androidFileName); |
| | | item.setIosFileUrl(iosFileUrl); |
| | | item.setIosFileName(iosFileName); |
| | | item.setForceUpdate(booleanToInteger(request.getForceUpdate())); |
| | | item.setUpdateNotice(request.getUpdateNotice().trim()); |
| | | item.setDeleted(0); |
| | |
| | | } |
| | | |
| | | public AppVersionCheckVO checkUpdate(String platform, Integer currentVersionCode) { |
| | | return checkUpdate(platform, currentVersionCode, null); |
| | | } |
| | | |
| | | public AppVersionCheckVO checkUpdate(String platform, Integer currentVersionCode, String currentVersionNo) { |
| | | if (currentVersionCode == null) { |
| | | throw new IllegalArgumentException("当前版本号不能为空"); |
| | | } |
| | |
| | | return vo; |
| | | } |
| | | |
| | | boolean hasUpdate = defaultNumber(latest.getVersionCode()) > currentVersionCode; |
| | | String downloadUrl = AppVersionConfig.PLATFORM_ANDROID.equals(normalizedPlatform) |
| | | ? normalizeOptionalText(latest.getAndroidFileUrl()) |
| | | : normalizeOptionalText(latest.getIosFileUrl()); |
| | | boolean hasUpdate = downloadUrl != null && isNewerVersion(latest, currentVersionCode, currentVersionNo); |
| | | vo.setHasUpdate(hasUpdate); |
| | | if (!hasUpdate) { |
| | | return vo; |
| | | } |
| | | vo.setLatestVersionNo(latest.getVersionNo()); |
| | | vo.setLatestVersionCode(defaultNumber(latest.getVersionCode())); |
| | | vo.setForceUpdate(integerToBoolean(latest.getForceUpdate())); |
| | | vo.setUpdateNotice(latest.getUpdateNotice()); |
| | | vo.setDownloadUrl(AppVersionConfig.PLATFORM_ANDROID.equals(normalizedPlatform) |
| | | ? latest.getAndroidFileUrl() |
| | | : latest.getIosFileUrl()); |
| | | vo.setDownloadUrl(downloadUrl); |
| | | return vo; |
| | | } |
| | | |
| | | public AppVersionCheckVO checkUpdateNew(String platform) { |
| | | |
| | | String normalizedPlatform = normalizePlatform(platform); |
| | | AppVersionConfig latest = latest(); |
| | | AppVersionCheckVO vo = new AppVersionCheckVO(); |
| | | if (latest == null) { |
| | | vo.setHasUpdate(Boolean.FALSE); |
| | | return vo; |
| | | } |
| | | |
| | | String downloadUrl = AppVersionConfig.PLATFORM_ANDROID.equals(normalizedPlatform) |
| | | ? normalizeOptionalText(latest.getAndroidFileUrl()) |
| | | : normalizeOptionalText(latest.getIosFileUrl()); |
| | | boolean hasUpdate = downloadUrl != null; |
| | | vo.setHasUpdate(hasUpdate); |
| | | if (!hasUpdate) { |
| | | return vo; |
| | | } |
| | | vo.setLatestVersionNo(latest.getVersionNo()); |
| | | vo.setLatestVersionCode(defaultNumber(latest.getVersionCode())); |
| | | vo.setForceUpdate(integerToBoolean(latest.getForceUpdate())); |
| | | vo.setUpdateNotice(latest.getUpdateNotice()); |
| | | vo.setDownloadUrl(downloadUrl); |
| | | return vo; |
| | | } |
| | | |
| | | /** |
| | | * 判断后台最新版本是否高于当前 APP,兼容原生 versionCode 与展示 versionNo 不一致的历史包。 |
| | | */ |
| | | private boolean isNewerVersion(AppVersionConfig latest, Integer currentVersionCode, String currentVersionNo) { |
| | | if (defaultNumber(latest.getVersionCode()) > currentVersionCode) { |
| | | return true; |
| | | } |
| | | return compareVersionNo(latest.getVersionNo(), currentVersionNo) > 0; |
| | | } |
| | | |
| | | /** |
| | | * 比较数字点号版本号,无法解析的版本号不参与兜底判断。 |
| | | */ |
| | | private int compareVersionNo(String latestVersionNo, String currentVersionNo) { |
| | | String latest = normalizeOptionalText(latestVersionNo); |
| | | String current = normalizeOptionalText(currentVersionNo); |
| | | if (latest == null || current == null) { |
| | | return 0; |
| | | } |
| | | String[] latestParts = latest.split("\\."); |
| | | String[] currentParts = current.split("\\."); |
| | | int maxLength = Math.max(latestParts.length, currentParts.length); |
| | | for (int i = 0; i < maxLength; i++) { |
| | | Integer latestNumber = parseVersionNumber(latestParts, i); |
| | | Integer currentNumber = parseVersionNumber(currentParts, i); |
| | | if (latestNumber == null || currentNumber == null) { |
| | | return 0; |
| | | } |
| | | int compareResult = latestNumber.compareTo(currentNumber); |
| | | if (compareResult != 0) { |
| | | return compareResult; |
| | | } |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | /** |
| | | * 解析指定版本号片段,缺失片段按 0 处理。 |
| | | */ |
| | | private Integer parseVersionNumber(String[] parts, int index) { |
| | | if (index >= parts.length) { |
| | | return 0; |
| | | } |
| | | String value = parts[index] == null ? "" : parts[index].trim(); |
| | | if (!value.matches("\\d+")) { |
| | | return null; |
| | | } |
| | | try { |
| | | return Integer.valueOf(value); |
| | | } catch (NumberFormatException ex) { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | private AppVersionConfig latest() { |
| | |
| | | private Boolean integerToBoolean(Integer value) { |
| | | return value != null && value == 1; |
| | | } |
| | | |
| | | private void validatePackageFields(String androidFileUrl, String androidFileName, String iosFileUrl, String iosFileName) { |
| | | boolean hasAndroidFileUrl = androidFileUrl != null; |
| | | boolean hasAndroidFileName = androidFileName != null; |
| | | boolean hasIosFileUrl = iosFileUrl != null; |
| | | boolean hasIosFileName = iosFileName != null; |
| | | boolean hasAndroidPackage = hasAndroidFileUrl || hasAndroidFileName; |
| | | boolean hasIosPackage = hasIosFileUrl || hasIosFileName; |
| | | |
| | | if (hasAndroidPackage && (!hasAndroidFileUrl || !hasAndroidFileName)) { |
| | | throw new IllegalArgumentException("安卓文件地址和名称必须同时填写"); |
| | | } |
| | | if (hasIosPackage && (!hasIosFileUrl || !hasIosFileName)) { |
| | | throw new IllegalArgumentException("iOS文件地址和名称必须同时填写"); |
| | | } |
| | | if (!hasAndroidPackage && !hasIosPackage) { |
| | | throw new IllegalArgumentException("请至少上传一个安装包"); |
| | | } |
| | | } |
| | | |
| | | private String normalizeOptionalText(String value) { |
| | | if (value == null) { |
| | | return null; |
| | | } |
| | | String trimmed = value.trim(); |
| | | return trimmed.isEmpty() ? null : trimmed; |
| | | } |
| | | } |