面向已在国内应用商店通过审核的 Android 应用,提供本地可视化多渠道状态观察与更新发布。
它不是只记录“由本工具发出的版本”。只要纳管包名并绑定渠道,就能查询平台后台、 其他 CI 或人工发布形成的最新审核/上架状态;上传 APK 则是另一条独立的发布执行链路。
一次发布可以上传一个或多个同版本、同签名生产 APK。普通渠道明确选择一个制品, 小米和应用宝可分别选择两个 APK:
应用身份锁定 → APK 一致性校验 → 渠道制品映射 → 账号预检 → 并发传包 → 提交审核 → 查询审核
- Vue 3 + Element Plus 本地发布控制台
- “应用 × 渠道”状态矩阵,不依赖本地发布单或 APK
- SQLite 持久化应用、渠道绑定、最新快照、历史观察和调度租约
- 后台低频自动观察、立即同步、失败退避、陈旧数据标识
- 华为、荣耀、小米、OPPO、vivo、应用宝、Samsung、Google Play 八个独立 Provider
- APK 包名、versionCode、versionName、SHA-256 和签名证书校验
- 多渠道并发、失败分类、有限重试、发布单恢复;中断时禁止盲目重复提交
- 平台外部任务 ID、审核证据、事件时间线和发布历史
- 每个 App 独立的 macOS 钥匙串凭据;发布单、SQLite 和浏览器不保存密钥
- CLI 与 Web 共用同一个
ReleaseService - 小米审核/在架状态不可查询、应用宝在架版本不可查询时的明确降级入口
- OPPO/vivo 新审核版本与已知线上版本并行展示
环境要求:
- Node.js 22+
- Android SDK
apkanalyzer - Android SDK
apksigner - macOS(可视化凭据持久化使用系统钥匙串)
首次启动:
cd /path/to/android-store-ops
npm install
npm run build
npm start浏览器打开:
http://127.0.0.1:8787
控制台包含三个全局页面和每个 App 内的三个业务子页面:
- 应用管理:
http://127.0.0.1:8787/applications - 所有发布:
http://127.0.0.1:8787/releases - 渠道概览(只读):
http://127.0.0.1:8787/channels - App 状态:
/applications/:applicationId/status - App 发布:
/applications/:applicationId/releases - App 渠道配置:
/applications/:applicationId/channels
选择应用或发布单后,页面会把对应 ID 写入 URL,复制链接或刷新不会丢失当前上下文。
日常前端开发:
npm run dev开发页面是 http://127.0.0.1:5173,API 是 http://127.0.0.1:8787。
控制台只允许绑定本机回环地址,避免 APK 和平台凭据暴露到局域网。
- 创建 App 工作区,填写应用名、所属主体和包名。
- 进入该 App 的“渠道配置”,逐个平台保存专属于该 App 的凭据和远端 App ID。
- 逐渠道执行只读验证;只有验证通过的渠道会进入自动观察和正式发布。
- 点击“立即同步全部渠道”,或开启“自动观察”让后台按低频计划查询。
- 在同一张矩阵中分别查看在审版本、线上版本、与目标版本的关系和数据新鲜度。
查询失败不会抹掉最后一次成功快照。页面同时保留最后错误和最后成功时间,避免把 “接口暂时失败”误显示成“应用没有上架”。状态观察不要求先上传 APK,也不要求版本由 本工具提交。
- 从 App 工作区点击“创建发布”,当前 App 全程锁定。
- 上传一个或多个生产 APK;系统校验包名、版本和证书指纹完全一致。
- 只选择当前 App 已验证的渠道;普通渠道选择一个 APK,小米和应用宝可选择主 APK 和第二 APK,小米还需要 PNG 图标。
- 填写版本说明、可选的定时上架时间。
- 明确确认 APK 使用已上架应用的生产签名。
- 创建发布单后,系统先执行只读渠道预检。
- 检查通过后点击“上传并提审”。
- 用“查询状态”刷新本次发布单;应用矩阵继续独立观察平台最新现状。
小米官方没有开放审核中、驳回或当前在架版本查询接口。/dev/query 只展示应用包信息,
页面不会再把它标成“已上架”,并保留“确认上架/确认驳回”的人工闭环入口。
每个 App、每个平台只有一套完整凭据。运行时必须使用
applicationId + provider 解析,缺失时直接失败;不会回退到其他 App、旧全局 Keychain
条目或无归属环境变量。华为/荣耀 App ID 属于当前 App 的渠道绑定,不属于全局账号。
当前 App 的渠道配置页会直接显示钥匙串中已保存的完整值,便于核对和修改;这些值不会进入
应用列表、渠道总览、发布单、日志或浏览器 localStorage。
凭据按 App 和平台隔离保存在 macOS Keychain 中,内部 service 名称不是公共接口,无需手工 创建或读取。新增或修改凭据后,必须在当前 App 的渠道配置页逐渠道执行只读验证。
Web 和 CLI 使用同一份 store-ops.json。
# 创建发布单并校验 APK
node src/cli.js create \
--config store-ops.json \
--manifest release.local.json
# 只读渠道预检
node src/cli.js preflight <release-id> --config store-ops.json
# 正式上传并提交审核
node src/cli.js submit <release-id> --config store-ops.json
# 查询一次状态
node src/cli.js status <release-id> --config store-ops.json清单必须包含 applicationId;多 APK 时通过 channelArtifacts 显式映射。示例见
examples/release.example.json。
默认轮询间隔是 3 小时,以符合荣耀官方的审核状态查询频率建议。不要用秒级定时任务 持续请求应用商店;Web 页面的实时刷新只读取本地状态,不会自动高频调用商店接口。
状态机:
pending
└─ preflighted
└─ submitting
├─ submission_uncertain
├─ reviewing
│ ├─ approved
│ │ └─ released
│ └─ rejected
└─ failed
页面同时显示状态证据:
精确审核单:荣耀使用本次提交返回的releaseId查询。平台状态:华为直接返回在架版本;荣耀同时查询当前审核版本和在架版本;OPPO/vivo 读取最新审核版本及平台上下架字段。指定版本复核/上次结果:OPPO可按已知 versionCode 复核旧线上版本;首次遇到“另有版本 上架”时只额外验证紧邻的前一 versionCode,验证失败就保持版本未知。vivo在新版本审核时 保留上次已经确认的线上快照,并明确标识来源。状态不可用:小米/dev/query的包信息不能证明审核或上架结果。人工确认:平台 API 无法证明最终结果时,由操作人补齐证据。
approved 和 released 不合并。审核通过不等于目标版本已经对用户可见。
submission_uncertain 表示进程在平台响应写回本地前中断。系统不会自动重传,以免平台
已经成功收包时产生重复提交;操作人应先查询平台状态,再决定后续处理。
- 服务端只监听
127.0.0.1。 - 商店密钥按 App + Provider 存入 macOS 钥匙串。
- 凭据只在 Provider 子进程启动时临时转换为环境变量。
- Provider 子进程会清除继承环境里的全部渠道密钥,只注入本次 App、当前平台的字段。
- 发布单不保存 client secret、私钥、审核测试账号或证书原文。
- APK 创建发布单时固定文件 SHA-256 和签名证书 SHA-256。
- 正式提交前再次解析 APK,检测文件是否被替换。
- Provider stdout 是严格 JSON 协议;诊断信息不能混入协议输出。
运行状态保存在:
.android-store-ops/state/<release-id>.json
.android-store-ops/observations.sqlite
前者保存发布执行状态;后者保存应用、渠道绑定、当前快照、历史观察和后台调度租约。 服务重启后不会从历史发布单或其他 App 自动补渠道;新 App 始终从全部已注册渠道未配置开始。
上传到本地控制台的文件保存在:
.android-store-ops/uploads/<upload-id>/
npm run check
npm test
npm run build
npm auditProvider 测试使用本地模拟官方端点,不会连接真实商店或提交真实应用。上线使用前仍需用 各平台真实账号完成一次下一正式版本验证,尤其要核对账号权限、平台返回错误码和审核结果。 本地契约测试通过不代表真实账号已经跑通;正式使用前必须逐渠道执行只读验证。
本项目采用 Apache License 2.0 开源许可证。