From 7fa2431a4a7bb3963090fec102c5d47c70c6c285 Mon Sep 17 00:00:00 2001 From: lafay <2021211506@stu.hit.edu.cn> Date: Wed, 17 Jun 2026 20:06:07 +0800 Subject: [PATCH] feat(api): enhance public APK endpoint to return semantic version from OTA bundle The PublicLatestAPK endpoint now reads the expoConfig.json from the OTA bundle to extract the actual semantic version (expo.version) instead of returning the runtimeVersion as the version name. Falls back to runtimeVersion if expoConfig.json is not available. --- internal/handlers/handlers.go | 11 ++++++++++- internal/service/update_service.go | 22 ++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index 081424a..d9086cc 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -300,9 +300,18 @@ func (h *Handler) PublicLatestAPK(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusNotFound, map[string]any{"error": "No APK available"}) return } + + // versionName 优先从同 runtimeVersion 的 OTA bundle 里读取 expoConfig.json + // (CI 在 publish OTA 时会把 expoConfig.json 打入 zip) + versionName := h.svc.GetAPKVersionName(apk.RuntimeVersion) + if versionName == "" { + // 兜底:没有 expoConfig 时退回 runtimeVersion(不应该发生,但保底) + versionName = apk.RuntimeVersion + } + resp := model.LatestAPKResponse{ RuntimeVersion: apk.RuntimeVersion, - VersionName: apk.RuntimeVersion, + VersionName: versionName, Size: apk.Size, DownloadURL: fmt.Sprintf("%s/api/apk/download?runtimeVersion=%s", h.svc.Hostname(), apk.RuntimeVersion), CreatedAt: apk.CreatedAt.Format(time.RFC3339), diff --git a/internal/service/update_service.go b/internal/service/update_service.go index 5ec7d3b..91e4ead 100644 --- a/internal/service/update_service.go +++ b/internal/service/update_service.go @@ -88,6 +88,28 @@ func (s *UpdateService) GetLatestAPK() (*model.APKInfo, error) { return s.store.GetLatestAPK() } +// GetAPKVersionName 返回 APK 对应 runtimeVersion 的 OTA bundle 中的语义版本号。 +// 读取路径://android/expoConfig.json -> expo.version +// 若 OTA bundle 尚未发布或 expoConfig.json 缺失,返回空字符串(调用方应兜底)。 +func (s *UpdateService) GetAPKVersionName(runtimeVersion string) string { + releasePath, err := s.store.LatestReleasePath(runtimeVersion, "android") + if err != nil { + return "" + } + cfg, err := s.store.ReadExpoConfig(releasePath) + if err != nil { + return "" + } + expo, ok := cfg["expo"].(map[string]any) + if !ok { + return "" + } + if v, ok := expo["version"].(string); ok { + return v + } + return "" +} + func (s *UpdateService) BuildManifestResponse(req ManifestRequest) (ManifestResponse, error) { releasePath, err := s.store.LatestReleasePath(req.RuntimeVersion, req.Platform) if err != nil {