Blog
iOS KMP Jun 3, 2026

XcodeGen: generar .xcodeproj desde project.yml sin conflictos en Git

Por qué gestionar .xcodeproj a mano causa conflictos en Git y cómo XcodeGen regenera el proyecto desde YAML declarativo en cada checkout.

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 a sources.

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.yml está en iosApp/. Cambia al directorio correcto o usa --spec.
  • Build settings en configuraciones: Los settings dentro de la sección configurations tienen 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 resources si 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.