Consejo rápido de iOS: administra configuraciones con facilidad
Spanish (Español) translation by Juliana Carvajal (you can also view the original English article)
¿Alguna vez has sentido la necesidad de poder cambiar rápida y fácilmente entre configuraciones sin meterte con los indicadores del compilador o modificar manualmente las variables en tu proyecto? En este consejo rápido, me gustaría mostrarte una solución inteligente a este problema aprovechando los esquemas de Xcode y las configuraciones de proyectos personalizadas.
El problema
Para algunos proyectos de iOS, necesitas la capacidad de cambiar rápidamente entre diferentes configuraciones o entornos. Un escenario común es cuando una aplicación de iOS se comunica con una API o un servicio web. Durante el desarrollo, debes trabajar en un entorno de desarrollo o de ensayo. Sin embargo, antes de lanzar una actualización, lo más probable es que desees probar tu aplicación en un entorno de ensayo o de producción. Cambiar entre configuraciones o entornos puede ser engorroso, especialmente si necesitas realizar este cambio con frecuencia.
La solución
El método más sencillo es modificar manualmente la configuración cada vez que cambias de entorno. Esto significa modificar un indicador del compilador o modificar manualmente los valores en tu proyecto. Este enfoque es propenso a errores, tedioso y está lejos de ser ideal. Una mejor solución es crear una configuración personalizada para cada entorno. Esto implica la creación de un archivo de configuración que centralice las variables de entorno y los esquemas Xcode personalizados. Déjame mostrarte cómo funciona esto creando un proyecto de muestra.
1. Configuración del proyecto
Crea un nuevo proyecto en Xcode seleccionando la plantilla Aplicación vacía de la lista de plantillas (figura 1). Asigna un nombre a tu aplicación Configurable, ingresa un identificador de empresa, configura el iPhone para la familia de dispositivos y marca Usar recuento automático de referencias. El resto de las casillas de verificación se pueden dejar sin marcar para este proyecto (figura 2). Dile a Xcode dónde deseas guardar el proyecto y haz clic en Crear.






2. Edita Info.plist
Paso 1: agrega configuraciones personalizadas
La idea clave de este enfoque es saber cuál es la configuración actual. ¿Qué es una configuración y dónde se definen? Puedes ver una lista de todas las configuraciones del proyecto seleccionando tu proyecto en el Navegador de proyectos y abriendo la pestaña Información en la parte superior. Asegúrate de haber seleccionado tu proyecto en la barra lateral izquierda y no un objetivo de la lista de objetivos (figura 3).



En este tutorial, asumiremos que tenemos un entorno de desarrollo, preparación y producción con el que debemos trabajar. Comienza creando una nueva configuración para cada entorno haciendo clic en el botón más debajo de la lista de configuraciones. Selecciona la opción Duplicar configuración "Depurar" para cada nueva configuración (figura 4) y asigna un nombre apropiado a la configuración (figura 5).






Paso 2: edita Info.plist
Cuando la aplicación se está ejecutando, necesitamos saber cuál es la configuración actual. Podemos hacer esto agregando una nueva entrada al archivo Info.plist del objetivo. Selecciona el archivo Info.plist del destino y crea un nuevo par clave-valor. Establece la clave en Configuración y el valor en ${CONFIGURACIÓN} (figura 6). El identificador de CONFIGURACIÓN identifica la configuración de compilación (por ejemplo, Desarrollo o Puesta en escena) que el objetivo usa para generar el producto.



