Редкое приложение обходится без конфигурационных параметров. Проекты для iOS не исключение. То URL сервера надо указать, то режим отладки или демонстрационный параметр. Обычно их указывают через макросы препроцессора в настройках проекта.
Далее мы добавим свой параметр и посмотрим как им управлять через xcodebuild.
Пару слов о препроцессорах, директивах и макросах
Препроцессор С/С++ (англ. pre processor, предобработчик) — программа, подготавливающая код на языке C/C++ к компиляции.
Директивой препроцессора называется строка в исходном коде, имеющая следующий формат: #ключевое_слово параметры
Наверняка встречали в коде следующие директивы:
- #include — вставка (включение) содержимого произвольного файла;
- #define — макроподстановки;
- #if, #ifdef, #elif, #else, #endif
-
условная компиляция;
Макрос — фрагмент код, которому дали имя. Где бы имя не использовалось, оно заменяется на содержимое макроса. Есть два типа макросов: object-like и function-like. Различие в основном в их форме. Одни похожи на объекты, другие на функции.
Пример object-like макроса
#define BUFFER_SIZE 1024
Пример function-like макроса
#define lang_init() c_init()
Макрос препроцессора в настройках проекта Xcode
Чтобы объявить свой макрос препроцессора в настройках Xcode для этого надо:
Объявить User-Defined параметр
- Если для всех target’ов сразу — то в project setting, если для определенного target’a то в него.
- Выбрать вкладку Build Settings
- Найти Заголовок User Defined
- Добавить нужную настройку
Указать макрос для Apple LLVM 7.0 -Preprocessing
- Ищем Apple LLVM 7.0 -Preprocessing
- В строке с Processor Macros добавляем имя макроса и присваиваем ему значение параметра API_URL=${API_URL}. В данном случае имя макроса совпадает с именем параметра(User-Defined).
В окне сразу подхватится указанная настройка для макроса
Для Debug и Release укзаывайте отдельно.
Теперь в коде мы можем использовать данный макрос
self.firebase = [[Firebase alloc] initWithUrl:API_URL];
Но данный код не скомпилируется т.к. значения макроса не является NSString.
Preprocessor macros string
Тут два решения:
- Модифицировать значения макроса (привести к NSString)
- Использовать макрос для перевода значения в NSString
Для первого решения необходимо «забекслешить» значение макроса — \@\»https://firebaseio.com\»
Для второго написать еще один макрос:
#define STRINGIZE(x) #x #define STRINGIZE2(x) STRINGIZE(x) #define API_URL_LITERAL @ STRINGIZE2(API_URL) ... self.firebase = [[Firebase alloc] initWithUrl:API_URL_LITERAL];
Но для второго варианта опять не все гладко. Двойной слеш (\\) в URL не распознается и получается строка вида «http:» — урезанная.
С двойным слешем бороться не так просто. Предлагают различные варианты эскейпа:
- https:/$()/firebaseio.com
- https:\/\/firebaseio.com
Но у меня ни один не заработал
Можно доработать макрос перевода
#define STRINGIZE(x) "https://" #x
Но этот код как-то «попахивает».
Чтобы избавиться от запаха добавим флаг -traditional для Info.plist Other Preprocessor Flags. Это описано в технической записке от apple — предотвращение конвертирования URL в комментарии
Проброс макросов через xcodebuild
Если у вас есть CI сервер (TeamCity или другой), то вы возможно сталкивались с консольной сборкой проекта. Типичная сборка выглядит так:
xcodebuld --workspace projectName.xcodeproj/project.workspace --sheme projectNameScheme clean build archive ARCHS="armv7 armv7s arm64" ONLY_ACTIVE_ARCH=NO
В очередной сборке мы хотим поменять API_URL, как это сделать?
Существуют несколько параметров для макросов согласно XCODE BUILD SETTING REFERENCE
Вот GCC_PREPROCESSOR_DEFINITIONS нам и нужны. Теперь команда сборки будет выглядит так:
xcodebuld --workspace projectName.xcodeproj/project.workspace --sheme projectNameScheme clean build archive ARCHS="armv7 armv7s arm64" ONLY_ACTIVE_ARCH=NO GCC_PREPROCESSOR_DEFINITIONS = "API_URL='another.url' DEMO = 'NO'"
Список макросов указывается через пробел.
Настройка info.plist?
Если вы решили поменять номер сборки, имя приложения и многое другое, что указывается в info.plist, то это все можно сделать через USER-DEFINED settings. Прописываете свой параметр и добавляете его при сборке
RELEASE_VERSION = 1.1
И добавляете его в info.plist — ${RELEASE_VERSION}
Отличи GCC_PREPROCESSOR_DEFINITIONS от USER_DEFINED settings?
GCC_PREPROCESSOR_DEFINITIONS доступны в коде, а USER_DEFINED settings — нет