Configurar CI/CD para apps de Capacitor puede ser complejo y llevar mucho tiempo. Esto es lo que necesitas saber:
Recomendado para nuevos builds: Usa Capgo Build
Ahora recomendamos usar Capgo Build con el Capgo CLI para builds nativos de Capacitor. Esta guía de Fastlane es para equipos que mantienen pipelines de GitHub Actions existentes, pero para nuevos builds de iOS se recomienda usar Capgo CLI para no tener que gestionar Fastlane, runners de Xcode, certificados y scripts de upload.
Capgo Build para CI/CD por Capgo
Olvídate de mantener Fastlane, runners de Xcode, certificados, provisioning profiles y scripts de upload. Build de Capgo ejecuta builds nativos de iOS firmados desde tu pipeline de CI/CD actual:
- Funciona con tu pipeline: Dispara Capgo Build desde GitHub Actions, GitLab CI, Jenkins o scripts locales tras tu web build y
npx cap sync. - Firma mediante secretos de CI: Mantén las claves de App Store Connect, certificados, provisioning profiles, contraseñas y team IDs en tus propios secretos de CI.
- Sin mantenimiento de runners nativos: Capgo Build ofrece entornos de build de Apple gestionados, para que no tengas que administrar runners de macOS, imágenes de Xcode o lanes de Fastlane.
- Artifacts y envío: Descarga artifacts firmados para QA o envía builds de release mediante Capgo CLI.
Precios
- Los planes de Capgo desde $12/mes
- Incluye actualizaciones OTA y unos 15 Native Build al mes
- Los minutos de build extra se cobran por minuto mediante créditos
Configura Capgo Build en tu CI/CD
Guía de configuración manual
Esto es lo que tienes que hacer:
Continuous Delivery para iOS con Fastlane, GitHub Actions y certificados
Requisitos
Antes de continuar con el tutorial:
- Asegúrate de tener Fastlane instalado en tu máquina de desarrollo.
- Asegúrate de formar parte del programa de desarrolladores de iOS.
Información importante sobre el precio

https://github.com/features/actions
El servicio es ‘gratis’ hasta el límite, según la máquina elegida.
Vamos a utilizar un macOS máquina, en la captura puedes ver su precio y límites (precios vigentes al crear el tutorial, podrían cambiar en el futuro)
Una vez vistos los requisitos y precios, continuemos.
Nota: En este post asumo que ya tienes la app creada en App Store Connect. ¡Fastlane se encargará de copiar la información importante!
Qué aprenderás en el tutorial
Pasos a seguir en el post
- Uso de App Store Connect API con Fastlane
- Requisitos:
- Crear una clave API de App Store Connect
- Usar una clave API de App Store Connect
- Requisitos:
- Copiar archivos de Fastlane
- Configurar GitHub Actions
1. Uso de App Store Connect API con Fastlane
A partir de febrero de 2021, todos los usuarios deben usar la autenticación de dos factores o la verificación en dos pasos para iniciar sesión en App Store Connect. Esta capa adicional de seguridad para tu Apple ID ayuda a garantizar que seas la única persona que pueda acceder a tu cuenta.
Desde Soporte de Apple
Requisitos
Para que Fastlane pueda usar API de App Store Connect para subir tu app, necesitas proporcionar lo siguiente tres detalles:
- ID de emisor
- ID de clave
- Archivo de clave o contenido de la clave
Cómo obtener una clave API de App Store Connect
Para generar claves, debes tener permisos de Admin en App Store Connect. Si no los tienes, puedes redirigir a la persona encargada a este artículo.
-
Inicia sesión en App Store Connect.
-
Selecciona Usuarios y acceso.

3 — Selecciona la pestaña Integración.

- Haz clic en Generate API Key o en el botón Add (+).

- Asigna un nombre a la clave. El nombre es solo para tu referencia y no forma parte de la clave.

