7fa2431a4a7bb3963090fec102c5d47c70c6c285
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.
Expo Updates Server (Go)
这个目录是 expo-updates-server 的 Go 版本实现,目标是:
- 保持客户端接口兼容:
GET /api/manifest、GET /api/assets - 增加便于上传和 CI 的管理接口:
/admin/publish、/admin/rollback、/admin/releases
运行
cd expo-updates-server-go
go run ./cmd/server
默认监听 :3001,可通过环境变量覆盖:
PORT:默认3001HOSTNAME:默认http://localhost:3001,用于拼接 assets URLUPDATES_ROOT:默认updatesPRIVATE_KEY_PATH:可选;若客户端请求expo-expect-signature,必须配置ADMIN_TOKEN:管理接口 Bearer Token
示例(复用现有 expo-updates-server/updates):
cd expo-updates-server-go
PORT=3001 \
HOSTNAME=http://localhost:3001 \
UPDATES_ROOT=../expo-updates-server/updates \
PRIVATE_KEY_PATH=../expo-updates-server/code-signing-keys/private-key.pem \
ADMIN_TOKEN=dev-token \
go run ./cmd/server
生产环境建议将 HOSTNAME 配置为:
https://updates.littlelan.cn
兼容接口
GET /api/manifest- 支持
expo-platform、expo-runtime-version、expo-protocol-version - 支持
rollBackToEmbedded、noUpdateAvailable - 支持
expo-expect-signature
- 支持
GET /api/assets?asset=...&runtimeVersion=...&platform=...
APK 管理接口(公开)
获取最新 APK 版本信息
GET /api/apk/latest
返回最新 APK 的版本信息,用于客户端检查更新。
{
"runtimeVersion": "1.0.11",
"versionName": "1.0.11",
"size": 52428800,
"downloadUrl": "https://updates.littlelan.cn/api/apk/download?runtimeVersion=1.0.11",
"createdAt": "2026-03-26T00:00:00Z"
}
下载 APK
GET /api/apk/download?runtimeVersion=<runtimeVersion>
下载指定版本的 APK 文件。
管理接口(上传/CI)
1) 发布 zip
POST /admin/publish?runtimeVersion=<rv>&platform=<ios|android>
- Header:
Authorization: Bearer <ADMIN_TOKEN> - Body:
expo export产物 zip(zip 根目录需包含metadata.json)
curl -X POST \
"https://updates.littlelan.cn/admin/publish?runtimeVersion=2&platform=ios" \
-H "Authorization: Bearer dev-token" \
-H "Content-Type: application/zip" \
--data-binary @dist.zip
2) 创建回滚标记
POST /admin/rollback
curl -X POST "https://updates.littlelan.cn/admin/rollback" \
-H "Authorization: Bearer dev-token" \
-H "Content-Type: application/json" \
-d '{"runtimeVersion":"2","platform":"ios"}'
3) 查看发布列表
GET /admin/releases?runtimeVersion=2
curl "https://updates.littlelan.cn/admin/releases?runtimeVersion=2" \
-H "Authorization: Bearer dev-token"
4) 上传 APK
POST /admin/apk/upload?runtimeVersion=<runtimeVersion>
- Header:
Authorization: Bearer <ADMIN_TOKEN> - Content-Type:
application/vnd.android.package-archive或application/octet-stream - Body:APK 二进制文件
curl -X POST \
"https://updates.littlelan.cn/admin/apk/upload?runtimeVersion=1.0.11" \
-H "Authorization: Bearer dev-token" \
-H "Content-Type: application/vnd.android.package-archive" \
--data-binary @app-release.apk
CI 示例思路
- 在客户端跑
npx expo export - 打包
dist为 zip - 调用
/admin/publish
可直接参考根目录新增工作流:.github/workflows/go-updates-server-ci.yml
CI/CD
项目使用 Gitea Actions 进行持续集成和部署:
Build Workflow (.gitea/workflows/build.yml)
- 触发条件:push 到 master/main 分支,或 PR
- 步骤:
- 编译 Go 二进制文件
- 构建 Docker 镜像
- 推送到私有镜像仓库
code.littlelan.cn/carrot_bbs/updates-server
Deploy Workflow (.gitea/workflows/deploy.yml)
- 触发条件:PR 合并到 master/main,或手动触发
- 步骤:
- SSH 到服务器
- 拉取最新镜像
- 重启容器
所需 Secrets
GIT_USERNAME- Gitea 用户名GIT_TOKEN- Gitea Token(用于推送镜像)SERVER_PASSWORD- 服务器 SSH 密码UPDATES_ADMIN_TOKEN- 管理接口 Token
Docker 打包与运行
1) 构建镜像并导出 tar
在 expo-updates-server-go 目录执行:
./build-docker-tar.sh
可指定 tag:
./build-docker-tar.sh 20260309-ota
执行后会生成:
- 镜像:
carrot-bbs-updates-server:<tag> - tar:
carrot-bbs-updates-server-<tag>.tar
2) 运行容器(挂载更新目录和密钥)
docker run -d \
--name carrot-bbs-updates-server \
-p 3001:3001 \
-e PORT=3001 \
-e HOSTNAME=https://updates.littlelan.cn \
-e UPDATES_ROOT=/data/updates \
-e PRIVATE_KEY_PATH=/data/privatekey.pem \
-e ADMIN_TOKEN=dev-token \
-v /opt/carrot-bbs/updates:/data/updates \
-v /opt/carrot-bbs/keys/privatekey.pem:/data/privatekey.pem:ro \
carrot-bbs-updates-server:latest
Description
Languages
Go
97%
Shell
1.9%
Dockerfile
1.1%