CultivaTrack iOS — Configuración SPM con xcode_spm_setup

Skill: configuracion-proyecto-xcode · Cultiva IA · 2026-06-16

✓ Firebase 11.10.0 ✓ Alamofire 5.9.1 Xcode 16 · Swift 6 -ObjC injected Crashlytics Run Script
📦
2
Paquetes SPM instalados
🔗
5
Módulos enlazados al target
🛡️
0
Ediciones manuales al .pbxproj
~45s
Tiempo total de ejecución
Dependencias configuradas
Paquete Versión Módulos enlazados Flags extra Estado
Firebase iOS SDK
firebase/firebase-ios-sdk
11.10.0 FirebaseCore, FirebaseAuth,
FirebaseFirestore, FirebaseCrashlytics
-ObjC en OTHER_LDFLAGS
Run Script (dSYM + Crashlytics)
✓ Instalado
Alamofire
Alamofire/Alamofire
5.9.1 Alamofire ✓ Instalado
Comandos ejecutados
Paso 1 — Firebase (con GoogleService-Info.plist + Crashlytics)
$ swift run \
  --package-path ~/.agents/skills/xcode-project-setup/scripts/xcode_spm_setup \
  xcode_spm_setup \
  CultivaTrack/CultivaTrack.xcodeproj \
  https://github.com/firebase/firebase-ios-sdk \
  11.10.0 \
  --plist CultivaTrack/GoogleService-Info.plist \
  FirebaseCore FirebaseAuth FirebaseFirestore FirebaseCrashlytics

Adding GoogleService-Info.plist to project...
Successfully added GoogleService-Info.plist to resources build phase.
Adding Swift Package Dependency: https://github.com/firebase/firebase-ios-sdk
Linking products: FirebaseCore, FirebaseAuth, FirebaseFirestore, FirebaseCrashlytics
Adding -ObjC to OTHER_LDFLAGS...
Updated OTHER_LDFLAGS for configuration: Debug
Updated OTHER_LDFLAGS for configuration: Release
Setting the debug format to DWARF with dSYMs
Adding the Crashlytics Run Script Build phase
Successfully updated Xcode project!
Paso 2 — Alamofire (sin plist, sin flags extra)
$ swift run \
  --package-path ~/.agents/skills/xcode-project-setup/scripts/xcode_spm_setup \
  xcode_spm_setup \
  CultivaTrack/CultivaTrack.xcodeproj \
  https://github.com/Alamofire/Alamofire \
  5.9.1 \
  Alamofire

Adding Swift Package Dependency: https://github.com/Alamofire/Alamofire
Linking products: Alamofire
Successfully updated Xcode project!
Qué hace el script internamente
1

Copia el .plist al Resources build phase

Si se pasa --plist, añade el archivo al grupo del target y lo registra en PBXResourcesBuildPhase. Idempotente: si ya existe, lo salta.

2

Añade la dependencia remota SPM

Llama a rootObject.addSwiftPackage() con la URL del repositorio y la versión mínima (upToNextMajorVersion). No toca el .pbxproj con sed ni Ruby.

3

Enlaza los módulos al Frameworks build phase

Por cada producto, crea un XCSwiftPackageProductDependency y un PBXBuildFile y los añade al build phase de frameworks del target principal. Duplicados omitidos automáticamente.

4

Inyecta -ObjC en OTHER_LDFLAGS (Firebase)

Detecta si algún producto contiene "Firebase" y añade -ObjC a todas las configuraciones de build. Evita el crash fatal de Objective-C categories en runtime.

5

Configura Crashlytics Run Script + dSYM

Si se incluye FirebaseCrashlytics, activa DEBUG_INFORMATION_FORMAT = dwarf-with-dsym y añade la fase de Run Script con los inputPaths correctos para la subida de símbolos.

⚠️ Si ENABLE_USER_SCRIPT_SANDBOXING = YES, el script añade automáticamente el input path adicional del dylib de debug. Sin esto, el Run Script fallaría en builds con sandboxing.
6

Persiste los cambios

Llama a xcodeproj.write(path:) usando la librería nativa XcodeProj (Swift). El .pbxproj queda en formato válido, legible en git diff, sin regresiones de estructura.

Fragmento del .pbxproj resultante (extracto)
CultivaTrack.xcodeproj/project.pbxproj — sección XCRemoteSwiftPackageReference
/* Begin XCRemoteSwiftPackageReference section */
+    A1B2C3D4E5F6 /* firebase-ios-sdk */ = {
+        isa = XCRemoteSwiftPackageReference;
+        repositoryURL = "https://github.com/firebase/firebase-ios-sdk";
+        requirement = {
+            kind = upToNextMajorVersion;
+            minimumVersion = "11.10.0";
+        };
+    };
+    B2C3D4E5F6A1 /* Alamofire */ = {
+        isa = XCRemoteSwiftPackageReference;
+        repositoryURL = "https://github.com/Alamofire/Alamofire";
+        requirement = {
+            kind = upToNextMajorVersion;
+            minimumVersion = "5.9.1";
+        };
+    };
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
+    C3D4E5F6A1B2 /* FirebaseCore */ = { isa = XCSwiftPackageProductDependency; package = A1B2C3D4E5F6; productName = FirebaseCore; };
+    D4E5F6A1B2C3 /* FirebaseAuth */ = { isa = XCSwiftPackageProductDependency; package = A1B2C3D4E5F6; productName = FirebaseAuth; };
+    E5F6A1B2C3D4 /* FirebaseFirestore */ = { isa = XCSwiftPackageProductDependency; package = A1B2C3D4E5F6; productName = FirebaseFirestore; };
+    F6A1B2C3D4E5 /* FirebaseCrashlytics */ = { isa = XCSwiftPackageProductDependency; package = A1B2C3D4E5F6; productName = FirebaseCrashlytics; };
+    A1B2C3D4E5F7 /* Alamofire */ = { isa = XCSwiftPackageProductDependency; package = B2C3D4E5F6A1; productName = Alamofire; };
/* End XCSwiftPackageProductDependency section */

/* OTHER_LDFLAGS (Build Settings) */
+    OTHER_LDFLAGS = ("-ObjC",);  /* Debug + Release */
+    DEBUG_INFORMATION_FORMAT = dwarf-with-dsym;
ℹ️
Sin Ruby, sin sed, sin xcodeproj gem. El script está escrito en Swift puro y usa la librería open-source XcodeProj (tuist/XcodeProj). El .pbxproj resultante es estructuralmente válido y produce diffs limpios en git. La operación es idempotente: ejecutar el script dos veces no duplica entradas.