Automatizando la configuración de tus compilaciones en Xcode

A la hora de crear un nuevo proyecto en Xcode para nuestro siguiente gran éxito, disponemos de una nueva oportunidad para hacer las cosas bien antes de que perdamos el norte entre tanta configuración, parámetro, librería, gestor de dependencias, etc.

En esta entrada vamos a aprender cómo crear tantos esquemas de ejecución (Schemes) como deseemos, en función de los distintos entornos planteados para la aplicación: desarrollo, staging, beta, producción, etc. Definiendo su configuración en ficheros xcconfig.

Definiendo la configuración de la aplicación mediante archivos xcconfig

Existen diversas alternativas para la configuración básica de nuestra aplicación: identificador del paquete (Bundle ID), nombre de la app, icono, servidor al que reventar a peticiones, GoogleService-Info.plist del que extraer la configuración de conexión a Google para sepa todo lo que hacemos, etc. Pero hoy vamos a hablar de cómo establecer dicha configuración a través de ficheros xcconfig.

Añadir al proyecto

Para añadir un fichero de configuración xcconfig al proyecto debemos ir a File/New/File o CMD+N y hacer scroll buscando como inútiles escribir en el cuadro de búsqueda (está habilitada la escritura por defecto cuando se abre la ventana). Dependiendo de cuantas plantillas tengamos y con qué nombre deberemos especificar más o menos carácteres, en un caso normal escribiendo “con” ya debería aparecer resaltada la opción Configuration Settings File. Pulsamos Next, escogemos un buen nombre para el archivo (Development, Staging y Production suelen ser mis favoritos) y lo guardamos en un sitio adecuado (¿carpeta Configurations?).

Xcode detectará automáticamente los ficheros de tipo xcconfig que añadamos al proyecto, y nos los
ofrecerá allá donde podamos usarlos.

Ficheros xcconfig

Los ficheros xcconfig permiten, de forma espartana, definir una serie de parámetros/variables que más tarde podremos recoger para configurar múltiples aspectos de nuestra aplicación. Su sintaxis básica es muy simple:

// App
APP_BUNDLE_ID = com.aratech.vayapasada
APP_NAME = vayapasada
APP_ICON = Cutre

// Firebase (te está observando)
FIREBASE_FILE_CONFIGURATION = GoogleService-Info.plist

// Servidor de la muerte
SERVER_URL = https:\/\/vayapasada.aratech.com //Ojo al SKAP de barras

// Etc

 

Como véis es sencillo, pese a ello se pueden hacer algunas que otras cosas naz**, os dejo un enlace a la guía no oficial.

Por resumir posiblidades:

  1. Herencia con otros xcconfig para no repetirnos
  2. Asignación condicional en función de la plataforma, sistema operativo, SDK, etc.
  3. Sustitución de variables
  4. Más y mejor

Asignando configuraciones

Para que el contenido de los ficheros xcconfig surja efecto, deberemos asignárselo a la Build Configuration de nuestra elección, en este caso vamos a crear tantas como entornos se hayan definido para la aplicación, dos por cada una, para nuestras compilaciones de depuración o lanzamiento.

Build Configurations

Si, una vez abierto en Xcode, pinchamos en el proyecto, veremos en la segunda columna por la izquierda el propio proyecto, así como los distintos Targets. Al hacer click en el proyecto se nos abren dos pestañas: Info y Build Settings. Dentro de Info nos interesa el desplegable Configurations, en él veremos las habituales que se generan por defecto al crear un nuevo proyecto: Debug y Release. Estas configuraciones contienen mucha de la información relativa a cómo se compilará nuestra aplicación: mensajes de depuración, optimización y velocidad de la compilación, etc. Y es el punto de partida de cualquiera que queramos crear.

 

Para generar nuestra configuración personalizada deberemos duplicar una existente. Las configuraciones por defecto, como comentábamos, son Debug y Release. La estrategia a seguir es duplicar cada una para cada entorno. Usaremos DebugMiNuevoEntorno para compilar la aplicación en depuración (simulador y dispositivos conectados), y ReleaseMiNuevoEntorno para archivar y subir a la AppStore (pudiendo así subir al TestFlight la versión apuntando al servidor de desarrollo/staging por ejemplo).

 

Configuraciones basadas en Configuration File

Una vez creadas todas aquellas Build Configurations que queramos/necesitemos/nuestro jefe nos exija, deberemos asignarles los ficheros de configuración xcconfig que previamente hemos generado, de dónde tomarán aquellos datos que hayamos definido.

Partiendo de las propiedades del proyecto, donde hemos duplicado las configuraciones por defecto para generar las propias, pulsando en la flecha a la izquierda de cada nombre estaremos expandiendo las filas en las que se especifica, para cada Target, qué configuración se debe aplicar. En nuestro caso, deberemos seleccionar aquella que corresponda (ver imagen).

 

De esta manera, si seleccionamos el Target, pestaña Build Settings, y bajamos hasta el final, podremos ver todos los parámetros de configuración que hayamos definido en los ficheros xcconfig.

Haciendo caso omiso a nuestros parámetros

Una vez definidos los parámetros de configuración que nos permitan automatizar los ajustes de los distintos entornos, debemos hacer uso de ellos. Dependiendo de qué queramos configurar, tendremos que hacerlo desde un sitio u otro. Mediante la notación $(NOMBRE_PARAMETRO), al igual que con los ya existentes por defecto, estaremos estableciendo el valor de dicho parámetro en el ajuste.

 

Build Settings

Como sabéis (o no), en cada Target de Xcode, pestaña Build Settings, podemos editar los parametros de la compilación, y, efectivamente, referenciar los definidos en los ficheros xcconfig. Los ajustes básicos personalizados son:

 

