外观
CLI / API 参考
foxstore-cli 是 Fox Store 面向 CI/CD 的无交互发布 API。这里的 API 指命令行进程接口(参数、文件、stdout/stderr 和退出码),不提供 HTTP 服务。它是静态链接 foxstore-engine 的单一可执行文件,不要求安装或启动桌面客户端,也不读取桌面端 SQLite 凭据。
CLI 当前覆盖 Apple、Google Play、华为、微信小程序、腾讯应用宝、荣耀、Samsung、蒲公英、vivo、小米和 OPPO 的发布自动化。对象存储、评论、Analytics、证书日常管理、图片优化与 AI 应用体检保留在 Engine 和 Desktop,不进入 CLI。
从 CI/CD 接入指南 开始接入 GitHub Actions、GitLab CI 或 Jenkins,再按本页查参数。
全局调用格式
text
foxstore-cli [--output human|json|ndjson] <command>| 参数 | 默认值 | 说明 |
|---|---|---|
--output | human | human 供终端阅读;json 输出单个结构化结果;ndjson 输出一条紧凑的最终结果,当前不输出实时进度事件。该参数可放在子命令前后。 |
--help | - | 查看当前命令的实时帮助。 |
--version | - | 查看二进制版本。 |
--help / -h 始终输出帮助文本;--version / -V 始终输出版本文本,即使指定机器格式也不包 envelope。需要机器版本信息时用 version --output json。
下文类型:string 是字符串(ID 保留字符串类型),path 是 Runner 本机路径,i64 / i32 是有符号整数,u64 / u8 是非负整数,f64 是浮点数。标注“可选”表示可省略且无默认值;布尔“开关”只写参数名,布尔“值”必须跟 true 或 false。所有发布和状态命令均继承对应 Provider 的凭据参数。
基础命令:
bash
foxstore-cli version
foxstore-cli providers --output json
foxstore-cli capabilities --provider apple --output json
foxstore-cli artifact inspect --file ./build/App.ipa --output json
foxstore-cli preflight apple --file ./build/App.ipa --output json
foxstore-cli preflight android --file ./build/App.aab --expected-package-name com.example.app --output json
foxstore-cli preflight huawei --file ./build/App.app --output json| 命令 | 参数 | 结果 |
|---|---|---|
version | 无 | 返回 version 和 engineSchemaVersion。 |
providers | 无 | 返回编译进当前二进制的 Provider 与可用状态。 |
capabilities | 必填 --provider <string> | 返回 Provider 描述、cliPublish 与排除能力,不是逐命令 schema。 |
artifact inspect | 必填 --file <path> | 识别发布产物类型、大小与 SHA-256。 |
preflight apple | 必填 --file <path> | 执行 Apple IPA 预检。 |
preflight android | 必填 --file <path>;可选 --expected-package-name <string> | 执行 Android 包体预检并可核对包名。 |
preflight huawei | 必填 --file <path> | 仅分析 HarmonyOS .app;华为 APK/AAB 使用 preflight android。 |
providers 会列出全部 15 个静态 Provider;对象存储项的 cliPublish 为 excluded。capabilities --provider 接收 ID:apple、google-play、huawei-appgallery、wechat-miniprogram、tencent-appstore、honor、samsung-galaxy-store、pgyer、vivo、xiaomi、oppo、aliyun、tencent-cloud、aws、minio。注意华为和 Samsung 的子命令分别写 huawei、samsung,不是目录 ID。
artifact inspect 只识别类型、大小和 SHA-256,不验证签名。preflight 是本地分析,不发起发布;Apple 即使返回成功 envelope / 退出 0,data.status 仍可能是 blocked,必须检查 data.status == "ready" 和 data.checks[].blocksUpload。Android 的 warnings 也需要按团队策略处理。publish apple 会再次预检并阻止 blocked 包体;预检通过不代表商店已接受。
凭据来源
Secret 不能直接作为普通命令行参数传入。*-env 接收的是环境变量名,*-file 接收的是 CI 创建的临时文件路径;同一 Secret 的两者互斥,所有 *-env 为可选 string、*-file 为可选 path。未显式指定时,CLI 使用下表默认环境变量。
| Provider | 默认环境变量 | 可替换参数 |
|---|---|---|
| Apple | APPLE_PRIVATE_KEY | --private-key-env / --private-key-file;Issuer ID 与 Key ID 分别用 --issuer-id、--key-id |
| Google Play | GOOGLE_PLAY_CREDENTIALS_JSON | --credentials-env / --credentials-file |
| Huawei HarmonyOS | HUAWEI_SERVICE_ACCOUNT_JSON | --service-account-env / --service-account-file |
| Huawei Android | HUAWEI_ANDROID_API_CLIENT_JSON | --android-api-client-env / --android-api-client-file |
| 微信小程序 | WECHAT_MINIPROGRAM_PRIVATE_KEY | --private-key-env / --private-key-file |
| 腾讯应用宝 | TENCENT_APPSTORE_USER_ID、TENCENT_APPSTORE_ACCESS_SECRET | --user-id-env / --user-id-file、--access-secret-env / --access-secret-file |
| 荣耀 | HONOR_CLIENT_ID、HONOR_API_SECRET | --client-id-env / --client-id-file、--api-secret-env / --api-secret-file |
| Samsung | SAMSUNG_CREDENTIALS_JSON | --credentials-env / --credentials-file |
| 蒲公英 | PGYER_API_KEY、PGYER_USER_KEY | --api-key-env / --api-key-file、--user-key-env / --user-key-file |
| vivo | VIVO_ACCESS_KEY、VIVO_ACCESS_SECRET | --access-key-env / --access-key-file、--access-secret-env / --access-secret-file |
| 小米 | XIAOMI_USER_NAME、XIAOMI_API_SECRET、XIAOMI_PUBLIC_CERTIFICATE | --user-name-env / --user-name-file、--api-secret-env / --api-secret-file、--public-certificate-env / --public-certificate-file |
| OPPO | OPPO_CLIENT_ID、OPPO_CLIENT_SECRET | --client-id-env / --client-id-file、--client-secret-env / --client-secret-file |
Apple 的 --issuer-id、--key-id 在 doctor/publish/status 都是必填 string。JSON 凭据传入完整文档内容,不是 JSON 文件路径字符串;Google/Huawei 使用各平台导出的凭据 JSON,Samsung 使用 { "serviceAccountId": "…", "privateKey": "…", "accessToken": null }(前两项必填 string,accessToken 可选 string)。私钥保留 PEM 换行;不要将实际 Secret 写进命令行、仓库或日志。
各凭据 JSON 的字段沿用导出格式,不要统一转成 camelCase:
| 凭据 | 文档字段(均为 string,除注明外必填) |
|---|---|
| Google Play | type 固定 service_account、project_id、private_key_id、private_key、client_email、token_uri。 |
| Huawei Service Account | key_id、private_key、sub_account、auth_uri、token_uri、auth_provider_cert_uri、client_cert_uri;project_id 可选。 |
| Huawei Android API Client | client_id、client_secret。 |
| Samsung | serviceAccountId、privateKey;accessToken 可选。 |
CLI 不会自动读取名为 *_FILE 的环境变量;必须显式写 --private-key-file "$APPLE_KEY_FILE" 等参数。华为的四个来源参数全部互斥:doctor/status 未指定时选择 HarmonyOS Service Account;Android 必须显式选择 --android-api-client-env HUAWEI_ANDROID_API_CLIENT_JSON 或 --android-api-client-file <path>。publish 按 .app / .apk|.aab 选择凭据类型,示例仍建议显式指定来源以避免混淆。
连接诊断
doctor 检查凭据与 Provider 连接或本机运行环境,不上传或提交应用;通常会请求远端,不能当作离线参数校验。
bash
foxstore-cli doctor apple --issuer-id "$APPLE_ISSUER_ID" --key-id "$APPLE_KEY_ID" --output json
foxstore-cli doctor google-play --package-name com.example.app --output json
foxstore-cli doctor huawei --output json
foxstore-cli doctor pgyer --output json
foxstore-cli doctor tencent-appstore --output json
foxstore-cli doctor vivo --package-name com.example.app --output json
foxstore-cli doctor samsung --output json
foxstore-cli doctor wechat-miniprogram --output json
foxstore-cli doctor oppo --output json
foxstore-cli doctor honor --output json
foxstore-cli doctor xiaomi --output jsonApple 需要 --issuer-id、--key-id;Google Play 需要 --package-name;vivo 需要 --package-name,并可用 --endpoint 覆盖默认生产地址。腾讯应用宝还必须设置 TENCENT_APPSTORE_APP_ID 与 TENCENT_APPSTORE_PACKAGE_NAME 环境变量(string,doctor 没有对应命令行参数)。其他命令的参数为各自凭据来源。微信仅检查私钥来源和本机 Node.js、miniprogram-ci、miniprogram-mp-ci,这两个包必须能从当前目录或父目录的 node_modules 找到;它不验证远端上传权限。小米使用固定探测包名查询,不替代目标应用的 status 查询。
发布命令与参数
Apple App Store
bash
foxstore-cli publish apple \
--issuer-id "$APPLE_ISSUER_ID" --key-id "$APPLE_KEY_ID" \
--app-id 1234567890 --file ./build/App.ipa --output ndjson必填 string:--issuer-id、--key-id、--app-id;必填 path:--file,以及私钥环境变量或文件。CLI 通过 Build Upload API 上传 IPA,成功数据为 { "provider": "apple", "buildUploadId": "…" };不提交 App Store 审核,也不保证 Apple 后续处理或 TestFlight 分发已完成。
Google Play
bash
foxstore-cli publish google-play \
--package-name com.example.app --file ./build/App.aab \
--track internal --release-status completed \
--release-notes-file ./release-notes.json --output ndjson| 参数 | 必填/默认 | 说明 |
|---|---|---|
--package-name、--file | 必填 string / path | Play 包名与 APK/AAB 路径。 |
--track | string,internal | 目标 Track。 |
--release-status | string,completed | 仅 draft、inProgress、completed;不接受 halted。 |
--user-fraction | 可选 f64 | inProgress 必填且 0 < 值 < 1,其他状态不得传入。 |
--release-name | string,空字符串 | 发布名称。 |
--release-notes-file | 可选 path | JSON 数组;每项必填 string language 和 text;省略时为空数组。 |
release-notes.json 示例:
json
[{ "language": "zh-CN", "text": "修复已知问题" }, { "language": "en-US", "text": "Bug fixes" }]Huawei AppGallery
bash
foxstore-cli publish huawei \
--app-id 123456 --expected-package-name com.example.app \
--file ./build/App.app --submit true --timeout-seconds 240 --output ndjson| 参数 | 必填/默认 | 说明 |
|---|---|---|
--app-id、--expected-package-name、--file | 必填 string / string / path | 支持 .app、.apk、.aab;凭据类型应与包体平台一致。 |
--chinese-mainland-flag | 可选 i32 | 仅 HarmonyOS 上传区域标记:0 或 1。 |
--submit | bool 值,true | 上传完成后是否提交发布。 |
--release-time、--remark | 可选 string | 发布时间使用 yyyy-MM-ddTHH:mm:ssZZ;备注仅 HarmonyOS 使用,填写时 10–300 字符。 |
--release-phase | i64,0 | 仅 HarmonyOS:0 全网、3 分阶段。 |
--phased-release-description | 可选 string | 仅 HarmonyOS;阶段 3 必填,最多 500 字符。 |
--timeout-seconds | u64,240 | 仅 Android 编译轮询预算,须大于 0;按约每 2 秒一次计算次数,请求耗时另计。不是总 deadline,HarmonyOS 不使用此值。 |
蒲公英
bash
foxstore-cli publish pgyer \
--file ./build/App.ipa --update-description "CI build" \
--timeout-seconds 180 --output ndjson--file 为必填 path(IPA/APK/HAP);--build-type 为可选 string:ios/ipa、android/apk、harmonyos/hap,默认按扩展名推断;--update-description 为可选 string;--timeout-seconds 为 u64,默认 180 且须大于 0,覆盖鉴权、上传票据、上传和轮询的总 deadline。
腾讯应用宝
bash
foxstore-cli publish tencent-appstore \
--package-name com.example.app --app-id 1000123 --file ./build/App.apk \
--release-notes "修复已知问题" --deploy-type 1 --output ndjson--package-name、--app-id 为必填 string,--file 为必填 APK path;--release-notes 为 string,默认空;--deploy-type 为 i64,默认 1,可选 1/2(定时);--deploy-time 为可选 i64 秒级时间戳,类型 2 时必填;--apk-64-only 是 bool 开关,默认 false。此流程更新已有应用。
vivo
bash
foxstore-cli publish vivo \
--package-name com.example.app --file ./build/App.apk --version-code 42 \
--online-type 1 --update-description "修复已知问题" --output ndjson--package-name 为必填 string,--file 为必填 APK path,--version-code 为必填 i64;--online-type 为 i64,默认 1,可选 1/2(定时);--scheduled-online-time 为可选 string,类型 2 时必填;--update-description 为可选 string。--endpoint 为 string,默认 https://developer-api.vivo.com.cn/router/rest,另一个允许值为 https://sandbox-developer-api.vivo.com.cn/router/rest,不接受其他地址。
Samsung Galaxy Store
bash
foxstore-cli publish samsung \
--content-id 000007654321 --file ./build/App.apk \
--uses-gms true --submit true --output ndjson--content-id 为必填 string,--file 为必填 APK path;--uses-gms 为可选 bool 值(例如 --uses-gms false),省略时沿用商店已有二进制的 GMS 设置;--release-at 为可选 i64 Unix 毫秒时间戳,必须晚于当前时间,且仅当前内容为 FOR_SALE 时可在此次更新设置;--submit 为 bool 值,默认 true,只上传时写 --submit false。
微信小程序
bash
foxstore-cli publish wechat-miniprogram \
--appid wx1234567890 --project-path ./miniprogram --version 1.2.3 \
--description "CI build" --robot 1 --output ndjson--appid、--version 为必填 string,--project-path 为必填 path;--description 为 string,默认空;--robot 为可选 u8,范围 1–30;--project-type 为 string,默认 miniProgram,可选 miniProgram、miniProgramPlugin、miniGame、miniGamePlugin。这是上传代码版本,不是自动提审/上线命令;需满足上文 Node.js 与两项 npm 包前提。
OPPO / HeyTap
bash
foxstore-cli publish oppo --request-file ./oppo-release.json --output ndjson--request-file 为必填 path。文件是顶层 JSON 对象;以下为完整输入字段,名称区分大小写。
| 字段 | JSON 类型 / 必填 | 约束 |
|---|---|---|
packageKind | string,必填 | ordinary 或 multi;必须显式填写。 |
apkFiles | object[],必填 | 每项必填 string filePath 和 integer cpuCode;普通包恰好一项且 cpuCode=0;多包恰好两项且分别为 32、64。 |
packageName、versionCode、appName | string,必填 | versionCode 为正整数的字符串,必须与包体一致。 |
secondCategoryId、thirdCategoryId | integer,必填 | 商店有效分类 ID。 |
summary | string,必填 | 最多 13 字符,不含空格或标点。 |
detailDescription、updateDescription | string,必填 | 分别至少 20 / 5 字符。 |
privacyPolicyUrl、iconUrl、copyrightUrl | string,必填 | 隐私政策、已上传图标、版权材料 URL。 |
screenshotUrls | string[],必填 | 2–5 个已上传的竖版截图 URL。 |
testDescription | string,必填 | 测试附加说明,不可为空。 |
businessContactName、businessContactEmail、businessContactMobile | string,必填 | 商务联系人。 |
ageLevel | integer,必填 | 大于 0 的有效年龄分级。 |
adaptiveEquipment | integer,必填 | 4、5 或 6。 |
onlineType | integer,必填 | 1 或 2(定时)。 |
scheduledOnlineTime | string,可选 | onlineType=2 时必填。 |
landscapeScreenshotUrls | string[],可选 | 已上传横屏截图 URL。 |
icpUrl、specialCertificateUrl、specialCertificateFileUrl | string,可选 | 备案/特殊资质 URL,按应用资质要求填写。 |
adaptiveType | integer,可选 | 适配类型。 |
示例骨架(分类 ID、素材 URL、联系人、分级需替换成应用的真实资料;apkFiles 指向已构建 APK,CLI 不把本地图片自动换成远端 URL):
json
{
"packageKind": "ordinary",
"apkFiles": [{ "filePath": "./build/App.apk", "cpuCode": 0 }],
"packageName": "com.example.app", "versionCode": "42", "appName": "示例应用",
"secondCategoryId": 1, "thirdCategoryId": 1,
"summary": "便捷记录日常生活",
"detailDescription": "这是一款用于记录日常生活与管理个人事项的示例应用。",
"updateDescription": "修复已知问题并改善使用体验",
"privacyPolicyUrl": "https://example.com/privacy",
"iconUrl": "https://example.com/uploaded/icon.png",
"screenshotUrls": ["https://example.com/uploaded/1.png", "https://example.com/uploaded/2.png"],
"copyrightUrl": "https://example.com/uploaded/copyright.png",
"testDescription": "无需登录即可使用基础功能",
"businessContactName": "应用联系人", "businessContactEmail": "[email protected]",
"businessContactMobile": "13800000000", "ageLevel": 1,
"adaptiveEquipment": 4, "onlineType": 1
}荣耀应用市场
bash
foxstore-cli publish honor \
--app-id 123456 --package-name com.example.app --file ./build/App.apk \
--audit-file ./honor-audit.json --output ndjson--app-id 为必填 i64,--package-name 为必填 string,--file(APK)与 --audit-file 为必填 path。审核 JSON 为顶层对象:
| 字段 | JSON 类型 / 必填 | 约束 |
|---|---|---|
releaseType | integer,必填 | 1 普通、2 定时、3 分阶段。 |
forceUpdate | boolean,必填 | 使用 true/false,不是数字。 |
testAccount、testPassword | string,可选 | 审核测试账号和密码;含密码的文件应由 CI 临时创建。 |
testComment | string,可选 | 最多 500 字符。 |
releaseTime | string,可选 | releaseType=2 时必填。 |
phasedReleasePercentage | string,可选 | releaseType=3 时必填,数值大于 0 且不超过 100。 |
phasedReleaseStart、phasedReleaseEnd | string,可选 | releaseType=3 时必填。 |
phasedReleaseNote | string,可选 | releaseType=3 时必填,最多 500 字符。 |
releaseNotesLanguage、releaseNotes | string,可选 | 非空 releaseNotes 需要对应语言 ID;更新说明最多 500 字符。 |
时间字符串使用 yyyy-MM-ddTHH:mm:ssZZ,例如 2026-10-01T09:00:00+0800。最小普通发布 honor-audit.json:
json
{ "releaseType": 1, "forceUpdate": false }小米应用商店
bash
foxstore-cli publish xiaomi --request-file ./xiaomi-release.json --output ndjson--request-file 为必填 path。JSON 为顶层对象(无需添加 appInfo / RequestData 包装):
| 字段 | JSON 类型 / 必填 | 约束 |
|---|---|---|
synchroType | integer,必填 | 0 新增、1 更新版本、2 更新资料;最终受账号和应用权限约束。 |
appName、packageName、privacyUrl、iconPath | string,必填 | 非空;iconPath 为本地文件路径。 |
publisherName、versionName | string,可选 | 开发者与版本名称。 |
category、keyWords、description、brief | string,可选 | synchroType=0 时均必填。 |
updateDescription | string,可选 | synchroType=1 时必填。 |
testAccount | string,可选 | 内容是序列化 JSON 字符串,见下文。 |
onlineTime | integer,可选 | 上线时间。 |
suitableType | integer,可选 | 0、1 或 2。 |
apkPath | string,可选 | synchroType=0/1 时必填,本地 APK。 |
secondApkPath | string,可选 | 第二个本地 APK。 |
screenshotPaths | string[],默认 [] | 最多 5 个;新增应用至少 3 个本地截图。 |
tabletScreenshotPaths | string[],默认 [] | 最多 5 个;新增且 suitableType=1/2 时至少 4 个。 |
更新版本示例 xiaomi-release.json(文件必须存在且符合目标应用要求):
json
{
"synchroType": 1, "appName": "示例应用", "packageName": "com.example.app",
"privacyUrl": "https://example.com/privacy", "iconPath": "./store/icon.png",
"apkPath": "./build/App.apk", "updateDescription": "修复已知问题"
}testAccount 是嵌套 JSON 编码后的字符串,例如 "{\"zh_CN\":{\"auditNotes\":\"无需登录\"}}";每个语言键对应对象,可含 auditNotes(最多 500 字符)与 accounts 数组(最多 5 项)。accounts 每项是对象:必填 integer t(1 或 2),可选 string a(账号)、p(密码)、c(补充值),三个字符串各最多 50 字符;账号与密码应同时填写或同时留空。不要直接传 JSON 对象给 testAccount。
状态查询
微信小程序上传由本机 CI 同步返回结果,当前没有独立 status 命令;结果未知时到微信后台核对。其他查询入口如下,均需同 Provider 凭据。未标注可选的参数均必填,默认类型 string;所有 status 都是一次查询,不是持续等待。
| 命令 | 参数 |
|---|---|
status apple | --issuer-id、--key-id 与私钥来源;按上传时间倒序查询凭据可见的 Build;没有 --app-id 过滤,也不能用 buildUploadId 直接查询。 |
status google-play | --package-name;返回 Tracks。 |
status huawei | --app-id;HarmonyOS 使用 Service Account;Android 使用 API Client 且至少传一个可重复的 --package-id。 |
status pgyer | --app-key;可选 --build-key。 |
status tencent-appstore | --package-name、--app-id。 |
status vivo | --package-name;可选 --endpoint。 |
status samsung | --content-id。 |
status oppo | --package-name;可选 --version-code;多包查询加 --multi-package(bool 开关,默认 false)。 |
status honor | --app-id 与一个或多个 --release-id(app-id 为 i64,每个 release-id 为 string,可重复)。 |
status xiaomi | --package-name。 |
机器输出与退出码
当前 schemaVersion 为字符串 "1"。json 是缩进 JSON;ndjson 是一条紧凑 JSON 行。两种格式都只有最终结果,当前没有上传进度事件流。成功 envelope 写入 stdout,错误 envelope(包括参数错误)写入 stderr;不要只解析 stdout,也不要将两个流混成一个 JSON 文件。
成功示例(Apple 上传,不表示已审核/上架):
json
{ "schemaVersion": "1", "status": "success", "data": { "provider": "apple", "buildUploadId": "example-upload-id" } }错误示例(仅展示结构):
json
{ "schemaVersion": "1", "status": "error", "error": { "code": "CLI_ARGUMENT_INVALID", "category": "input", "message": "缺少必填参数", "retryable": false } }data 由命令决定,可能是对象或数组,不保证包含 provider。error.code 为字符串,category 为下表的固定字符串,message 为说明,retryable 为 boolean。上游 Secret/鉴权信息会做脱敏;输入路径和请求 JSON 中的业务文本仍应按团队日志策略保护。
| 退出码 | 分类 | 流水线处理 |
|---|---|---|
0 | 成功 | 命令执行成功;还需判断预检/发布数据,不等于审核通过或上架。 |
2 | input:输入或包体错误 | 修正参数或构建产物。 |
3 | credential:凭据错误 | 检查 Secret 名称、临时文件和权限。 |
4 | network:网络错误 | 仅在 retryable: true 时按策略重试。 |
5 | provider:Provider 拒绝或响应错误 | 读取脱敏错误码并修复权限、资料或平台状态。 |
6 | unsupported:未支持能力 | 不要把该动作视为成功。 |
7 | result-unknown:结果未知 | 远端写入可能已发生;必须先执行 status 对账,不能立即重复发布。 |
10 | internal:CLI 内部错误 | 保存版本和脱敏日志后反馈。 |
重试与对账边界
退出码 7 / result-unknown 表示远端写入可能已发生,通常 retryable: false。例如蒲公英在上传开始前超时可返回 4;上传请求发出后超时返回 7。华为 Android 编译轮询耗尽也返回 7。这是已知的结果未知分类,不保证所有平台中断都能产生完整错误 envelope;Runner 超时、进程被终止或断电时也应先对账。
保存命令版本、产物哈希、应用/包名、版本号、构建号和返回的远端 ID。用上表 status 比对这些标识与远端状态,不能仅凭 status 命令退出 0 判定该版本已发布。Apple 需从构建列表核对目标应用与构建,Google Play 需核对 Track 和 versionCodes;荣耀需 releaseId,华为 Android 需 packageId。如果失败前未拿到这些 ID,或列表尚未出现该版本,请到商店控制台核对,不能虚构 ID 或立刻重新 publish。
没有跨 Provider 的 wait、cancel、reconcile、统一 --timeout 或 --dry-run 命令。retryable: true 也不等于重复发布必定安全,需结合命令是否已经写入远端判断。完整的 Secret 注入、输出保存和流水线失败保留示例见 CI/CD 接入指南。
