自托管应用分发平台,支持 iOS(IPA)与 Android(APK)。上传版本、按团队管理应用、上下架、下载分发,并提供 API Key 供 CI 流水线调用。
- 版本托管 — 上传 APK/IPA,设置当前版本、更新日志,按版本统计下载/安装次数与趋势图
- 单平台应用 — 每个应用固定
ios或android;全局(platform, appid)唯一,首次上传版本时锁定 appid - 上下架 — 应用级开关;仅上架应用的当前版本对外可见
- 访问控制 — 应用级访问模式(
public公开 /password密码),下载链接有效期与密码解耦,按日期粒度设置;凭据经查询参数随链接传递 - Webhook 通知 — 订阅「版本上传 / 设为当前 / 发布下架 / 到期」事件,模板化请求体推送(
{{.key}}占位符),支持未保存配置试推与推送日志 - 桌面二维码 — 电脑端访问应用详情页展示二维码,手机扫码直达下载
- 团队管理 — 应用成员决定谁能管理该应用;超管(配置于
config.json,uid = -1)管理一切 - API Key — 通过
?apikey=供 CI/脚本调用,支持run/read权限与有效期;key 的可用范围 = 创建人当前可管理的应用,实时生效 - 下载直链 — 链接主机名取自请求
Host头,反向代理部署时返回真实外部域名 - 双语界面 — 中文 / 英文,按浏览器语言自动切换
| 层 | 技术 |
|---|---|
| 前端 | Vue 3 + Vite + TypeScript + Tailwind CSS v4 + shadcn-vue |
| 后端 | Go,标准库 HTTP(mux.HandleFunc("METHOD /path")) |
| 存储 | GORM + SQLite(纯 Go,无 CGO) |
| 文件 | 本地目录、腾讯云 COS 或 Oracle 对象存储(S3 兼容) |
| 前端图床 | qrcode(桌面端二维码生成) |
| 认证 | JWT(golang-jwt),超管由配置定义 |
frontend/ Vue 3 + Vite + TS + Tailwind v4 + shadcn-vue
backend/
main.go 入口:组装 config/DB/storage/service
internal/
controller/ HTTP 处理器(薄:解析 → 调 service → 写 JSON)
service/ 业务逻辑(DB/存储/校验)
router/ Routes + 静态文件
resources/ config · store/{db,model} · storage/{local,cos,oci}
static/ 可选 —— 加 `-tags dist` 才内嵌前端 dist
.github/workflows/release.yml tag 推送 → 跨平台编译并发布 GitHub Release
公开下载页(无需登录,首页 / 为空白占位;通过应用详情直链访问):
公开应用详情页(桌面端附带二维码):
管理后台(应用列表):
API Key 管理:
更多截图见 docs/screenshots/:登录页、应用详情、用户管理、API 参考文档等。
# 前端构建
cd frontend && npm install && npm run build
# 后端构建 + 测试(默认不内嵌前端;`-tags dist` 才内嵌)
cd backend && go build -o ../bin/disapp . && go test ./...
# 重置本地数据库(仅开发)
make reset两个终端:
cd backend && APP_CONFIG=../config.json go run . # :8080
cd frontend && npm run dev # :5173 → 代理 /api → :8080访问 http://localhost:5173。前端使用 hash 路由,任意 SPA 路径可直接访问。
全部配置在 JSON 文件(APP_CONFIG 指定,默认 ./config.json):
admin块留空则运行时不带超管(此时所有管理端接口不可用)。超管从不写入数据库。
无迁移机制 — GORM 启动时自动建表。schema 变更后需重建(仅开发):make reset。
- 每个应用
access_mode:public(公开下载)或password(需密码访问) - 下载链接有效期与是否设密码解耦:可设
expires_at(日期粒度),过期后详情返回「应用不存在」 - 链接中的密码、token 经查询参数传递,复制/转发即可分发
| 角色 | 说明 |
|---|---|
| 超管 | 来自 config.json 的 admin 块,JWT uid = -1。可管理所有应用、所有用户、所有 API Key(可见创建人) |
| 应用成员 | 被加入某应用 members 的用户可管理该应用(上传版本、编辑、设置当前版本) |
| 普通用户 | 可创建应用,管理自己应用的成员与 key |
在「API Keys」页面创建,通过 ?apikey= 查询参数认证,无需 JWT。
上传新版本(两段式)——先取上传票据,推送文件字节,再创建版本记录:
# 1) 预签名:获取 {key, url}
curl -X POST "https://your-host/api/v1/keys/123/files?apikey=dk_xxxx" \
-H "Content-Type: application/json" -d '{"file_name":"app.apk"}'
# 2) 将文件字节推送到返回的 url(COS 为 PUT,local 为 /files/upload)
curl -X PUT "…返回的 url…" --data-binary "@app.apk"
# 3) 创建版本(携带 key / file_size / sha256)
curl -X POST "https://your-host/api/v1/keys/123/versions?apikey=dk_xxxx" \
-H "Content-Type: application/json" \
-d '{"key":"distapp/123/0/…","file_name":"app.apk","file_size":1048576,"sha256":"…","version_name":"1.0.0","version_code":1}'- 权限:
run(上传版本、设置当前、预签名)或read(仅查询/下载) - 有效期:可选预设(永久 / 1 天 / 3 天 / 7 天 / 1 个月 / 6 个月 / 1 年)
- 范围:key 等同于创建人身份,可管理的应用实时解析
- 可见性:key 仅创建人可见;超管可见全部
端点(id 为数字 ID,appid 为包名/bundle 标识):
| 方法 | 路径 | 权限 |
|---|---|---|
| POST | /api/v1/keys/{id}/files |
run(获取上传票据) |
| POST | /api/v1/keys/{id}/versions |
run(创建新版本) |
| POST | /api/v1/keys/{id}/current |
run(设置当前版本) |
| GET | /api/v1/keys/{id}/versions |
run / read |
| GET | /api/v1/keys/{id}/current |
run / read |
| GET | /api/v1/keys/{id}/current/download |
run / read(下载直链) |
完整参考(参数、响应示例)见界面「API Keys → API Reference」。
在「订阅」页创建机器人:绑定应用、选择请求方法(POST/GET/PUT)、URL、请求头、事件与请求体模板。请求体支持 {{.key}} 占位符替换:
| 参数 | 说明 |
|---|---|
event / event_key |
事件中文名 / 原始键(version_uploaded、version_current、app_publish、app_expire) |
app_id / app_name |
应用 ID / 名称 |
version_id / version_name / version_code |
版本信息(上传相关事件) |
file_name / file_size |
文件信息 |
published / expires_at |
上下架状态 / 到期时间 |
time |
事件时间 |
- 试推 — 编辑弹窗可对未保存配置发送测试请求,也支持批量重试
- 日志 — 每次发送记录的 URL、请求体、状态码与错误
- 到期扫描 — 后台轮询应用到期,首次触发
app_expire推送(以日志去重,重启不重复触发)
下载接口返回绝对 URL,主机名取自请求 Host 头(回退 X-Forwarded-Host)。反向代理必须透传真实外部域名,例如 nginx:
location / {
proxy_set_header Host $host; # 真实外部域名
proxy_set_header X-Forwarded-For $remote_addr;
proxy_pass http://127.0.0.1:8080;
}推送 v* tag 触发 .github/workflows/release.yml:构建前端 → 嵌入 → 后端交叉编译
linux/amd64、linux/arm64、darwin/amd64、darwin/arm64,并把二进制 + sha256
校验和附到 GitHub Release:
git tag v1.0.0
git push origin v1.0.0单二进制同时提供 API 与打包的 SPA:
APP_CONFIG=/etc/disapp/config.json ./bin/disapp &其他语言:English




{ "server": { "addr": ":8080" }, "database":{ "dsn": "./data/app.db" }, "storage": { "backend": "local" /* 或 "cos" / "oci" */, "local": { "dir": "./data/files" }, "cos": { "secret_id": "...", "secret_key": "...", "bucket": "app-dist-1250000000", "region": "ap-guangzhou", "base_url": "..." }, "oci": { "access_key": "...", "secret_key": "...", "bucket": "app-dist", "namespace": "...", "region": "ap-singapore-1", "base_url": "..." } }, "jwt": { "secret": "change-me", "expire": "24h" }, "admin": { "username": "admin", "password": "admin123" } }