Paso 3: obtén la configuración actual
Con estos cambios realizados, ahora podemos recuperar la configuración actual en nuestra aplicación. Para probar esto, abre
MTAppDelegate.m y actualiza la application:didFinishLaunchingWithOptions: como se muestra a continuación. Para acceder a la información en Info.plist, le pedimos al paquete de aplicaciones principal su infoDiccionario. Del diccionario de información, tomamos el valor de la clave de configuración que agregamos y lo registramos en la consola de Xcode. Crea y ejecuta tu aplicación para ver qué está registrado en la consola de Xcode.
1 |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { |
2 |
NSString *configuration = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"Configuration"]; |
3 |
|
4 |
NSLog(@"Current Configuration > %@", configuration); |
5 |
|
6 |
// Initialize Window
|
7 |
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; |
8 |
|
9 |
// Configure Window
|
10 |
self.window.backgroundColor = [UIColor whiteColor]; |
11 |
[self.window makeKeyAndVisible]; |
12 |
return YES; |
13 |
}
|
A pesar de que creamos tres configuraciones personalizadas, la configuración actual todavía está establecida en Debug. Reparemos eso en la siguiente sección.
2. Esquemas personalizados de Xcode
Al crear una aplicación, se utiliza un esquema de Xcode. Un esquema de Xcode define una serie de variables que se utilizarán al crear el producto. Una de esas variables es la configuración que se debe utilizar.
El esquema actual de Xcode se muestra en la parte superior izquierda de la barra de herramientas de Xcode. Para cambiar fácilmente entre las configuraciones (Desarrollo, Puesta en escena, etc.) que creamos anteriormente, recomiendo crear un esquema de Xcode para cada configuración. Haz clic en el esquema actual, selecciona Nuevo esquema en el menú que aparece y asigna el nombre Desarrollo al nuevo esquema. Con el nuevo esquema seleccionado, haz clic en el esquema y selecciona Editar esquema en el menú. Selecciona Ejecutar configurable en el panel izquierdo, abre la pestaña Información en la parte superior y establece la Configuración de compilación en Desarrollo (figura 7). Crea un esquema de Xcode para las configuraciones de puesta en escena y producción repitiendo los pasos anteriores.



3. Crea un archivo de configuración
Para facilitar la gestión de los ajustes de configuración, crearemos una lista de propiedades personalizada que agrupa los distintos ajustes de configuración. Crea una nueva lista de propiedades y asígnale el nombre Configurations.plist (figura 8). La lista de propiedades es un diccionario con una entrada para cada configuración. Cada entrada en la lista de propiedades contiene otro diccionario con información específica para esa configuración (figura 9).