6 — En Access, selecciona el rol para la clave. Los roles que se aplican a las claves son los mismos que se aplican a los usuarios de tu equipo. Ver permisos de rol. Recomendamos seleccionar Gestor de apps.
- Haz clic en Generar.
El acceso de una clave API no se puede limitar a apps específicas.
En la página aparecerán el nombre de la nueva clave, su ID, un enlace de descarga y más info.

Aquí puedes obtener los tres datos necesarios.
<1> ID del issue. (APPLE_ISSUER_ID secreto)
<2> ID de la clave. (APPLE_KEY_ID secreto)
<3> Haz clic en “Download API Key” para descargar tu clave privada API. El enlace de descarga solo aparece si aún no se ha descargado la clave privada. Apple no conserva una copia de la clave privada, así que solo podrás descargarla una vez.
🔴 Guarda tu clave privada en un lugar seguro. Nunca compartas tus claves ni las guardes en un repositorio code, ni las incluyas en code del lado del cliente.
Usar una clave API de App Store Connect
El archivo API Key (el archivo p8 que descargaste), el key ID y el issuer ID son necesarios para crear el token JWT de autorización. Hay varias formas de pasar esta información a Fastlane. Elegí usar la nueva action de Fastlane app_store_connect_api_key. Puedes conocer otras formas en la documentación de Fastlane. Te muestro este método porque creo que es la forma más fácil de trabajar con la mayoría de los CI que hay, donde puedes configurar variables de entorno.
Por favor, convierte el archivo p8 que descargaste a Base64 y guárdalo como un secret (APPLE_KEY_CONTENT).
base64 -i APPLE_KEY_CONTENT.p8 | pbcopy
¡Ahora podemos gestionar App Store Connect con Fastlane usando la clave API, genial!
2. Certificados
Abre Xcode y ve a Configuración > Cuentas > Apple ID > Equipos y selecciona tu equipo.

Haz clic en Gestionar certificados.
Si aún no has creado un certificado, puedes crear uno nuevo.
Haz clic en + y selecciona Distribución de Apple

Luego tienes que ir al Keychain para descargar el certificado como un .p12 archivo.
Para ello, tienes que ir al Keychain y cambiar al login keychain y luego a la pestaña Mis certificados.

Luego puedes seleccionar el certificado que quieras descargar. (Fíjate en la fecha del certificado)
Y luego haz clic derecho en la clave privada del certificado y selecciona Exportar.
Elige el formato de archivo Intercambio de información personal (.p12).
Esto descargará el certificado como un .p12 archivo.
Abre el archivo en la terminal y usa este comando para convertirlo a Base64:
base64 -i BUILD_CERTIFICATE.p12 | pbcopy
Esto se convertirá en tu BUILD_CERTIFICATE_BASE64 secreto. Además, cuando se te solicite, introduce la contraseña del certificado. Esta será tu P12_PASSWORD secreto.
3. Perfiles de aprovisionamiento
Abrir Apple Developer y selecciona el equipo correcto.
Luego crea un nuevo perfil haciendo clic en +

Y selecciona App Store Connect.

Luego debes seleccionar la app correcta; cuidado, no puedes usar wildcard o la firma fallará.

Selecciona el certificado que creaste antes (revisa la fecha de expiración, debe ser el mismo día y mes que hoy) y haz clic en Continuar.

Finalmente, ponle nombre al perfil y haz clic en Generar.
El nombre se usará para identificar el perfil en Fastlane, con el valor de
APPLE_PROFILE_NAME.

Puedes descargar el perfil como un .mobileprovision archivo.

