Статьи

Быстрый совет для iOS: управление конфигурациями с легкостью

Вы когда-нибудь чувствовали необходимость иметь возможность быстро и легко переключаться между конфигурациями, не путаясь с флагами компилятора или вручную изменяя переменные в вашем проекте? В этом кратком совете я хотел бы показать вам умное решение этой проблемы, используя схемы Xcode и пользовательские конфигурации проекта.


Для некоторых проектов iOS вам нужна возможность быстрого переключения между различными конфигурациями или средами. Распространенный сценарий — это когда приложение iOS связывается с API или веб-службой. Во время разработки вам нужно работать в среде разработки или промежуточной среды. Однако перед выпуском обновления вы, скорее всего, захотите протестировать свое приложение в промежуточной или производственной среде. Переключение между конфигурациями или средами может быть обременительным, особенно если вам нужно часто переключаться.

Самый простой подход состоит в том, чтобы вручную изменять конфигурацию при каждом переключении среды. Это означает изменение флага компилятора или изменение значений в вашем проекте вручную. Этот подход подвержен ошибкам, утомителен и далек от идеала. Лучшее решение — создать индивидуальную конфигурацию для каждой среды. Это включает в себя создание файла конфигурации, который централизует переменные среды и пользовательские схемы XCode. Позвольте мне показать вам, как это работает, создав пример проекта.


Создайте новый проект в XCode, выбрав пустой шаблон приложения из списка шаблонов (рисунок 1). Назовите свое приложение настраиваемым , введите идентификатор компании, установите iPhone для семейства устройств и установите флажок Использовать автоматический подсчет ссылок . Остальные флажки могут быть оставлены непроверенными для этого проекта (рисунок 2). Сообщите Xcode, где вы хотите сохранить проект, и нажмите « Создать» .

Быстрый совет для iOS: управление конфигурациями с легкостью - выбор шаблона проекта
Рисунок 1: Выбор шаблона проекта
Быстрый совет для iOS: управление конфигурациями с легкостью - настройка проекта
Рисунок 2: Настройка проекта

Основная идея этого подхода состоит в том, чтобы знать, какова текущая конфигурация. Что такое конфигурация и где они определены? Вы можете просмотреть список всех конфигураций проекта, выбрав свой проект в Навигаторе проектов и открыв вкладку « Информация » в верхней части. Убедитесь, что вы выбрали свой проект на левой боковой панели, а не цель из списка целей (рисунок 3).

Быстрый совет для iOS: управление конфигурациями с легкостью - конфигурации проекта
Рисунок 3: Конфигурации проекта

В этом уроке мы будем предполагать, что у нас есть среда разработки, промежуточная и производственная среда, с которой нам нужно работать. Начните с создания новой конфигурации для каждой среды, нажав кнопку «плюс» под списком конфигураций. Выберите опцию Duplicate «Debug» Configuration для каждой новой конфигурации (рисунок 4) и присвойте конфигурации соответствующее имя (рисунок 5).

Быстрый совет для iOS: управление конфигурациями с легкостью - дублирование конфигурации отладки
Рисунок 4: Двойная конфигурация отладки
Быстрый совет для iOS: управление конфигурациями с легкостью - три пользовательских конфигурации
Рисунок 5: Три пользовательских конфигурации

Когда приложение работает, мы должны быть в состоянии выяснить, какова текущая конфигурация. Мы можем сделать это, добавив новую запись в целевой файл Info.plist. Выберите целевой файл Info.plist и создайте новую пару ключ-значение. Установите ключ для Configuration и значение для $ {CONFIGURATION} (рисунок 6). Идентификатор CONFIGURATION определяет конфигурацию сборки (например, Development или Staging), которую цель использует для генерации продукта.

Быстрый совет для iOS: управление конфигурациями с легкостью - добавление новой записи в Info.plist
Рисунок 6: Добавление новой записи в Info.plist

После внесения этих изменений мы можем получить текущую конфигурацию в нашем приложении. Чтобы попробовать это, откройте 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;
}

Несмотря на то, что мы создали три пользовательских конфигурации, текущая конфигурация по-прежнему настроена на отладку . Давайте исправим это в следующем разделе.


При создании приложения используется схема Xcode. Схема XCode определяет ряд переменных, используемых при создании продукта. Одна из этих переменных — это конфигурация, которую следует использовать.

Текущая схема XCode отображается в верхнем левом углу панели инструментов XCode. Чтобы легко переключаться между конфигурациями (Development, Staging и т. Д.), Которые мы создали ранее, я рекомендую создать схему Xcode для каждой конфигурации. Щелкните текущую схему, выберите « Новая схема» в появившемся меню и назовите новую схему « Разработка» . Выбрав новую схему, щелкните по схеме и в меню выберите « Редактировать схему» . Выберите Run Configurable на левой панели, откройте вкладку Info вверху и установите для Build Configuration значение Development (рисунок 7). Создайте схему XCode для промежуточных и производственных конфигураций, повторив вышеописанные шаги.

Быстрый совет для iOS: управление конфигурациями с легкостью - создание пользовательской схемы XCode
Рисунок 7: Создание пользовательской схемы XCode

Чтобы упростить управление настройками конфигурации, мы создадим настраиваемый список свойств, который группирует различные настройки конфигурации. Создайте новый список свойств и назовите его Configurations.plist (рисунок 8). Список свойств представляет собой словарь с записью для каждой конфигурации. Каждая запись в списке свойств содержит другой словарь с информацией, специфичной для этой конфигурации (рисунок 9).

Быстрый совет для iOS: управление конфигурациями с легкостью - создание списка свойств для параметров конфигурации
Рисунок 8: Создание нового списка свойств
Быстрый совет для iOS: управление конфигурациями с легкостью - список свойств конфигурации
Рисунок 9: Список свойств конфигурации

Как видите, вы можете добавить любые переменные в Configurations.plist, которые вам нравятся. Вам нужно только убедиться, что каждая запись в списке свойств содержит одинаковые переменные (ключи).


Теперь у вас есть все необходимые элементы для быстрого переключения между конфигурациями. Однако наша работа еще не завершена. Текущая реализация не очень удобна для пользователя (или разработчика). Принимая этот подход, я всегда создаю класс конфигурации, который дает мне легкий доступ к переменным, определенным в 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 могут действительно помочь организовать проект и оптимизировать рабочий процесс разработки. Я надеюсь, что смог убедить вас в ценности этого решения, особенно для сложных проектов с несколькими средами.