Para firmar y compilar una app de Capacitor en la nube, creas tu material de firma una sola vez (un keystore de Android, un certificado de distribución de iOS y un perfil de aprovisionamiento), lo proporcionas a un servicio de build en la nube y luego inicias los builds desde tu terminal o CI. El servicio compila el proyecto nativo, lo firma y puede subirlo directamente a TestFlight o Google Play. Esta guía cubre cada archivo de firma, cómo crearlo sin un Mac, cómo configurarlo con Capgo Build y cómo automatizar builds firmados de forma segura.
Qué significa “firmar en la nube”
Ambas tiendas solo aceptan binarios firmados. La firma demuestra que el build viene de ti y que nadie lo ha modificado después. Localmente, Xcode y Android Studio ocultan casi todo esto. En la nube, nada es implícito, así que debes saber exactamente qué archivos intervienen:
| Plataforma | Archivo | Qué es | Para qué sirve |
|---|---|---|---|
| Android | .jks / .keystore |
Keystore que contiene tu upload key | Firmar el AAB o APK |
| Android | Cuenta de servicio .json |
Credenciales de Google Cloud | Subir a Google Play |
| iOS | .p12 |
Certificado Apple Distribution y clave privada | Firma del IPA |
| iOS | .mobileprovision |
Provisioning profile que vincula bundle ID, certificado y capabilities | Permite que la app se ejecute y se distribuya |
| iOS | .p8 + ID de clave + ID de emisor |
Clave API de App Store Connect | Subida a TestFlight y lectura de números de build |
No los subas a Git. Todo lo que sigue los guarda en tu archivo de credenciales local o en el secret store de tu CI.
Firma de Android
Crear el keystore de upload
Si la app ya está en Google Play, reutiliza el keystore existente. Firmar una actualización con una clave diferente se rechaza a menos que realices el reset de la clave de upload en Play Console.
Para una app nueva:
keytool -genkeypair -v \
-storetype PKCS12 \
-keystore release.jks \
-alias upload \
-keyalg RSA -keysize 2048 \
-validity 10000
Notas:
- Google Play exige que la clave sea válida al menos hasta el 22 de octubre de 2033.
-validity 10000(unos 27 años) cubre ese requisito. - Con el tipo de almacén PKCS12, la contraseña de la clave es la misma que la del almacén.
- ¿No tienes un JDK a mano? El Generador de keystore para Android genera el mismo archivo en el navegador.
Play App Signing y la clave de carga
Las nuevas apps en Google Play usan Play App Signing. Google guarda la clave de firma de la app y vuelve a firmar lo que los usuarios descargan. Tu keystore es el subir clave. Si lo pierdes, el soporte de Play Console puede registrar una nueva clave de carga, por eso perderla es un retraso, no un desastre. Aun así, haz una copia de seguridad.
Cuenta de servicio para subidas
Para subir desde la nube, crea una cuenta de servicio en Google Cloud, habilita la API de Google Play Android Developer, descarga su clave JSON e invita a la cuenta de servicio en Play Console, en Usuarios y permisos con permisos de lanzamiento para tu app. El onboarding de Capgo puede hacerlo mediante Google sign-in, como se muestra abajo.
Firma de iOS
Los tres elementos de Apple
- Certificado de Apple Distribution. Con uno por equipo es suficiente, válido por un año. Apple limita cuántos puedes tener, así que no crees uno por cada desarrollador.
- Perfil de aprovisionamiento. Vincula el bundle ID, el certificado y las capacidades, como las notificaciones push. Usa un App Store Connect perfil para TestFlight y la App Store, y un Ad Hoc perfil para instalaciones en dispositivos registrados. Cada extensión de la app (widget, extensión de compartir, servicio de notificaciones) necesita su propio perfil.
- clave de App Store Connect API. Creada bajo Usuarios y acceso > Integraciones con acceso de App Manager. El
.p8archivo solo se descarga una vez.
Necesitas permisos de administrador o titular de la cuenta en el equipo de Apple Developer para crearlos.
Crear un certificado sin un Mac
El flujo de Keychain Access requiere macOS, pero OpenSSL funciona en cualquier lugar:
# 1. Private key and certificate signing request
openssl req -new -newkey rsa:2048 -nodes \
-keyout dist.key -out dist.csr \
-subj "/emailAddress=dev@example.com/CN=Example Inc/C=US"
# 2. Upload dist.csr at developer.apple.com > Certificates > + > Apple Distribution
# and download distribution.cer
# 3. Convert and bundle into a .p12
openssl x509 -inform DER -in distribution.cer -out distribution.pem
openssl pkcs12 -export -legacy \
-inkey dist.key -in distribution.pem \
-out distribution.p12 -passout pass:choose-a-password
El -legacy el flag importa con OpenSSL 3: sin él, las máquinas de build de macOS pueden fallar al importar el .p12 con “MAC verification failed”. El basado en navegador generador de certificados iOS hace los mismos pasos si prefieres no usar una terminal.
Luego crea el perfil de aprovisionamiento en el portal de desarrollador (Perfiles > + > App Store Connect), selecciona tu app ID y el nuevo certificado, y descárgalo.
Configura la firma con Capgo Build
Build de Capgo compila y firma apps de Capacitor en máquinas gestionadas por Capgo, para que puedas hacer build de iOS desde Windows o Linux. Comienza iniciando sesión y registrando la app:
bunx @capgo/cli@latest login
bunx @capgo/cli@latest app add
Opción A: onboarding guiado (recomendado)
bunx @capgo/cli@latest build init --platform ios
bunx @capgo/cli@latest build init --platform android
En iOS, el onboarding crea o reutiliza el certificado de distribución y el perfil de aprovisionamiento de App Store con tu clave de App Store Connect API. En macOS también puede guiarte para crear esa clave API. En Android, crea o importa el keystore y puede aprovisionar la cuenta de servicio de Google Cloud y la invitación de Play Console mediante el inicio de sesión de Google. Al final, ofrece iniciar el primer build.
Opción B: guardar archivos existentes
Si ya tienes los archivos de las secciones anteriores:
# iOS
bunx @capgo/cli@latest build credentials save \
--platform ios \
--certificate ./distribution.p12 \
--p12-password "choose-a-password" \
--ios-provisioning-profile ./AppStore.mobileprovision \
--apple-key ./AuthKey_ABC1234567.p8 \
--apple-key-id ABC1234567 \
--apple-issuer-id 00000000-0000-0000-0000-000000000000 \
--apple-team-id TEAM123456
# Android
bunx @capgo/cli@latest build credentials save \
--platform android \
--keystore ./release.jks \
--keystore-alias upload \
--keystore-key-password "store-password" \
--keystore-store-password "store-password" \
--play-config ./play-service-account.json
Para apps con extensiones, repite --ios-provisioning-profile con un bundleId=path mapping para cada target:
--ios-provisioning-profile com.example.app=./App.mobileprovision \
--ios-provisioning-profile com.example.app.widget=./Widget.mobileprovision
Las credenciales se almacenan en ~/.capgo-credentials/credentials.json, indexadas por app ID y plataforma. Añade --local para almacenarlas en .capgo-credentials.json en el proyecto en su lugar, y añade ese archivo a .gitignore. Revisa lo que se guarda con bunx @capgo/cli@latest build credentials list.
Lanzar un build firmado
Prepara el proyecto nativo y luego solicita el build:
bun run build
bunx cap sync
# iOS: sign with the App Store profile and upload to TestFlight
bunx @capgo/cli@latest build request com.example.app --platform ios --build-mode release
# Android: sign the AAB and upload to the internal track
bunx @capgo/cli@latest build request com.example.app --platform android --build-mode release --android-track internal
Los logs llegan a tu terminal. Un escaneo previo al build comprueba la caducidad de los certificados, las contraseñas y el emparejamiento de perfiles antes de subir nada, así que la mayoría de los errores de firma fallan en segundos en lugar de minutos. Ejecútalo por separado con bunx @capgo/cli@latest build prescan --platform ios.
Variaciones útiles:
| Objetivo | Flags |
|---|---|
| Build de prueba en iPhones registrados | --ios-distribution ad_hoc --ios-provisioning-profile ./adhoc.mobileprovision --output-upload |
| APK para MDM o dispositivos kiosk | --platform android --no-playstore-upload --output-upload |
| Enviar directamente a App Review | --submit-to-store-review --store-release-name 2.4.0 |
| Conservar tu propio número de build | --skip-build-number-bump |
| Build limpio sin caché | --no-cache |
Para builds ad hoc, recopila primero los UDIDs de los dispositivos con el Buscador de UDID de iOS y añádelos al perfil.
Automatizar builds firmados en CI
En CI, pasa las credenciales como variables de entorno en lugar de un archivo de credenciales. CLI exporta exactamente lo que necesitas:
bunx @capgo/cli@latest build credentials manage --appId com.example.app
# choose "Export to .env"
En GitHub, sube cada línea a los secrets del repositorio con un solo comando y luego elimina el archivo:
gh secret set -f .env.capgo.com.example.app
gh secret set CAPGO_TOKEN --body "your-capgo-api-key"
rm .env.capgo.com.example.app
Un workflow de release que firma y publica ambas plataformas al crear una tag:
name: Signed release
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform: [ios, android]
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run build
- run: bunx cap sync ${{ matrix.platform }}
- run: bunx @capgo/cli@latest build request com.example.app --platform ${{ matrix.platform }} --build-mode release
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
CAPGO_IOS_PROVISIONING_MAP_BASE64: ${{ secrets.CAPGO_IOS_PROVISIONING_MAP_BASE64 }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
ANDROID_KEYSTORE_FILE: ${{ secrets.ANDROID_KEYSTORE_FILE }}
KEYSTORE_KEY_ALIAS: ${{ secrets.KEYSTORE_KEY_ALIAS }}
KEYSTORE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }}
KEYSTORE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }}
PLAY_CONFIG_JSON: ${{ secrets.PLAY_CONFIG_JSON }}
El job se ejecuta en Linux. Sin runner de macOS, sin comandos de keychain, sin fastlane. Las mismas variables de entorno funcionan en cualquier CI: variables de GitLab CI/CD, variables seguras de Bitbucket, secrets de Gitea o grupos de variables de Azure DevOps. Guías específicas por plataforma: Bitbucket Pipelines, Gitea Actions, y la Docs de GitHub Actions.
Cómo se gestionan tus claves
Una pregunta justa antes de entregar tus claves de firma a cualquier servicio cloud. Con Capgo Build:
- Las credenciales residen en tu máquina (
~/.capgo-credentials/) o en tu almacén de secretos de CI. Capgo no guarda tus claves en un vault. - En cada build, CLI las envía por HTTPS. Solo se usan durante ese build y se borran al terminar.
- Solo se sube el proyecto nativo preparado. Tu código web,
.git, y.envlos archivos no. - Las apps compiladas van directamente a App Store Connect o Google Play, o a un enlace de descarga temporal si lo solicitas.
La contrapartida: rotar una credencial implica actualizar tus secretos de CI manualmente. Re-exporta con build credentials manage y vuelve a subir el archivo.
Expiración y rotación
| Elemento | De por vida | Qué hacer |
|---|---|---|
| Certificado Apple Distribution | 1 año | Crear uno nuevo, regenerar perfiles, volver a guardar, actualizar CI |
| Perfil de aprovisionamiento | 1 año, o hasta que se revoque su certificado | Regenerar y volver a guardar |
| Clave API de App Store Connect | Hasta que se revoque | Revocar cuando alguien con acceso se vaya |
| Keystore de subida de Android | Mientras sea válido (configúralo en décadas) | Haz backup; si se pierde, resetéalo desde Play Console |
| Clave de cuenta de servicio de Play | Hasta que se elimine | Rótala cada año o cuando cambie el acceso |
Anota las fechas de Apple en un calendario compartido. Un certificado expirado no afecta a las apps ya instaladas, pero bloquea cada nuevo build.
Solución de problemas
| Error | Causa y solución |
|---|---|
Provisioning profile doesn't include signing certificate |
El perfil se generó para otro certificado. Regenéralo con el actual. |
Provisioning profile doesn't match bundle ID |
Perfil creado para otro ID de app o falta un target de extensión. Añade un bundleId=path mapeo para cada destino. |
MAC verification failed |
Incorrecto .p12 contraseña, o exportación de OpenSSL 3 sin -legacy. |
Keystore was tampered with, or password was incorrect |
Contraseña del keystore incorrecta, o el archivo se corrompió por saltos de línea en base64. |
Key alias not found |
El alias difiere del que hay en el keystore. Liéstalo con keytool -list -keystore release.jks. |
| Error de autenticación en App Store Connect | Key ID o issuer ID incorrectos, clave revocada o el reloj del sistema desincronizado en la máquina que firma el token. |
| Play upload: el usuario que llama no tiene permisos | La cuenta de servicio no está invitada en Play Console, o el API de Android Developer no está habilitado. |
Más soluciones están en la guía de resolución de problemas de Capgo Build y CI/CD para Capacitor: errores comunes.
Tras el primer build firmado
Solo necesitas builds nativos firmados cuando cambian los code nativos. Para cambios en JavaScript, CSS y HTML, envía un live update a las apps instaladas y reserva los builds de tienda para releases que toquen plugins o configuración nativa. Si vienes de un setup con Mac, Compila una app iOS desde Windows con Capgo Build muestra el workflow completo sin macOS.