Вы когда-нибудь чувствовали необходимость иметь возможность быстро и легко переключаться между конфигурациями, не путаясь с флагами компилятора или вручную изменяя переменные в вашем проекте? В этом кратком совете я хотел бы показать вам умное решение этой проблемы, используя схемы Xcode и пользовательские конфигурации проекта.
Проблема
Для некоторых проектов iOS вам нужна возможность быстрого переключения между различными конфигурациями или средами. Распространенный сценарий — это когда приложение iOS связывается с API или веб-службой. Во время разработки вам нужно работать в среде разработки или промежуточной среды. Однако перед выпуском обновления вы, скорее всего, захотите протестировать свое приложение в промежуточной или производственной среде. Переключение между конфигурациями или средами может быть обременительным, особенно если вам нужно часто переключаться.
Решение
Самый простой подход состоит в том, чтобы вручную изменять конфигурацию при каждом переключении среды. Это означает изменение флага компилятора или изменение значений в вашем проекте вручную. Этот подход подвержен ошибкам, утомителен и далек от идеала. Лучшее решение — создать индивидуальную конфигурацию для каждой среды. Это включает в себя создание файла конфигурации, который централизует переменные среды и пользовательские схемы XCode. Позвольте мне показать вам, как это работает, создав пример проекта.
1. Настройка проекта
Создайте новый проект в XCode, выбрав пустой шаблон приложения из списка шаблонов (рисунок 1). Назовите свое приложение настраиваемым , введите идентификатор компании, установите iPhone для семейства устройств и установите флажок Использовать автоматический подсчет ссылок . Остальные флажки могут быть оставлены непроверенными для этого проекта (рисунок 2). Сообщите Xcode, где вы хотите сохранить проект, и нажмите « Создать» .
2. Изменить Info.plist
Шаг 1: Добавить пользовательские конфигурации
Основная идея этого подхода состоит в том, чтобы знать, какова текущая конфигурация. Что такое конфигурация и где они определены? Вы можете просмотреть список всех конфигураций проекта, выбрав свой проект в Навигаторе проектов и открыв вкладку « Информация » в верхней части. Убедитесь, что вы выбрали свой проект на левой боковой панели, а не цель из списка целей (рисунок 3).
В этом уроке мы будем предполагать, что у нас есть среда разработки, промежуточная и производственная среда, с которой нам нужно работать. Начните с создания новой конфигурации для каждой среды, нажав кнопку «плюс» под списком конфигураций. Выберите опцию Duplicate «Debug» Configuration для каждой новой конфигурации (рисунок 4) и присвойте конфигурации соответствующее имя (рисунок 5).
Шаг 2: Редактировать Info.plist
Когда приложение работает, мы должны быть в состоянии выяснить, какова текущая конфигурация. Мы можем сделать это, добавив новую запись в целевой файл Info.plist. Выберите целевой файл Info.plist и создайте новую пару ключ-значение. Установите ключ для Configuration и значение для $ {CONFIGURATION} (рисунок 6). Идентификатор CONFIGURATION определяет конфигурацию сборки (например, Development или Staging), которую цель использует для генерации продукта.
Шаг 3: Получить текущую конфигурацию
После внесения этих изменений мы можем получить текущую конфигурацию в нашем приложении. Чтобы попробовать это, откройте MTAppDelegate.m и обновите application:didFinishLaunchingWithOptions:
как показано ниже. Чтобы получить доступ к информации в Info.plist, мы запрашиваем основной пакет приложения для его infoDictionary
. Из информационного словаря мы берем значение добавленного нами ключа конфигурации и записываем его в консоль Xcode. Создайте и запустите ваше приложение, чтобы увидеть, что вошло в консоль Xcode.
01
02
03
04
05
06
07
08
09
10
11
12
13
|
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *configuration = [[[NSBundle mainBundle] infoDictionary] objectForKey:@»Configuration»];
NSLog(@»Current Configuration > %@», configuration);
// Initialize Window
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Configure Window
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
|
Несмотря на то, что мы создали три пользовательских конфигурации, текущая конфигурация по-прежнему настроена на отладку . Давайте исправим это в следующем разделе.
2. Пользовательские схемы XCode
При создании приложения используется схема Xcode. Схема XCode определяет ряд переменных, используемых при создании продукта. Одна из этих переменных — это конфигурация, которую следует использовать.
Текущая схема XCode отображается в верхнем левом углу панели инструментов XCode. Чтобы легко переключаться между конфигурациями (Development, Staging и т. Д.), Которые мы создали ранее, я рекомендую создать схему Xcode для каждой конфигурации. Щелкните текущую схему, выберите « Новая схема» в появившемся меню и назовите новую схему « Разработка» . Выбрав новую схему, щелкните по схеме и в меню выберите « Редактировать схему» . Выберите Run Configurable на левой панели, откройте вкладку Info вверху и установите для Build Configuration значение Development (рисунок 7). Создайте схему XCode для промежуточных и производственных конфигураций, повторив вышеописанные шаги.
3. Создайте файл конфигурации
Чтобы упростить управление настройками конфигурации, мы создадим настраиваемый список свойств, который группирует различные настройки конфигурации. Создайте новый список свойств и назовите его Configurations.plist (рисунок 8). Список свойств представляет собой словарь с записью для каждой конфигурации. Каждая запись в списке свойств содержит другой словарь с информацией, специфичной для этой конфигурации (рисунок 9).
Как видите, вы можете добавить любые переменные в Configurations.plist, которые вам нравятся. Вам нужно только убедиться, что каждая запись в списке свойств содержит одинаковые переменные (ключи).
4. Класс конфигурации
Теперь у вас есть все необходимые элементы для быстрого переключения между конфигурациями. Однако наша работа еще не завершена. Текущая реализация не очень удобна для пользователя (или разработчика). Принимая этот подход, я всегда создаю класс конфигурации, который дает мне легкий доступ к переменным, определенным в Configurations.plist . Класс конфигурации извлекает текущую конфигурацию, загружает Configurations.plist и обеспечивает легкий доступ к переменным. Взгляните на класс MTConfiguration
ниже, чтобы понять, что я имею в виду.
01
02
03
04
05
06
07
08
09
10
11
12
|
#import <Foundation/Foundation.h>
@interface MTConfiguration : NSObject
#pragma mark —
+ (NSString *)configuration;
#pragma mark —
+ (NSString *)APIEndpoint;
+ (BOOL)isLoggingEnabled;
@end
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
#import «MTConfiguration.h»
#define MTConfigurationAPIEndpoint @»MTAPIEndpoint»
#define MTConfigurationLoggingEnabled @»MTLoggingEnabled»
@interface MTConfiguration ()
@property (copy, nonatomic) NSString *configuration;
@property (nonatomic, strong) NSDictionary *variables;
@end
@implementation MTConfiguration
#pragma mark —
#pragma mark Shared Configuration
+ (MTConfiguration *)sharedConfiguration {
static MTConfiguration *_sharedConfiguration = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedConfiguration = [[self alloc] init];
});
return _sharedConfiguration;
}
#pragma mark —
#pragma mark Private Initialization
— (id)init {
self = [super init];
if (self) {
// Fetch Current Configuration
NSBundle *mainBundle = [NSBundle mainBundle];
self.configuration = [[mainBundle infoDictionary] objectForKey:@»Configuration»];
// Load Configurations
NSString *path = [mainBundle pathForResource:@»Configurations» ofType:@»plist»];
NSDictionary *configurations = [NSDictionary dictionaryWithContentsOfFile:path];
// Load Variables for Current Configuration
self.variables = [configurations objectForKey:self.configuration];
}
return self;
}
#pragma mark —
+ (NSString *)configuration {
return [[MTConfiguration sharedConfiguration] configuration];
}
#pragma mark —
+ (NSString *)APIEndpoint {
MTConfiguration *sharedConfiguration = [MTConfiguration sharedConfiguration];
if (sharedConfiguration.variables) {
return [sharedConfiguration.variables objectForKey:MTConfigurationAPIEndpoint];
}
return nil;
}
+ (BOOL)isLoggingEnabled {
MTConfiguration *sharedConfiguration = [MTConfiguration sharedConfiguration];
if (sharedConfiguration.variables) {
return [[sharedConfiguration.variables objectForKey:MTConfigurationLoggingEnabled] boolValue];
}
return NO;
}
@end
|
Класс MTConfiguration
обеспечивает легкий доступ к переменным, хранящимся в Configurations.plist . Переключение между конфигурациями теперь так же просто, как выбор правильной схемы XCode. Хотя это может показаться довольно сложной задачей, я могу заверить вас, что это сэкономит вам огромное количество времени — и разочарование — в будущем.
Чтобы протестировать наше решение, импортируйте файл MTConfiguration
класса MTConfiguration в MTAppDelegate.m и обновите application:didFinishLaunchingWithOptions:
метод, как показано ниже.
1
2
3
|
#import «MTAppDelegate.h»
#import «MTConfiguration.h»
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@»Configuration > %@», [MTConfiguration configuration]);
NSLog(@»API Endpoint > %@», [MTConfiguration APIEndpoint]);
NSLog(@»Is Logging Enabled > %i», [MTConfiguration isLoggingEnabled]);
// Initialize Window
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Configure Window
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
|
Вывод
Пользовательские конфигурации и схемы XCode могут действительно помочь организовать проект и оптимизировать рабочий процесс разработки. Я надеюсь, что смог убедить вас в ценности этого решения, особенно для сложных проектов с несколькими средами.