CI/CD for a Cordova app in 2026 means building and signing the Android AAB on a Linux runner, building and signing the iOS IPA on a macOS runner, and uploading both to the stores from the same pipeline. The managed services Cordova teams used for this are gone or closing, so most teams now run the Cordova CLI on a general-purpose CI. This guide gives you a working GitHub Actions setup, the same steps for other CIs, and an honest look at live updates and long-term options.
¿Qué cambió para los equipos de Cordova?
Tres eventos moldearon el CI/CD de Cordova:
- PhoneGap Build se detuvo el 1 de octubre de 2020.
- Microsoft App Center se detuvo el 31 de marzo de 2025. Concluyó la construcción, la distribución y el servicio de CodePush hospedado.
- Ionic Appflow dejó de vender nuevos en febrero de 2025. Los clientes existentes mantienen acceso hasta el 31 de diciembre de 2027.
Cordova sigue funcionando. El proyecto Apache envía cordova-android y cordova-ios lanzamientos, y hay muchas aplicaciones internas y de empresa que funcionan en él. La brecha es la capa administrada: almacenamiento de firmas, subidas a la tienda y actualizaciones por aire. Ahora montas esas cosas desde un servicio CI más unos pocos herramientas.
Anatomía de una cadena de Cordova
| Etapa | Android | iOS |
|---|---|---|
| Ejecutor | Linux | macOS con Xcode 26 |
| Restaurar | cordova prepare (plataformas y plugins de package.json) |
mismo |
| Compilación web | tu empaquetador (Vite, webpack, Angular CLI) en www/ |
mismo |
| Compilación nativa | vía Gradle cordova build android --release |
xcodebuild vía cordova build ios --release --device |
| firmado | subir keystore (.jks) |
distribución de certificado (.p12) y perfil de provisión |
| Artículo | .aab para Google Play |
.ipa para TestFlight y la Tienda de Aplicaciones |
| Cargar | Desarrollador de Google Play API (cuenta de servicio) | Clave de App Store Connect API |
Dos reglas de plataforma se aplican a cada pipeline:
- Desde el 28 de abril de 2026, App Store Connect solo acepta compilaciones realizadas con Xcode 26 y el iOS 26 SDK o posterior. Verifique que su
cordova-iosSu versión debe admitirlo. - Google Play requires AAB uploads for new apps, and raises its minimum target API level every year. Keep
cordova-androidactualizado a su valor predeterminadotargetSdkVersionfollows.
Paso 1: Haga que el proyecto sea reproducible
CI solo puede reconstruir lo que está en el repositorio. Antes de escribir cualquier flujo de trabajo:
- Comitar
package.jsony el archivo de bloqueo. Cordova almacena plataformas y plugins en lacordovasección depackage.jsonpor lo quecordova preparelos restaura. - No cometas
platforms/oplugins/Estos son generados. - Instale Cordova CLI como una dependencia de desarrollo para que cada máquina utilice la misma versión:
bun add -d cordova
- Mueva los valores de firma fuera de
config.xmly en unbuild.jsonque lee secretos en tiempo de compilación (siguiente paso). - que lee secretos en tiempo de compilación (siguiente paso).
.nvmrcopackage.jsonengines.
Pinche la versión de Node.js en
Paso 2: Firma con build.json build.json file. Comita build.template.json con reemplazos, genere el real build.json en CI desde secretos, y nunca cometa el archivo generado:
{
"android": {
"release": {
"keystore": "release.jks",
"storePassword": "${KEYSTORE_STORE_PASSWORD}",
"alias": "upload",
"password": "${KEYSTORE_KEY_PASSWORD}",
"packageType": "bundle"
}
},
"ios": {
"release": {
"codeSignIdentity": "Apple Distribution",
"developmentTeam": "ABCDE12345",
"packageType": "app-store",
"provisioningProfile": "com.example.app AppStore",
"automaticProvisioning": false
}
}
}
El ${...} reemplazos no se expanden por Cordova. El flujo de trabajo a continuación escribe los valores reales con envsubst.
Si no tiene un keystore de Android todavía, cree uno con keytool o en el navegador El generador de keystore de AndroidPara iOS, el Generador de certificado de iOS Paso 3: Un flujo de trabajo de __CAPGO_KEEP_0__ de Acciones .p12 sin una Mac.
Paso 3: Un flujo de trabajo de GitHub
Este flujo de trabajo construye ambas plataformas en paralelo en una etiqueta de versión y las sube a las pistas de prueba internas.
# .github/workflows/cordova-release.yml
name: Cordova release
on:
push:
tags: ['v*']
jobs:
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '17'
- run: bun install --frozen-lockfile
- run: bun run build # outputs to www/
- run: bunx cordova prepare android
- name: Signing files
env:
KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }}
KEYSTORE_STORE_PASSWORD: ${{ secrets.KEYSTORE_STORE_PASSWORD }}
KEYSTORE_KEY_PASSWORD: ${{ secrets.KEYSTORE_KEY_PASSWORD }}
run: |
echo "$KEYSTORE_BASE64" | base64 --decode > release.jks
envsubst < build.template.json > build.json
- run: bunx cordova build android --release --buildConfig=build.json
- uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }}
packageName: com.example.app
releaseFiles: platforms/android/app/build/outputs/bundle/release/app-release.aab
track: internal
status: completed
ios:
runs-on: macos-26
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run build
- run: bunx cordova prepare ios
- name: Install certificate and profile
env:
P12_BASE64: ${{ secrets.IOS_P12_BASE64 }}
P12_PASSWORD: ${{ secrets.IOS_P12_PASSWORD }}
PROFILE_BASE64: ${{ secrets.IOS_PROFILE_BASE64 }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
echo "$P12_BASE64" | base64 --decode > dist.p12
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security set-keychain-settings -lut 21600 build.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security import dist.p12 -k build.keychain -P "$P12_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: -s -k "$KEYCHAIN_PASSWORD" build.keychain
security list-keychains -d user -s build.keychain login.keychain
for dir in "$HOME/Library/MobileDevice/Provisioning Profiles" \
"$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"; do
mkdir -p "$dir"
echo "$PROFILE_BASE64" | base64 --decode > "$dir/app.mobileprovision"
done
cp build.template.json build.json # iOS values hold no secrets
- run: bunx cordova build ios --release --device --buildConfig=build.json
- name: Upload to TestFlight
env:
API_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
API_ISSUER: ${{ secrets.APPLE_ISSUER_ID }}
API_KEY_BASE64: ${{ secrets.APPLE_KEY_CONTENT }}
run: |
mkdir -p ~/.appstoreconnect/private_keys
echo "$API_KEY_BASE64" | base64 --decode > ~/.appstoreconnect/private_keys/AuthKey_${API_KEY_ID}.p8
IPA=$(find platforms/ios/build -name '*.ipa' | head -n 1)
xcrun altool --upload-app -f "$IPA" -t ios --apiKey "$API_KEY_ID" --apiIssuer "$API_ISSUER"
- name: Clean up keychain
if: always()
run: security delete-keychain build.keychain || true
¿Por qué algunas líneas están allí:
- Dos carpetas de perfiles de configuración. Xcode 16 y posteriores leen perfiles de
~/Library/Developer/Xcode/UserData/Provisioning Profiles. Los Xcode más antiguos usaban~/Library/MobileDevice/Provisioning Profiles. Al escribir ambos se evita “No se encontraron perfiles para ‘com.example.app’”. set-key-partition-listevita que macOS solicite acceso a la cadena de claves, lo que haría que un trabajo de CI se quede colgado.- Versión de JDK. Utilice el JDK su
cordova-androiddocumentos de lanzamiento. Las últimas versiones se construyen con JDK 17. - Números de compilación. Incrementar
android-versionCodeyios-CFBundleVersionenconfig.xmlantes de la compilación, por ejemplo, desde el número de ejecución de CI, o las tiendas rechazan la carga como duplicado.
Puedes intercambiar el altool subir para fastlane's upload_to_testflight y la acción de Play para fastlane supply si tu equipo ya utiliza fastlane.
Paso 4: La misma pipeline en otros servicios de CI
Los comandos no cambian entre CIs. Solo la selección del ejecutor y la sintaxis de la clave secreta.
| CI | Ejecutor de Android | Ejecutor de iOS | Notas |
|---|---|---|---|
| GitHub Acciones | ubuntu-latest |
macos-26 / macos-latest |
Los minutos de macOS cuestan más que Linux en repositorios privados |
| GitLab CI | cualquier ejecutor de Linux | ejecutores de macOS hospedados (beta, Premium y Ultimate) o auto-hospedados | imágenes como macos-26-xcode-26 |
| Bitbucket Pipelines | imagen de Docker de Linux | solo Mac auto-hospedado | ver Guía de iOS de Bitbucket |
| Gitea / Forgejo | ejecutor de Linux | Mac autónomo en modo host | ver guía de iOS de Gitea |
| Bitrise | pila de Linux | pila de macOS | envía pasos de Cordova (preparar, archivar) |
| Codemagic | Linux | instancias de Mac mini | documentos de Ionic Cordova en codemagic.yaml |
| Azure DevOps | ubuntu-latest |
macOS-latest |
tareas para instalar certificados y perfiles |
Para una vista por características, lee Comparando plataformas de CI/CD para aplicaciones de Cordova.
Paso 5: Actualizaciones en vivo para Cordova
Live updates let you ship HTML, CSS, and JavaScript fixes without a store review. App Center CodePush ended in March 2025, Appflow Live Updates end on December 31, 2027, and the old community hot code push plugins are unmaintained. A maintained option is Capgo live updates el @capgo/cordova-updater plugin, que utiliza el mismo backend, canales y CLI como el Capacitor actualizador.
actualizador.
- Cordova CLI 12+
cordova-android13+ y/ocordova-ios7+ (el plugin depende de sus configuraciones por defecto)https://localhost/yapp://localhost/y- schemes)
cordova-plugin-ionic-webviewcon él. El navegador de Ionic evita los manipuladores de esquemas de Cordova, por lo que los paquetes descargados no se cargarían.
Instale el plugin
Create the app in Capgo the same way as for Capacitor, then install the plugin with your Capgo app ID:
cordova plugin add @capgo/cordova-updater \
--variable APP_ID=com.example.app \
--variable DEFAULT_CHANNEL=production
cordova prepare android ios
DEFAULT_CHANNEL, UPDATE_URL, and AUTO_UPDATE son variables de instalación opcionales. Ejecuta cordova prepare son variables de instalación opcionales. Ejecute
Confirme cada lanzamiento
After devicereadyel plugin está disponible como cordova.plugins.Updater. Llame notifyAppReady() a cada arranque, o el plugin trata el nuevo paquete como roto y vuelve a cargar:
document.addEventListener('deviceready', async () => {
const { Updater } = cordova.plugins
await Updater.notifyAppReady()
const latest = await Updater.getLatest()
if (latest.url && !latest.error) {
const bundle = await Updater.download({
url: latest.url,
version: latest.version,
checksum: latest.checksum,
})
await Updater.next({ id: bundle.id })
}
})
Subir paquetes desde CI
Agregar un trabajo que construya la capa web y la suba, para cambios web únicamente:
live-update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run build
- run: bunx @capgo/cli@latest bundle upload --channel=production
env:
CAPGO_TOKEN: ${{ secrets.CAPGO_TOKEN }}
Live updates only replace the web bundle. Adding, removing, or upgrading a Cordova plugin still needs a new store build. Capgo compares the native plugins recorded for the live bundle with your project and flags incompatible uploads; see compatibilidad con live updatecompatibilidad de Documentación de actualizaciones de Cordova.
documentos de actualizador de Cordova Capgo Construcción La documentación cubre solo proyectos Capacitor (sube el proyecto nativo producido por cap sync. Los binarios de Cordova siguen construyéndose en su CI como se muestra arriba.
Opcional: migrar a Capacitor más tarde
No necesita dejar Cordova para obtener una pipeline que funcione y actualizaciones en vivo. La migración es una decisión separada, merece la pena cuando:
- Quiere construir iOS sin mantener ejecutores de macOS. Capgo Build compila Capacitor aplicaciones desde un trabajo de CI de Linux.
- Plugins que dependen de usted dejaron de recibir actualizaciones de Cordova, pero tienen equivalentes Capacitor.
- Quieres soporte para Swift Package Manager y versiones actuales del plugin de Gradle para Android sin parchear las plataformas.
La migración conserva su www code. Agrega Capacitor, mueve los plugins (la mayoría de los plugins de Cordova funcionan tal como están), y reemplaza unos pocos que tienen equivalentes nativos Capacitor. Su ID de aplicación Capgo y canales siguen siendo los mismos; solo el plugin de actualizaciones cambia de @capgo/cordova-updater a @capgo/capacitor-updater. Los pasos están en Migrar desde Cordova a Capacitory el solución de Cordova a la página de Capacitor aborda obtener ayuda con ella. Después de la migración, la CI anterior se reduce a una compilación web, cap syncy una build request llamada por plataforma, como se describe en Comparar plataformas de CI/CD para aplicaciones Capacitor.
Solucionar problemas de compilación de Cordova en CI
| Error | Causa y solución |
|---|---|
Current working directory is not a Cordova-based project |
config.xml o www/ faltan. Ejecuta tu build web antes de los comandos de Cordova, o crea un } www/. |
No platforms added to this project |
Plataformas no se muestran en package.json. Ejecuta cordova platform add localmente una vez y haz commit package.json. |
Could not find an installed version of Gradle |
Recientes cordova-android utiliza el wrapper de Gradle. Actualiza la plataforma en lugar de instalar Gradle globalmente. |
Unsupported class file major version |
JDK en el ejecutor no coincide con el de cordova-android espera. Pínalo con setup-java. |
No signing certificate "iOS Distribution" found |
Use Apple Distribution como la identidad, y verificar que el .p12 Rechazado de carga: __CAPGO_KEEP_0__ demasiado antiguo |
errSecInternalComponent |
La imagen del ejecutor utiliza Xcode más antiguo que 26. Selecciona |
| Subida rechazada: SDK demasiado antiguo | como identidad, y verifica que contenga la clave privada. macos-26 o establecer Xcode con xcode-select. |
Subir a Play: Version code has already been used |
Incrementar android-versionCode para cada subida. |
Resumen
Una pila de Cordova en 2026 es un trabajo de CI por plataforma: un ejecutor de Linux para el AAB de Android, un ejecutor de macOS con Xcode 26 para el IPA, secretos descodificados en una clave generada build.jsony claves API para ambos almacenes. Cualquier CI de mainstream puede ejecutarlo. Agregar @capgo/cordova-updater y un bundle upload trabajo para arreglos web únicamente, y tienes los piezas de construcción, almacenamiento y actualizaciones en vivo que Appflow y App Center solían proporcionar. Moverse a Capacitor sigue siendo una opción para más adelante, no un requisito.