Posibilidad Ajuste Valor
Identificador de la aplicación Product Bundle Identifier $(APP_BUNDLE_ID)
Icono de la aplicación Asset Catalog App Icon Set Name $(APP_ICON)

 

Info.plist

Igualmente, hay ciertos ajustes que hay que personalizar a través del fichero Info.plist. Esta vez en la pestaña Info

Posibilidad Clave Valor
Nombre de la aplicación Bundle name $(APP_NAME)

Código

Para el resto de cuestiones que se necesiten personalizar, deberemos recoger los valores de los
parámetros desde el código. Para ello hay que trasladarlos al Bundle a través del fichero Info.plist. Si, por ejemplo, hemos personalizado el nombre del fichero que contendrá la configuración de conexión con Firebase, creamos una nueva entrada en el Property List con nombre Firebase y tipo diccionario. Dentro de este diccionario nos definimos la propiedad configurationFile de tipo String, y establecemos como valor lo que hubiésemos escrito en el fichero xcconfig, en el caso del ejemplo $(FIREBASE_FILE_CONFIGURATION).

<!-- Info.plist -->
<key>Firebase</key>
    <dict>
        <key>configurationFile</key>
        <string>$(FIREBASE_CONFIGURATION_FILE)</string>
    </dict>

 

Una vez trasladados los parámetros que queramos recoger en el código, el acceso será a través de:

func infoFor<T>(key: String) -> T? {
    return (Bundle.main.infoDictionary?[key] as? T)
}

Así por ejemplo, para establecer la configuración con Firebase:

guard let firebase: [String: Any] = infoFor(key: "Firebase"),
    let firebaseConfigurationFileName = firebase["configurationFile"] as? String else {
    log.error("No configuration information found for Firebase"); return
}
        
guard let firebaseConfigurationFilePath = Bundle.main.path(forResource: firebaseConfigurationFileName, ofType: "plist") else {
    log.error("No firebase configuration file found at \(firebaseConfigurationFileName)"); return
}
        
guard let firebaseOptions = FirebaseOptions(contentsOfFile: firebaseConfigurationFilePath) else {
    log.error("Could not init Firebase Options with contents of file \(firebaseConfigurationFilePath)"); return
}
        
FirebaseApp.configure(options: firebaseOptions)

Esquemas de ejecución (Scheme)

Por último, es bastante interesante y conveniente definir distintos esquemas de ejecución, de forma que solo tendremos que seleccionar el adecuado para que se aplique automáticamente la configuración.

Si pulsamos en el nombre del Target en la barra superior, al lado del dispositivo en el que lo ejecutaríamos, mientras pulsamos la tecla opción, abriremos la configuración del Scheme seleccionado. Uno de los botones inferiores es Manage Schemes, donde aparecen todos nuestros esquemas de ejecución. Cada esquema define una configuración para: Build, Run, Test, Profile, Analyze y Archive. Y es ahí donde podemos indicar de qué configuración queremos que beba en cada caso.

Creación de esquemas

Para crear un nuevo esquema partimos de la lista de esquemas (alternativamente Product/Scheme/Manage Schemes). Pulsando en el simbolo + en la parte inferior izquierda abrimos la creación de un nuevo esquema de ejecución, donde elegiremos nuestro Target, la app en este caso, y el nombre del esquema. La nomenclatura del esquema dependerá de cómo cada uno se aclare mejor. En mi caso prefiero llamarlos Develop, Staging y dejar con el nombre de la aplicación el esquema destinado a producción. Pero esa elección es vuestra.

Configuración de esquemas

Una vez creados tantos esquemas como sean necesarios, haciendo doble click en cada uno desde la lista, o con opción + click como hemos comentado, accederemos al menú para su configuración.

Por defecto Xcode establece las siguientes configuraciones

Opción Build Configuration
Run Debug
Test Debug
Profile Release
Analyze Debug
Archive Release

 

Trasladado, por ejemplo, a nuestro recién creado esquema de desarrollo

Opción Build Configuration
Run Debug Development
Test Debug Development
Profile Release Development
Analyze Debug Development
Archive Release Development

 

Seleccionando un esquema de ejecución

Ahora que ya están creados los esquemas, solo hay que elegir el que se desee ejecutar y darle al play. En función de lo que hagamos con él se aplicará la configuración Debug o Release.

Recapitulando

Hemos visto como, gracias a los esquemas de ejecución, las configuraciones de compilación, y los ficheros *xcconfig*, podemos automatizar gran parte de la configuración de nuestro proyecto. Desde la conexión al servidor, identificador del paquete, nombre de la aplicación, icono, cuentas de servicios externos, claves, etc. Ésto, además, nos permite abrir el abanico de posibilidades en la integración continua (CI), así como la distribución mediante TestFlight de distintas versiones de la misma aplicación.

Estos son solo un par de ejemplos, el límite, como casi siempre, en vuestras ideas.

Bibliografía

https://www.appcoda.com/xcconfig-guide/

https://hackernoon.com/a-cleaner-way-to-organize-your-ios-debug-development-and-release-distributions-6b5eb6a48356

https://medium.com/flawless-app-stories/manage-different-environments-in-your-swift-project-with-ease-659f7f3fb1a6

https://savvyapps.com/blog/using-testflight-to-distribute-multiple-versions-ios-app

https://pewpewthespells.com/blog/xcconfig_guide.html#VarAssignInherit

https://burcugeneci.wordpress.com/2015/09/24/using-xcconfig-files-and-custom-schemes-for-your-xcode-project/

Author: Nicolás Landa

USO DE COOKIES

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.

ACEPTAR
Aviso de cookies