Referencia CLI / API
foxstore-cli es la API de publicación no interactiva de Fox Store para CI/CD. API significa aquí la interfaz del proceso de línea de comandos: parámetros, archivos, stdout/stderr y códigos de salida, sin servicio HTTP. Es un ejecutable único enlazado estáticamente con foxstore-engine; no necesita instalar o iniciar Desktop ni lee sus credenciales SQLite.
La CLI automatiza publicaciones en Apple, Google Play, Huawei, miniprogramas WeChat, Tencent MyApp, HONOR, Samsung, Pgyer, vivo, Xiaomi y OPPO. Almacenamiento de objetos, reseñas, Analytics, gestión habitual de certificados, optimización de imágenes y diagnóstico IA permanecen en Engine y Desktop.
Empieza con la Guía CI/CD para integrar GitHub Actions, GitLab CI o Jenkins, y consulta aquí los parámetros.
Formato global
foxstore-cli [--output human|json|ndjson] <command>| Parámetro | Predeterminado | Descripción |
|---|---|---|
--output | human | human para terminal; json produce un resultado estructurado; ndjson, un resultado final compacto, sin eventos de progreso en tiempo real. Puede ir antes o después del subcomando. |
--help | - | Muestra la ayuda actual del comando. |
--version | - | Muestra la versión del binario. |
--help / -h siempre produce texto de ayuda y --version / -V, texto de versión, sin sobre incluso con formato estructurado. Para obtener la versión estructurada, usa version --output json.
Tipos usados: string, texto (los ID siguen siendo strings); path, ruta local del Runner; i64 / i32, enteros con signo; u64 / u8, enteros no negativos; f64, coma flotante. «Opcional» puede omitirse sin valor predeterminado. Un «interruptor» booleano solo lleva el nombre; un «valor» booleano exige true o false. Los comandos publish y status heredan las credenciales del proveedor.
Comandos básicos:
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| Comando | Parámetros | Resultado |
|---|---|---|
version | Ninguno | Devuelve version y engineSchemaVersion. |
providers | Ninguno | Devuelve proveedores compilados en el binario y su disponibilidad. |
capabilities | Obligatorio --provider <string> | Devuelve descripción, cliPublish y capacidades excluidas, no un schema por comando. |
artifact inspect | Obligatorio --file <path> | Identifica tipo, tamaño y SHA-256 del artefacto. |
preflight apple | Obligatorio --file <path> | Verifica un IPA Apple. |
preflight android | Obligatorio --file <path>; opcional --expected-package-name <string> | Verifica el paquete Android y, opcionalmente, su nombre. |
preflight huawei | Obligatorio --file <path> | Solo analiza HarmonyOS .app; para APK/AAB Huawei usa preflight android. |
providers enumera los 15 proveedores estáticos; el almacenamiento de objetos tiene cliPublish: excluded. capabilities --provider acepta los ID apple, google-play, huawei-appgallery, wechat-miniprogram, tencent-appstore, honor, samsung-galaxy-store, pgyer, vivo, xiaomi, oppo, aliyun, tencent-cloud, aws, minio. Los subcomandos Huawei y Samsung son huawei y samsung, no los ID del catálogo.
artifact inspect solo identifica tipo, tamaño y SHA-256, sin verificar firmas. preflight analiza localmente sin publicar; Apple puede devolver éxito y código 0 con data.status: blocked: comprueba data.status == "ready" y data.checks[].blocksUpload. Gestiona también warnings de Android según la política del equipo. publish apple repite la verificación y bloquea paquetes blocked; aprobarla no significa aceptación de la tienda.
Origen de credenciales
Los Secret no se pasan como argumentos ordinarios. *-env recibe el nombre de variable y *-file una ruta temporal creada por CI; son mutuamente excluyentes para el mismo secreto. Todos los *-env son string opcionales y *-file, path opcionales. Sin origen explícito se usan estas variables predeterminadas.
| Proveedor | Variable predeterminada | Parámetros alternativos |
|---|---|---|
| Apple | APPLE_PRIVATE_KEY | --private-key-env / --private-key-file; Issuer ID y Key ID usan --issuer-id y --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 |
| Miniprogramas WeChat | WECHAT_MINIPROGRAM_PRIVATE_KEY | --private-key-env / --private-key-file |
| Tencent MyApp | TENCENT_APPSTORE_USER_ID, TENCENT_APPSTORE_ACCESS_SECRET | --user-id-env / --user-id-file, --access-secret-env / --access-secret-file |
| HONOR | 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 | 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 | 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 |
En Apple, --issuer-id y --key-id son string obligatorios para doctor/publish/status. Las credenciales JSON reciben el documento completo, no una cadena con su ruta. Google/Huawei usan el JSON exportado; Samsung usa { "serviceAccountId": "…", "privateKey": "…", "accessToken": null } (dos primeros string obligatorios, accessToken string opcional). Conserva saltos PEM; no pongas secretos reales en argumentos, repositorios ni registros.
Conserva los nombres exportados de los campos JSON, sin convertir todo a camelCase:
| Credencial | Campos (string, obligatorios salvo indicación) |
|---|---|
| Google Play | type fijo en 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 opcional. |
| Huawei Android API Client | client_id、client_secret。 |
| Samsung | serviceAccountId, privateKey; accessToken opcional. |
La CLI no lee automáticamente variables *_FILE; indica explícitamente, por ejemplo, --private-key-file "$APPLE_KEY_FILE". Los cuatro orígenes Huawei son mutuamente excluyentes: doctor/status usa HarmonyOS Service Account por defecto; Android exige --android-api-client-env HUAWEI_ANDROID_API_CLIENT_JSON o --android-api-client-file <path>. publish elige credenciales según .app / .apk|.aab; aun así recomendamos indicar el origen para evitar confusiones.
Diagnóstico de conexión
doctor comprueba credenciales, conexión del proveedor o entorno local sin subir ni enviar aplicaciones. Normalmente hace solicitudes remotas; no es una validación de parámetros offline.
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 exige --issuer-id y --key-id; Google Play, --package-name; vivo, --package-name, con --endpoint opcional para sustituir producción. Tencent MyApp también exige variables TENCENT_APPSTORE_APP_ID y TENCENT_APPSTORE_PACKAGE_NAME (string; doctor no tiene argumentos equivalentes). Los demás usan sus orígenes de credenciales. WeChat solo comprueba origen de clave, Node.js, miniprogram-ci y miniprogram-mp-ci, localizables en node_modules del directorio actual o sus padres; no valida permisos remotos. Xiaomi consulta un paquete fijo de prueba, sin sustituir status de la aplicación de destino.
Comandos y parámetros de publicación
Apple App Store
foxstore-cli publish apple \
--issuer-id "$APPLE_ISSUER_ID" --key-id "$APPLE_KEY_ID" \
--app-id 1234567890 --file ./build/App.ipa --output ndjsonString obligatorios: --issuer-id, --key-id, --app-id; path obligatorio: --file, además de variable o archivo de clave privada. La CLI sube IPA con Build Upload API; el éxito es { "provider": "apple", "buildUploadId": "…" }. No solicita revisión de App Store ni garantiza que el procesamiento Apple o distribución TestFlight terminen.
Google Play
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| Parámetro | Obligatorio / predeterminado | Descripción |
|---|---|---|
--package-name, --file | string / path obligatorios | Nombre de paquete Play y ruta APK/AAB. |
--track | string, internal | Track de destino. |
--release-status | string, completed | Solo draft, inProgress, completed; no acepta halted. |
--user-fraction | f64 opcional | Obligatorio en inProgress, con 0 < valor < 1; prohibido para otros estados. |
--release-name | string, cadena vacía | Nombre de publicación. |
--release-notes-file | path opcional | Array JSON; cada elemento exige string language y text; si se omite, array vacío. |
Ejemplo de release-notes.json:
[{ "language": "zh-CN", "text": "修复已知问题" }, { "language": "en-US", "text": "Bug fixes" }]Huawei AppGallery
foxstore-cli publish huawei \
--app-id 123456 --expected-package-name com.example.app \
--file ./build/App.app --submit true --timeout-seconds 240 --output ndjson| Parámetro | Obligatorio / predeterminado | Descripción |
|---|---|---|
--app-id, --expected-package-name, --file | string / string / path obligatorios | Admite .app, .apk, .aab; credenciales y plataforma del paquete deben coincidir. |
--chinese-mainland-flag | i32 opcional | Indicador regional de subida solo HarmonyOS: 0 o 1. |
--submit | valor bool, true | Si se envía a publicación tras subir. |
--release-time, --remark | string opcionales | Hora en yyyy-MM-ddTHH:mm:ssZZ; remark solo HarmonyOS, 10–300 caracteres si se indica. |
--release-phase | i64, 0 | Solo HarmonyOS: 0 completa, 3 por fases. |
--phased-release-description | string opcional | Solo HarmonyOS; obligatorio en fase 3, máximo 500 caracteres. |
--timeout-seconds | u64, 240 | Presupuesto de sondeo de compilación solo Android, > 0; número de consultas calculado cada unos 2 s, duración de solicitudes aparte. No es un plazo total; HarmonyOS no lo usa. |
Pgyer
foxstore-cli publish pgyer \
--file ./build/App.ipa --update-description "CI build" \
--timeout-seconds 180 --output ndjson--file es path obligatorio (IPA/APK/HAP); --build-type, string opcional: ios/ipa, android/apk, harmonyos/hap, inferido de la extensión por defecto; --update-description, string opcional; --timeout-seconds, u64, predeterminado 180 y > 0, cubre el plazo total de autenticación, ticket, subida y sondeo.
Tencent MyApp
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 y --app-id son string obligatorios; --file, path APK obligatorio; --release-notes, string vacío por defecto; --deploy-type, i64 predeterminado 1, valores 1/2 (programado); --deploy-time, i64 opcional, timestamp en segundos obligatorio para tipo 2; --apk-64-only, interruptor bool false por defecto. Actualiza aplicaciones existentes.
vivo
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 es string obligatorio; --file, path APK obligatorio; --version-code, i64 obligatorio. --online-type, i64 predeterminado 1, acepta 1/2 (programado); --scheduled-online-time, string opcional obligatorio para tipo 2; --update-description, string opcional. --endpoint es string, por defecto https://developer-api.vivo.com.cn/router/rest; solo admite como alternativa https://sandbox-developer-api.vivo.com.cn/router/rest.
Samsung Galaxy Store
foxstore-cli publish samsung \
--content-id 000007654321 --file ./build/App.apk \
--uses-gms true --submit true --output ndjson--content-id es string obligatorio y --file, path APK obligatorio. --uses-gms es valor bool opcional (p. ej. --uses-gms false); al omitirlo conserva GMS del binario existente. --release-at es i64 opcional, timestamp Unix en milisegundos futuro, configurable en esta actualización solo si el contenido está FOR_SALE. --submit es valor bool predeterminado true; usa --submit false para solo subir.
Miniprogramas de WeChat
foxstore-cli publish wechat-miniprogram \
--appid wx1234567890 --project-path ./miniprogram --version 1.2.3 \
--description "CI build" --robot 1 --output ndjson--appid y --version son string obligatorios; --project-path, path obligatorio; --description, string vacío por defecto; --robot, u8 opcional, 1–30; --project-type, string predeterminado miniProgram, valores miniProgram, miniProgramPlugin, miniGame, miniGamePlugin. Sube una versión de código, sin revisión o publicación automática; requiere Node.js y los dos paquetes npm anteriores.
OPPO / HeyTap
foxstore-cli publish oppo --request-file ./oppo-release.json --output ndjson--request-file es un path obligatorio. El archivo es un objeto JSON de nivel superior; estos son todos sus campos, sensibles a mayúsculas.
| Campo | Tipo JSON / requerido | Restricciones |
|---|---|---|
packageKind | string, obligatorio | ordinary o multi; debe indicarse explícitamente. |
apkFiles | object[], obligatorio | Cada elemento exige string filePath e integer cpuCode; paquete ordinario: uno con cpuCode=0; múltiple: dos, con 32 y 64. |
packageName, versionCode, appName | string, obligatorios | versionCode es un entero positivo como string y debe coincidir con el paquete. |
secondCategoryId, thirdCategoryId | integer, obligatorios | ID de categoría válidos de la tienda. |
summary | string, obligatorio | Máximo 13 caracteres, sin espacios ni puntuación. |
detailDescription, updateDescription | string, obligatorios | Mínimo 20 / 5 caracteres, respectivamente. |
privacyPolicyUrl, iconUrl, copyrightUrl | string, obligatorios | URL de privacidad, icono ya subido y materiales de derechos de autor. |
screenshotUrls | string[], obligatorio | 2–5 URL de capturas verticales ya subidas. |
testDescription | string, obligatorio | Notas adicionales de prueba, no vacías. |
businessContactName, businessContactEmail, businessContactMobile | string, obligatorios | Contacto comercial. |
ageLevel | integer, obligatorio | Clasificación de edad válida > 0. |
adaptiveEquipment | integer, obligatorio | 4, 5 o 6. |
onlineType | integer, obligatorio | 1 o 2 (programado). |
scheduledOnlineTime | string, opcional | Obligatorio cuando onlineType=2. |
landscapeScreenshotUrls | string[], opcional | URL de capturas horizontales ya subidas. |
icpUrl, specialCertificateUrl, specialCertificateFileUrl | string, opcionales | URL de registro o permisos especiales según requisitos de la aplicación. |
adaptiveType | integer, opcional | Tipo de adaptación. |
Ejemplo base: sustituye categorías, URL de recursos, contactos y clasificación por datos reales. apkFiles apunta a APK ya compilados; la CLI no convierte automáticamente imágenes locales en URL remotas.
{
"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
}HONOR App Market
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 es i64 obligatorio; --package-name, string obligatorio; --file (APK) y --audit-file, path obligatorios. El JSON de revisión es un objeto de nivel superior:
| Campo | Tipo JSON / requerido | Restricciones |
|---|---|---|
releaseType | integer, obligatorio | 1 normal, 2 programado, 3 por fases. |
forceUpdate | boolean, obligatorio | Usa true/false, no números. |
testAccount, testPassword | string, opcionales | Cuenta y contraseña para revisión; CI debe crear temporalmente archivos con contraseñas. |
testComment | string, opcional | Máximo 500 caracteres. |
releaseTime | string, opcional | Obligatorio cuando releaseType=2. |
phasedReleasePercentage | string, opcional | Obligatorio cuando releaseType=3; valor > 0 y ≤ 100. |
phasedReleaseStart, phasedReleaseEnd | string, opcionales | Obligatorios cuando releaseType=3. |
phasedReleaseNote | string, opcional | Obligatorio cuando releaseType=3; máximo 500 caracteres. |
releaseNotesLanguage, releaseNotes | string, opcionales | releaseNotes no vacío requiere ID de idioma; máximo 500 caracteres. |
Usa yyyy-MM-ddTHH:mm:ssZZ, por ejemplo 2026-10-01T09:00:00+0800. Publicación normal mínima en honor-audit.json:
{ "releaseType": 1, "forceUpdate": false }Xiaomi App Store
foxstore-cli publish xiaomi --request-file ./xiaomi-release.json --output ndjson--request-file es path obligatorio. JSON es un objeto de nivel superior, sin envoltorio appInfo / RequestData:
| Campo | Tipo JSON / requerido | Restricciones |
|---|---|---|
synchroType | integer, obligatorio | 0 crear, 1 actualizar versión, 2 actualizar datos; sujeto a permisos de cuenta y aplicación. |
appName, packageName, privacyUrl, iconPath | string, obligatorios | No vacíos; iconPath es una ruta local. |
publisherName, versionName | string, opcionales | Nombre del desarrollador y versión. |
category, keyWords, description, brief | string, opcionales | Todos obligatorios cuando synchroType=0. |
updateDescription | string, opcional | Obligatorio cuando synchroType=1. |
testAccount | string, opcional | Cadena JSON serializada; véase abajo. |
onlineTime | integer, opcional | Hora de publicación. |
suitableType | integer, opcional | 0, 1 o 2. |
apkPath | string, opcional | Obligatorio cuando synchroType=0/1; APK local. |
secondApkPath | string, opcional | Segundo APK local. |
screenshotPaths | string[], predeterminado [] | Máximo 5; una app nueva exige al menos 3 capturas locales. |
tabletScreenshotPaths | string[], predeterminado [] | Máximo 5; al crear con suitableType=1/2 exige al menos 4. |
Ejemplo de actualización xiaomi-release.json; los archivos deben existir y cumplir los requisitos de la aplicación:
{
"synchroType": 1, "appName": "示例应用", "packageName": "com.example.app",
"privacyUrl": "https://example.com/privacy", "iconPath": "./store/icon.png",
"apkPath": "./build/App.apk", "updateDescription": "修复已知问题"
}testAccount es una cadena con JSON anidado codificado, p. ej. "{\"zh_CN\":{\"auditNotes\":\"无需登录\"}}". Cada clave de idioma corresponde a un objeto con auditNotes opcional (máximo 500 caracteres) y array accounts (máximo 5). Cada cuenta es un objeto con integer obligatorio t (1 o 2) y string opcionales a (cuenta), p (contraseña), c (valor adicional), máximo 50 caracteres cada uno; cuenta y contraseña deben rellenarse o dejarse vacías juntas. No pases un objeto JSON directamente a testAccount.
Consulta de estado
La CI local devuelve sincrónicamente el resultado de subidas WeChat; no existe status independiente. Si es desconocido, verifica en su consola. Las demás consultas requieren credenciales del mismo proveedor. Los parámetros son obligatorios salvo indicación, con tipo string por defecto. Todos los status consultan una sola vez, sin espera continua.
| Comando | Parámetros |
|---|---|
status apple | --issuer-id, --key-id y origen de clave; Build visibles ordenados por fecha de subida descendente; sin filtro --app-id ni consulta directa por buildUploadId. |
status google-play | --package-name; devuelve Tracks. |
status huawei | --app-id; HarmonyOS usa Service Account; Android usa API Client y al menos un --package-id repetible. |
status pgyer | --app-key; --build-key opcional. |
status tencent-appstore | --package-name、--app-id。 |
status vivo | --package-name; --endpoint opcional. |
status samsung | --content-id。 |
status oppo | --package-name; --version-code opcional; añade --multi-package para varios paquetes (interruptor bool, false por defecto). |
status honor | --app-id y uno o varios --release-id (app-id i64; cada release-id string, repetible). |
status xiaomi | --package-name。 |
Salida estructurada y códigos de salida
schemaVersion es actualmente string "1". json tiene sangría; ndjson es una línea compacta. Ambos solo emiten el resultado final, sin flujo de progreso. El sobre de éxito va a stdout; el de error, incluso argumentos, a stderr. No analices solo stdout ni mezcles ambos en un archivo JSON.
Ejemplo de éxito: subida Apple, no aprobación ni publicación:
{ "schemaVersion": "1", "status": "success", "data": { "provider": "apple", "buildUploadId": "example-upload-id" } }Ejemplo de error, solo para mostrar la estructura:
{ "schemaVersion": "1", "status": "error", "error": { "code": "CLI_ARGUMENT_INVALID", "category": "input", "message": "缺少必填参数", "retryable": false } }data depende del comando: objeto o array, sin garantía de campo provider. error.code es string, category uno de los strings fijos de la tabla, message la explicación y retryable boolean. Se eliminan secretos y datos de autenticación del proveedor; protege rutas de entrada y textos de negocio del JSON según la política de registros del equipo.
| Código | Categoría | Tratamiento en pipeline |
|---|---|---|
0 | Éxito | Comando correcto; evalúa datos de verificación/publicación, no significa aprobación ni disponibilidad en tienda. |
2 | input: entrada o paquete incorrectos | Corrige parámetros o artefactos. |
3 | credential: credenciales incorrectas | Revisa nombres de Secret, archivos temporales y permisos. |
4 | network: error de red | Reintenta según política solo con retryable: true. |
5 | provider: rechazo o respuesta incorrecta | Lee el código sin datos sensibles y corrige permisos, materiales o estado de plataforma. |
6 | unsupported: capacidad no soportada | No lo consideres éxito. |
7 | result-unknown: resultado desconocido | Puede haberse escrito remotamente; concilia con status antes de repetir la publicación. |
10 | internal: error interno CLI | Conserva versión y registros sin datos sensibles y comunícalo. |
Límites de reintentos y conciliación
El código 7 / result-unknown indica posible escritura remota, normalmente con retryable: false. En Pgyer, un timeout anterior a la subida puede devolver 4; después de enviar la solicitud, devuelve 7. Agotar el sondeo de compilación Huawei Android también da 7. Es una clasificación conocida, no garantiza sobre completo para toda interrupción. Ante timeout del Runner, terminación del proceso o corte eléctrico, concilia primero.
Conserva versión del comando, hash del artefacto, aplicación/paquete, versión, número de compilación e ID remotos devueltos. Compáralos con status; su código 0 no demuestra que esa versión se publicó. Apple requiere cotejar aplicación y Build en la lista, Google Play Track y versionCodes; HONOR necesita releaseId y Huawei Android packageId. Si no recibiste los ID o la versión aún no aparece, revisa la consola; no inventes ID ni repitas publish inmediatamente.
No hay comandos wait, cancel, reconcile, --timeout ni --dry-run comunes a todos los proveedores. retryable: true tampoco garantiza que repetir publish sea seguro; comprueba si ya hubo escritura remota. Consulta un ejemplo completo de inyección de Secret, conservación de resultados y fallo de pipeline en la Guía CI/CD.
