DucodeApp se distribuye exclusivamente vía TestFlight Internal Testing a un grupo cerrado de amigos. La automatización está armada con Fastlane sobre la API de App Store Connect.
Cambios en código
│
▼
┌──────────────────────┐
│ fastlane beta │ ← un solo comando
└──────────┬───────────┘
│
┌───────────────────┼─────────────────────┐
│ │ │
▼ ▼ ▼
xcodegen generate bump build # build_app (gym)
│
▼
ipa firmado (.ipa)
│
▼
upload_to_testflight
│
▼
App Store Connect (procesando)
│
▼
TestFlight Internal Testing
│
▼
Tus testers reciben push
| Pieza | Tecnología |
|---|---|
| Generación del proyecto | XcodeGen (project.yml) |
| Build / archive / export | gym (Fastlane wrapper de xcodebuild) |
| Subida a TestFlight | pilot (Fastlane) |
| Auth con App Store Connect | App Store Connect API key (.p8) + KeyID + IssuerID |
| Bump de build number | latest_testflight_build_number + increment_build_number |
| Fallback CLI puro | scripts/archive.sh y scripts/upload.sh |
Configuración:
fastlane/Fastfile— define los lanesfastlane/Appfile— bundle ID, Apple ID, Team IDfastlane/.env—ASC_KEY_IDyASC_ISSUER_ID(gitignored)envs/AuthKey_<KEY_ID>.p8— la API key (gitignored)
Lo relevante del Appfile:
app_identifier("com.ducode.app")
apple_id("ducode@outlook.com")
team_id("9WJGR2VP8X")
itc_team_id("129055091")Hazlo una sola vez por máquina.
brew install fastlane
# o, con Ruby gems
gem install fastlaneVerifica:
fastlane --version- Entra a App Store Connect → Users and Access → Integrations → App Store Connect API.
- Si nunca has usado la API: click "Request Access" (solo el Account Holder puede). Aprueba.
- Click "+" → "Generate API Key".
- Name: Ducode CI (o el que prefieras)
- Access: App Manager
- Click "Generate".
- Descarga el archivo
.p8(importante: solo se descarga una vez).
El nombre del archivo debe respetar el formato
AuthKey_<KEY_ID>.p8. Por ejemplo:AuthKey_AG95PDMY96.p8.
- Copia la Key ID (un identificador corto, ej.
AG95PDMY96). - Copia el Issuer ID (UUID que aparece arriba de la lista de keys).
mkdir -p envs
mv ~/Downloads/AuthKey_AG95PDMY96.p8 envs/envs/ está en .gitignore, no se sube a Git.
cat > fastlane/.env <<EOF
ASC_KEY_ID=AG95PDMY96
ASC_ISSUER_ID=tu-issuer-id-aqui
EOF.env también está en .gitignore.
fastlane latestDebería imprimir el último build number en TestFlight (o 0 si nunca has subido).
El comando que usarás 99% del tiempo. Sube un nuevo build a TestFlight con auto-bump.
fastlane betaPasos internos:
xcodegen generateregenera el proyecto Xcode.- Lee el último build number en TestFlight para la versión actual.
- Incrementa al siguiente.
gymarchiva, exporta IPA consigningStyle: automaticyteamID: 9WJGR2VP8X.pilotsube el IPA a App Store Connect (conskip_waiting_for_build_processing: trueyskip_submission: true).
Salida esperada (~5-10 min):
[18:22:01] [✓] App Store Connect API key cargada
[18:22:05] [✓] Build number bumped: 4
[18:23:30] [✓] Archive completo
[18:25:00] [✓] IPA exportado en ./build_output/DucodeApp.ipa
[18:27:15] [✓] 🚀 Build 4 subido a TestFlight
Mismo flow pero con changelog custom. Sin esa opción, el changelog default es:
"Build automático <N> - YYYY-MM-DD HH:MM"
fastlane beta changelog:"Mejoras en el Coach: streaming más fluido y nuevo reset de conversación."Solo build local sin subir a TestFlight. Útil para validar firma y signing antes de un release.
fastlane buildImprime el último build number subido a TestFlight para la versión actual. Útil para chequear estado sin tocar el repo.
fastlane latestSi Fastlane falla o no quieres instalarlo, los scripts crudos de xcodebuild siguen funcionando:
./scripts/archive.sh # genera build_output/DucodeApp.ipa
./scripts/upload.sh # imprime instrucciones de Transporter / altoolupload.sh no sube automáticamente — te da las instrucciones para arrastrar el IPA en Transporter (la app de Apple) o usar xcrun altool.
TestFlight Internal Testing te da hasta 100 usuarios sin Beta App Review.
- App Store Connect → tu app → TestFlight → Internal Testing → "+".
- Nombra el grupo: "Friends" (o el que prefieras).
- Marca "Enable automatic distribution" si quieres que cada nuevo build se asigne automáticamente al grupo.
Internal Testing requiere que cada tester sea un User del equipo en App Store Connect.
- App Store Connect → Users and Access → "+".
- Email de Apple ID del amigo.
- Asigna rol App Manager o Developer (cualquiera funciona; el rol más restrictivo es Developer).
- Importante: la persona recibirá un email de Apple. Debe aceptar antes de aparecer en la lista de Users del equipo.
- App Store Connect → tu app → TestFlight → Internal Testing → click en el grupo.
- "Testers" → "+".
- Selecciona los Users que quieres incluir.
- Si activaste "automatic distribution", todos los builds futuros les llegan solos.
Si NO activaste automatic distribution:
- TestFlight → tu build → click en él.
- "Internal Groups" → "+".
- Selecciona el grupo "Friends".
Los testers reciben un email/push con un enlace para abrir la app TestFlight (que descargan del App Store si no la tienen) y desde ahí instalan tu app.
Un día típico:
# 1. Hago cambios en código
git checkout -b mejora-coach
# (edito archivos)
# 2. Pruebo localmente en simulador o iPhone (Cmd+R en Xcode)
# 3. Commit
git add .
git commit -m "Streaming del Coach con fallback a respond"
# 4. Subo a TestFlight (1 comando)
fastlane beta changelog:"Coach: streaming más fluido"
# 5. Mientras se procesa (~5-15 min), merge a main
git checkout main
git merge mejora-coach
# 6. Cuando TestFlight termina de procesar, asigno el build al grupo
# (manual desde App Store Connect, o automático si activaste auto-distribution)Los amigos reciben push y pueden instalar.
Internal Testing NO requiere Beta App Review. Cualquier build que subes está disponible para hasta 100 internal testers minutos después de que termine de procesar.
External Testing (público o link compartido) SÍ requiere Beta App Review, que toma 24-48 horas la primera vez y suele ser instantáneo en builds posteriores con el mismo MARKETING_VERSION.
Como DucodeApp es una app personal, no se usa External Testing. Si en algún momento quisieras invitar gente fuera de tu equipo sin agregarlos como Users, tendrías que:
- Crear un External Group.
- Pasar el primer review (la primera vez por versión).
- Invitar por email o public link.
- Verifica que
envs/AuthKey_<KEY_ID>.p8existe y el nombre coincide conASC_KEY_IDenfastlane/.env. - Verifica que
ASC_ISSUER_IDen.envestá bien (UUID del Issuer).
- Verifica que tu API key tiene rol App Manager (no Developer-only).
- Comprueba conectividad y que tu Apple ID tiene acceso al equipo.
- App Store Connect tarda en procesar (5-30 min, a veces más).
- Si en 1 hora no aparece: revisa el email asociado a la cuenta — Apple suele mandar errores ahí (ITMS-90xxx).
- Errores típicos:
- ITMS-90683: missing usage description en Info.plist.
- ITMS-90713: missing entitlement (HealthKit no habilitado en App ID).
El lane lee latest_testflight_build_number y suma 1. Si dos personas suben en paralelo puede haber colisión. Espera a que el primer build termine de procesar y reintenta.
signingStyle: automaticrequiere que tu Apple ID tenga membresía Apple Developer activa.- En Xcode: Settings → Accounts → tu Apple ID → Manage Certificates → confirma que hay un Distribution Certificate vigente.
- Si nada funciona: borra DerivedData (
rm -rf ~/Library/Developer/Xcode/DerivedData) y reintenta.
- Apple rechaza imágenes con canal alpha. Verifica
DucodeApp/Assets.xcassets/AppIcon.appiconset— todos los PNG deben ser opacos. - Una forma rápida: abrir cada PNG en Preview → Export → desmarcar Alpha.
- Habilita HealthKit en el App ID
com.ducode.appen developer.apple.com → Identifiers. - Refresca provisioning profiles: borra DerivedData y recompila, o
fastlane match nukesi usas match (no es el caso aquí).
- Verifica que XcodeGen está instalado:
which xcodegen. - Si no:
brew install xcodegen.
Build subido más reciente: 1.0.0 (3).
MARKETING_VERSION y CURRENT_PROJECT_VERSION se definen en project.yml. El lane beta solo bumpa el CURRENT_PROJECT_VERSION (build number); para subir el MARKETING_VERSION hay que editarlo manualmente y commitear.
- SETUP.md — pasos previos (Whoop, Apple Intelligence, HealthKit App ID)
- ARCHITECTURE.md — visión general de la app