Por favor, convierte el perfil a Base64 y guárdalo como un secreto (BUILD_PROVISION_PROFILE_BASE64).
base64 -i BUILD_PROVISION_PROFILE.mobileprovision | pbcopy
4. Copiar los archivos de Fastlane
Fastlane es una librería de Ruby creada para automatizar tareas comunes de desarrollo móvil. Con Fastlane, puedes configurar “lanes” personalizadas que agrupan una serie de “actions” que realizan tareas que normalmente harías usando Android Studio. Puedes hacer mucho con Fastlane, pero para este tutorial usaremos solo unas pocas acciones principales.
Crea la carpeta Fastlane en la raíz de tu proyecto Capacitor/Ionic y añade el Fastfile allí:
- Carpeta:
<project-root>/fastlane/ - Archivo:
<project-root>/fastlane/Fastfile
Esto está al mismo nivel que package.json, capacitor.config.*, y la ios/ la carpeta. No la crees dentro de ios/App/.
platform :ios do
desc 'Export ipa and submit to TestFlight'
lane :beta do
keychain_info = { keychain_name: "ios-build-#{Time.now.to_i}.keychain", keychain_password: SecureRandom.uuid }
begin
setup_signing(keychain_info)
bump_build_number
build_app_with_signing(keychain_info)
submit_to_testflight
ensure
cleanup_keychain(keychain_info)
end
end
private_lane :setup_signing do |options|
create_keychain(
name: options[:keychain_name],
password: options[:keychain_password],
unlock: true,
timeout: 0,
lock_when_sleeps: false,
add_to_search_list: true
)
import_cert(options)
install_profile
update_project_settings
end
lane :bump_build_number do
file = File.read('../package.json')
data_hash = JSON.parse(file)
api_key = app_store_connect_api_key(
key_id: ENV['APPLE_KEY_ID'],
issuer_id: ENV['APPLE_ISSUER_ID'],
key_content: ENV['APPLE_KEY_CONTENT'],
is_key_content_base64: true,
duration: 1200,
in_house: false
)
build_num = app_store_build_number(
api_key: api_key,
app_identifier: ENV['BUNDLE_IDENTIFIER'],
live: false
)
build_num = build_num + 1
UI.message("Bumped build number to #{build_num}")
increment_build_number(
build_number: build_num,
xcodeproj: "./ios/App/App.xcodeproj",
skip_info_plist: true
)
end
private_lane :import_cert do |options|
cert_path = "#{Dir.tmpdir}/build_certificate.p12"
File.write(cert_path, Base64.decode64(ENV['BUILD_CERTIFICATE_BASE64']))
import_certificate(
certificate_path: cert_path,
certificate_password: ENV['P12_PASSWORD'] || "",
keychain_name: options[:keychain_name],
keychain_password: options[:keychain_password],
log_output: true
)
File.delete(cert_path)
end
private_lane :cleanup_keychain do |options|
delete_keychain(
name: options[:keychain_name]
)
end
private_lane :install_profile do
profile_path = "#{Dir.tmpdir}/build_pp.mobileprovision"
File.write(profile_path, Base64.decode64(ENV['BUILD_PROVISION_PROFILE_BASE64']))
UI.user_error!("Failed to create provisioning profile at #{profile_path}") unless File.exist?(profile_path)
ENV['PROVISIONING_PROFILE_PATH'] = profile_path
install_provisioning_profile(path: profile_path)
File.delete(profile_path)
end
private_lane :update_project_settings do
update_code_signing_settings(
use_automatic_signing: false,
path: "./ios/App/App.xcodeproj",
code_sign_identity: "iPhone Distribution",
profile_name: ENV['APPLE_PROFILE_NAME'],
bundle_identifier: ENV['BUNDLE_IDENTIFIER'],
team_id: ENV['APP_STORE_CONNECT_TEAM_ID']
)
update_project_team(
path: "./ios/App/App.xcodeproj",
teamid: ENV['APP_STORE_CONNECT_TEAM_ID']
)
end
private_lane :build_app_with_signing do |options|
unlock_keychain(
path: options[:keychain_name],
password: options[:keychain_password],
set_default: false
)
build_app(
workspace: "./ios/App/App.xcworkspace",
scheme: "App",
configuration: "Release",
export_method: "app-store",
output_name: "App.ipa",
export_options: {
provisioningProfiles: {
ENV['BUNDLE_IDENTIFIER'] => ENV['APPLE_PROFILE_NAME']
}
},
xcargs: "-verbose",
buildlog_path: "./build_logs",
export_xcargs: "-allowProvisioningUpdates",
)
end
private_lane :submit_to_testflight do
api_key = app_store_connect_api_key(
key_id: ENV['APPLE_KEY_ID'],
issuer_id: ENV['APPLE_ISSUER_ID'],
key_content: ENV['APPLE_KEY_CONTENT'],
is_key_content_base64: true,
duration: 1200,
in_house: false
)
pilot(
api_key: api_key,
skip_waiting_for_build_processing: true,
skip_submission: true,
distribute_external: false,
notify_external_testers: false,
ipa: "./App.ipa"
)
end
end
5. Configuración de secrets
GitHub Actions usa los secrets del repositorio que configures en el siguiente paso. Solo necesitas un .env archivo local si quieres ejecutar o probar Fastlane desde tu propia máquina.
Para pruebas locales, crea <project-root>/fastlane/.env junto al Fastfile. No hagas commit de este archivo. Añade fastlane/.env a tu .gitignore primero (o verifica que ya esté ignorado). Aquí tienes un ejemplo:
APP_STORE_CONNECT_TEAM_ID=UVTJ336J2D
BUNDLE_IDENTIFIER=ee.forgr.testfastlane
# See previous section for these secrets
BUILD_CERTIFICATE_BASE64=
BUILD_PROVISION_PROFILE_BASE64=
APPLE_KEY_ID=
APPLE_ISSUER_ID=
APPLE_KEY_CONTENT=
P12_PASSWORD=
APPLE_PROFILE_NAME=
Obtener el APP_STORE_CONNECT_TEAM_ID
Ve a Centro de Desarrolladores y desplázate hacia abajo hasta Membership details sección.
El Team ID es el valor que debes configurar en APP_STORE_CONNECT_TEAM_ID secreto.
Obtener el BUNDLE_IDENTIFIER
- Abre Xcode
- Haz doble clic en
Appen el project navigator - Luego haz clic en la pestaña
Signing and Capabilities - Copia el valor de
Bundle identifier. Este es el valor que debes configurar enBUNDLE_IDENTIFIERsecreto.
6. Procesamiento de la build
En GitHub Actions, se te factura según los minutos que has usado para ejecutar tu workflow de CI/CD. Según mi experiencia, tarda unos 10–15 minutos antes de que la build se procese en App Store Connect.
Para proyectos privados, el coste estimado por build puede llegar a $0,08/min x 15 min = $1,2, o más, según la configuración y dependencias de tu proyecto.
Si te preocupan los costes en proyectos privados, puedes configurar skip_waiting_for_build_processing a true. Esto ahorrará minutos de build al no tener que esperar a que App Store Connect termine de procesar el build.
Sin embargo, hay una contrapartida: tendrás que actualizar manualmente la información de cumplimiento de tu app en App Store Connect antes de distribuir el build a los usuarios.
Esta optimización es útil principalmente para proyectos privados donde los minutos de build cuestan dinero. En proyectos públicos o gratuitos, los minutos de build son gratis, así que no hace falta activar este ajuste. Consulta la página de precios de GitHub página de precios para más detalles.
7. Configurar GitHub Actions
Configurar los secrets de GitHub
Por favor, copia los secrets del .env archivo y pégalos en los secrets del repositorio de GitHub.
Ve a Configuración > Secrets y variables > Acciones > Nuevo secreto de repositorio
2. BUILD_CERTIFICATE_BASE64 - Certificado en Base64.
3. BUILD_PROVISION_PROFILE_BASE64 - Provisioning profile en Base64.
4. BUNDLE_IDENTIFIER - el bundle identifier de tu app.
5. APPLE_KEY_ID — API Key de App Store Connect 🔺Key ID.
6. APPLE_ISSUER_ID — API Key de App Store Connect 🔺Issuer ID.
7. APPLE_KEY_CONTENT — App Store Connect API Key 🔺 Contenido de la clave .p8, compruébalo
8. Configurar el archivo de workflow de GitHub
Crea un directorio GitHub workflow.
cd .github/workflows
Dentro de la workflow carpeta, crea un archivo llamado build-upload-ios.ymly añade lo siguiente.
name: Build source code on ios
on:
push:
tags:
- '*'
jobs:
build_ios:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v6
- name: Set Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
- name: Install dependencies
id: install_code
run: npm ci
- name: Build
id: build_code
run: npm run build
- uses: actions/cache@v5
with:
path: ios/App/Pods
key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }}
restore-keys: |
${{ runner.os }}-pods-
- name: Sync
id: sync_code
run: npx cap sync
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.0'
bundler-cache: true
- uses: maierj/fastlane-action@v3.1.0
env:
APP_STORE_CONNECT_TEAM_ID: ${{ secrets.APP_STORE_CONNECT_TEAM_ID }}
BUNDLE_IDENTIFIER: ${{ secrets.BUNDLE_IDENTIFIER }}
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
BUILD_PROVISION_PROFILE_BASE64: ${{ secrets.BUILD_PROVISION_PROFILE_BASE64 }}
APPLE_KEY_ID: ${{ secrets.APPLE_KEY_ID }}
APPLE_ISSUER_ID: ${{ secrets.APPLE_ISSUER_ID }}
APPLE_KEY_CONTENT: ${{ secrets.APPLE_KEY_CONTENT }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
APPLE_PROFILE_NAME: ${{ secrets.APPLE_PROFILE_NAME }}
with:
lane: ios beta
- name: Upload release bundle
uses: actions/upload-artifact@v6
with:
name: ios-release
path: ./App.ipa
retention-days: 10
Este workflow debe ejecutarse tras cada GitHub etiqueta, si necesitas automatizar el tag, consulta Build y release automáticos con GitHub actions primero.
Este workflow descargará tus deps de NodeJS, las instalará y hará el build de tu app JS.
Cada vez que envíes un nuevo commit, se generará un release en TestFlight.
Tu app no necesita usar Ionic, solo la base de Capacitor es obligatoria. Puede tener módulos antiguos de Cordova, pero se recomienda usar el plugin JS de Capacitor.
8. Ejecutar el workflow
Crear un commit
Haz un commit, y verás el workflow activo en el repositorio.
Ejecutar el workflow
Haz push de los nuevos commits a la rama main o development para ejecutar el workflow.

En unos minutos, el build debería estar disponible en tu dashboard de App Store Connect.

9. ¿Puedo desplegar desde mi máquina local?
Sí, puedes hacerlo sin esfuerzo.
Puedes usar Xcode para compilar y firmar tu app, como siempre.
Artículos relacionados
Guías de configuración CI/CD
- Build automático de Capacitor Android con GitHub Actions - Configuración completa de CI/CD para Android
- Build y release automáticos con GitHub Actions - Tutorial de pipeline CI/CD completo
- Gestiona builds de Dev y Prod con GitHub Actions - Gestión de entornos
- Build automático de Capacitor para iOS con Match - Alternativa usando Fastlane Match
Plataformas CI/CD alternativas
- Build con GitLab CI - Alternativa para GitLab
- Build con CodeMagic - Guía de configuración de CodeMagic
Live Updates y despliegue
- Documentación de Capgo Live Updates - Añade actualizaciones OTA a tu app
- Integración CI/CD con Capgo - Integra Live Updates en tu pipeline
Gracias
Este blog se basa en los siguientes artículos:
- Entrega continua para iOS con Fastlane y acciones de GitHub
- Documentación de Fastlane
- Este mensaje de GitHub de @mrogunlana
- Esta documentación de GitHub
Continúa desde el build automático de iOS de Capacitor con acciones de GitHub con certificado
Si estás usando Build automático de Capacitor para iOS con GitHub actions y certificado para planificar la automatización de CI/CD, conéctalo con CI/CD de Capgo para el flujo de trabajo del producto en Capgo CI/CD, Native Builds de Capgo para el flujo de trabajo del producto en Capgo Native Builds, Integraciones de Capgo para el flujo de trabajo del producto en Capgo Integraciones, Integración CI/CD para los detalles de implementación de CI/CD Integration, y Integración con GitHub Actions para los detalles de implementación de GitHub Actions Integration.