TL;DR: XcodeGen genera el .xcodeproj a partir de un fichero project.yml declarativo, eliminando conflictos en Git y automatizando la configuración de proyectos iOS, especialmente necesario en KMP donde el proyecto se regenera frecuentemente.
Mantener un .xcodeproj bajo control de versiones es una fuente constante de conflictos. Cada cambio de configuración, target o esquema genera un diff binario ilegible en Git. En un proyecto Kotlin Multiplatform donde el .xcodeproj se regenera frecuentemente, el problema se amplifica: o bien lo ignoras en .gitignore y no tienes forma reproducible de generarlo, o lo commiteas y lidias con merges que rompen el proyecto.
XcodeGen resuelve esto declarando la estructura del proyecto en un fichero YAML (project.yml) que Git entiende, genera el .xcodeproj automáticamente y permite tenerlo versionado sin conflictos.
Instalación
brew install xcodegen
Verificar la instalación:
xcodegen --version
Estructura básica de project.yml
El fichero project.yml debe estar en la raíz del proyecto iOS. Estructura mínima:
name: MyApp
options:
bundleIdPrefix: com.company
deploymentTarget: "14.0"
targets:
MyApp:
type: application
platform: iOS
sources:
- path: Sources
settings:
DEVELOPMENT_TEAM: "ABCD123456"
CODE_SIGN_IDENTITY: "Apple Development"
- name: nombre del proyecto Xcode que se generará.
- options.bundleIdPrefix: prefijo usado para construir bundle identifiers.
- options.deploymentTarget: versión mínima de iOS soportada.
- targets: diccionario de targets. Cada target debe tener
type,platform, y las rutas asources.
Definir dos configuraciones de build con bundle ID y nombre distintos
Para poder instalar Debug y Release simultáneamente en un dispositivo, asigna un PRODUCT_BUNDLE_IDENTIFIER y PRODUCT_NAME distintos a cada configuración:
name: MyApp
options:
bundleIdPrefix: com.company
deploymentTarget: "14.0"
targets:
MyApp:
type: application
platform: iOS
sources:
- path: Sources
settings:
DEVELOPMENT_TEAM: "ABCD123456"
CODE_SIGN_IDENTITY: "Apple Development"
configurations:
Debug:
settings:
PRODUCT_BUNDLE_IDENTIFIER: com.company.app.debug
PRODUCT_NAME: MyApp Debug
GCC_PREPROCESSOR_DEFINITIONS: DEBUG=1
Release:
settings:
PRODUCT_BUNDLE_IDENTIFIER: com.company.app
PRODUCT_NAME: MyApp
GCC_PREPROCESSOR_DEFINITIONS: ""
La sección configurations sobrescribe los settings globales. Al instalar, verás dos apps en el simulador o dispositivo: “MyApp Debug” (bundle com.company.app.debug) y “MyApp” (bundle com.company.app).
Generar el proyecto
xcodegen generate
XcodeGen busca project.yml en el directorio actual. Si está en otra ruta:
xcodegen generate --spec path/to/project.yml
Resultado: se crea (o regenera) el .xcodeproj con todas las configuraciones declaradas en el YAML.
Integración con .gitignore
Añade el .xcodeproj al .gitignore:
.xcodeproj/
Luego, cada miembro del equipo regenera el proyecto tras clonar:
git clone <repo>
cd iosApp
xcodegen generate
O automatiza esto en un hook pre-commit o en el proceso de setup del proyecto.
CocoaPods y XcodeGen
XcodeGen no gestiona CocoaPods automáticamente. Si el proyecto usa Pods:
xcodegen generate
pod install
Hay que ejecutar pod install después de xcodegen generate. Si quieres automatizarlo:
#!/bin/bash
xcodegen generate
pod install
Guarda como script y ejecuta desde el setup.
Trampas
- Ruta de project.yml: XcodeGen busca en el directorio actual por defecto. En un KMP, el
project.ymlestá eniosApp/. Cambia al directorio correcto o usa--spec. - Build settings en configuraciones: Los settings dentro de la sección
configurationstienen precedencia sobre los settings globales del target. No duplicar configuración global si ya está en una configuración específica. - Esquemas personalizados: XcodeGen genera esquemas automáticamente para cada target. Si necesitas esquemas con build phases personalizadas, hay que declararlos en YAML bajo la sección
schemes. - Assets y resources: Declara las rutas explícitamente bajo
resourcessi XcodeGen no las detecta automáticamente.
Ejemplo completo: KMP con dos configuraciones
name: GasGuru
options:
bundleIdPrefix: com.company.gasguru
deploymentTarget: "14.0"
usesTabs: false
indentWidth: 2
targets:
GasGuruApp:
type: application
platform: iOS
sources:
- path: Sources
resources:
- path: Resources
settings:
DEVELOPMENT_TEAM: "ABCD123456"
CODE_SIGN_IDENTITY: "Apple Development"
IPHONEOS_DEPLOYMENT_TARGET: "14.0"
configurations:
Debug:
settings:
PRODUCT_BUNDLE_IDENTIFIER: com.company.gasguru.debug
PRODUCT_NAME: GasGuru Debug
GCC_PREPROCESSOR_DEFINITIONS: DEBUG=1
SWIFT_OPTIMIZATION_LEVEL: "-Onone"
Release:
settings:
PRODUCT_BUNDLE_IDENTIFIER: com.company.gasguru
PRODUCT_NAME: GasGuru
SWIFT_OPTIMIZATION_LEVEL: "-O"
XcodeGen transforma la gestión de proyectos iOS en algo declarativo y reproducible. Una vez integrado, el .xcodeproj es código generado — no un artefacto que cause conflictos en Git.