Como puedes ver, puedes agregar las variables que desees a Configurations.plist. Solo necesitas asegurarte de que cada entrada en la lista de propiedades contenga las mismas variables (claves).
4. Clase de configuración
Ahora tienes todos los elementos necesarios para cambiar rápidamente entre configuraciones. Sin embargo, nuestro trabajo aún no ha terminado. La implementación actual no es muy amigable para el usuario (o desarrollador). Al adoptar este enfoque, siempre creo una clase de configuración que me da fácil acceso a las variables definidas en
Configurations.plist. La clase de configuración obtiene la configuración actual, carga Configurations.plist y proporciona un fácil acceso a las variables. Echa un vistazo a la clase MTConfiguration a continuación para ver a qué me refiero.
1 |
#import <Foundation/Foundation.h>
|
2 |
|
3 |
@interface MTConfiguration : NSObject |
4 |
|
5 |
#pragma mark -
|
6 |
+ (NSString *)configuration; |
7 |
|
8 |
#pragma mark -
|
9 |
+ (NSString *)APIEndpoint; |
10 |
+ (BOOL)isLoggingEnabled; |
11 |
|
12 |
@end
|
1 |
#import "MTConfiguration.h"
|
2 |
|
3 |
#define MTConfigurationAPIEndpoint @"MTAPIEndpoint"
|
4 |
#define MTConfigurationLoggingEnabled @"MTLoggingEnabled"
|
5 |
|
6 |
@interface MTConfiguration () |
7 |
|
8 |
@property (copy, nonatomic) NSString *configuration; |
9 |
@property (nonatomic, strong) NSDictionary *variables; |
10 |
|
11 |
@end
|
12 |
|
13 |
@implementation MTConfiguration |
14 |
|
15 |
#pragma mark -
|
16 |
#pragma mark Shared Configuration
|
17 |
+ (MTConfiguration *)sharedConfiguration { |
18 |
static MTConfiguration *_sharedConfiguration = nil; |
19 |
static dispatch_once_t onceToken; |
20 |
dispatch_once(&onceToken, ^{ |
21 |
_sharedConfiguration = [[self alloc] init]; |
22 |
});
|
23 |
|
24 |
return _sharedConfiguration; |
25 |
}
|
26 |
|
27 |
#pragma mark -
|
28 |
#pragma mark Private Initialization
|
29 |
- (id)init { |
30 |
self = [super init]; |
31 |
|
32 |
if (self) { |
33 |
// Fetch Current Configuration
|
34 |
NSBundle *mainBundle = [NSBundle mainBundle]; |
35 |
self.configuration = [[mainBundle infoDictionary] objectForKey:@"Configuration"]; |
36 |
|
37 |
// Load Configurations
|
38 |
NSString *path = [mainBundle pathForResource:@"Configurations" ofType:@"plist"]; |
39 |
NSDictionary *configurations = [NSDictionary dictionaryWithContentsOfFile:path]; |
40 |
|
41 |
// Load Variables for Current Configuration
|
42 |
self.variables = [configurations objectForKey:self.configuration]; |
43 |
}
|
44 |
|
45 |
return self; |
46 |
}
|
47 |
|
48 |
#pragma mark -
|
49 |
+ (NSString *)configuration { |
50 |
return [[MTConfiguration sharedConfiguration] configuration]; |
51 |
}
|
52 |
|
53 |
#pragma mark -
|
54 |
+ (NSString *)APIEndpoint { |
55 |
MTConfiguration *sharedConfiguration = [MTConfiguration sharedConfiguration]; |
56 |
|
57 |
if (sharedConfiguration.variables) { |
58 |
return [sharedConfiguration.variables objectForKey:MTConfigurationAPIEndpoint]; |
59 |
}
|
60 |
|
61 |
return nil; |
62 |
}
|
63 |
|
64 |
+ (BOOL)isLoggingEnabled { |
65 |
MTConfiguration *sharedConfiguration = [MTConfiguration sharedConfiguration]; |
66 |
|
67 |
if (sharedConfiguration.variables) { |
68 |
return [[sharedConfiguration.variables objectForKey:MTConfigurationLoggingEnabled] boolValue]; |
69 |
}
|
70 |
|
71 |
return NO; |
72 |
}
|
73 |
|
74 |
@end
|
La clase MTConfiguration proporciona un fácil acceso a las variables almacenadas en Configurations.plist. Cambiar entre configuraciones ahora es tan fácil como seleccionar el esquema Xcode correcto. A pesar de que puede parecer bastante trabajo desde el principio, puedo asegurarte que te ahorrarás una enorme cantidad de tiempo y frustración en el futuro.
Para probar nuestra solución, importa el archivo de encabezado de la clase MTConfiguration en MTAppDelegate.m y actualiza el método application:didFinishLaunchingWithOptions: como se muestra a continuación.
1 |
#import "MTAppDelegate.h"
|
2 |
|
3 |
#import "MTConfiguration.h"
|
1 |
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { |
2 |
NSLog(@"Configuration > %@", [MTConfiguration configuration]); |
3 |
|
4 |
NSLog(@"API Endpoint > %@", [MTConfiguration APIEndpoint]); |
5 |
NSLog(@"Is Logging Enabled > %i", [MTConfiguration isLoggingEnabled]); |
6 |
|
7 |
// Initialize Window
|
8 |
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; |
9 |
|
10 |
// Configure Window
|
11 |
self.window.backgroundColor = [UIColor whiteColor]; |
12 |
[self.window makeKeyAndVisible]; |
13 |
return YES; |
14 |
}
|
Conclusión
Las configuraciones personalizadas y los esquemas de Xcode realmente pueden ayudar a organizar un proyecto y agilizar tu flujo de trabajo de desarrollo. Espero haberte podido convencer del valor de esta solución, especialmente para proyectos complejos con múltiples entornos.



