Swift: как использовать флаги PREPROCESSOR (например, `#if DEBUG`) для реализации ключей API?

95

В Objective-Cэто иногда полезно использовать статические строковые константы для определения альтернативных ключей API (например, дифференцируется между RELEASE и ключами DEBUG для аналитических пакетов, как MixPanel, Flurry или Crashlytics):

#if DEBUG
static NSString *const API_KEY = @"KEY_A";
#else
static NSString *const API_KEY = @"KEY_B";
#endif

а потом...

[Analytics startSession:API_KEY];

Как это соотносится с Swift, если компилятор Swift больше не использует препроцессор?

умный бит
источник

Ответы:

161

Apple включила полную поддержку флагов препроцессора Swift начиная с Xcode 8 , поэтому больше нет необходимости устанавливать эти значения в «Другие флаги Swift».

Новый параметр называется «Условия активной компиляции», который обеспечивает поддержку верхнего уровня для Swift-эквивалента флагов препроцессора. Вы используете его точно так же, как и «Other Swift Flags», за исключением того, что нет необходимости добавлять значение с помощью «-D» (так что это просто немного чище).

Из примечаний к выпуску Xcode 8 :

Active Compilation Conditions- это новый параметр сборки для передачи флагов условной компиляции компилятору Swift. Каждый элемент значения этого параметра передается в swiftc с префиксом -D точно так же, как элементы Preprocessor Macrosпередаются в clang с тем же префиксом. (22457329)

введите описание изображения здесь

Вы используете указанную выше настройку так:

#if DEBUG
    let accessToken = "DebugAccessToken"
#else
    let accessToken = "ProductionAccessToken"
#endif
Дэн Лёвенгерц
источник
2
Примечание: вы не должны указывать = 1 или любое другое значение =. Скорее, вам нужно просто указать имя флага. :]
JRG-Developer
@ JRG-Developer Я не возражаю, но я не уверен, как здесь применим ваш комментарий.
Дэн
9
Это полезный ответ, но, исходя из опыта работы с Objective-C (как я полагаю, многие разработчики iOS), я предположил, что мне нужно указать =1... Я потерял немного времени, пытаясь понять, почему он не работает когда я это сделал. Итак, я подумал, что поделюсь этим лакомым кусочком, чтобы помочь следующему парню. :] В любом случае, спасибо за ваш ответ здесь!
JRG-Developer
1
@ JRG-Developer, @Dan Loewenherz Я настроил как DEBUGin, так Active Compilation Conditionsи DEBUG=1in, Preprocessor Macrosи эта конфигурация вообще не работает. Следует удалить DEBUG=1?? Не ясно из приведенных выше комментариев.
Bhavin_m
2
@DanLoewenherz Вы абсолютно правы. Я установил «DEBUG» для конфигурации архива в моих целевых настройках, поэтому каждый раз, когда он запускает оператор Debug и никогда не запускает условие выпуска. Всем, кто сталкивается с проблемой, Build Configurationсначала проверьте свою цель . Проверьте этот ответ stackoverflow.com/questions/9063100/… для получения дополнительной информации.
Bhavin_m
131

ОБНОВЛЕНО: Xcode 8 теперь поддерживает это автоматически, см. Ответ @ DanLoewenherz выше.

До Xcode 8 вы могли использовать макросы таким же образом:

#if DEBUG
let apiKey = "KEY_A"
#else
let apiKey = "KEY_B"
#endif

Однако для того, чтобы Swift мог их подобрать, вам необходимо установить «Other Swift Flags» в настройках сборки вашей цели:

  • Откройте настройки сборки для вашей цели
  • Искать "другие быстрые флаги"
  • Добавьте макросы, которые хотите использовать, перед -Dфлагом

введите описание изображения здесь

умный бит
источник
вы сделали мой день! у меня не получилось без -Dприставки
номном
5

В качестве последующего наблюдения постарайтесь не хранить ключи / секреты API в репозитории открытым текстом. Используйте систему управления секретами для загрузки ключей / секретов в переменные среды пользователя. В противном случае шаг 1 необходим, если он приемлем.

  1. Поместите "секреты" в текстовый файл выше во включающем репозитории.
  2. Создайте список ../set_keys.sh, содержащий список export API_KEY_A='<plaintext_key_aef94c5l6>'(используйте одинарные кавычки, чтобы предотвратить оценку)
  3. Добавьте фазу выполнения сценария, которая может быть выполнена, source ../set_keys.shи переместите ее в начало порядка выполнения.
  4. В «Параметры сборки»> «Макросы препроцессора» добавьте необходимые определения, например API_KEY_A="$API_KEY_A"

Это фиксирует переменную среды в определении компилятора, которое позже используется при каждом вызове clang для каждого исходного файла.

Пример структуры каталогов

[10:33:15] ~/code/memo yes? tree -L 2 .
.
├── Memo
│   ├── Memo
│   ├── Memo.xcodeproj
│   ├── Memo.xcworkspace
│   ├── Podfile
│   ├── Podfile.lock
│   └── Pods
└── keys
Майкл Лоренцо
источник
0

В быстрых пакетах вы должны сделать это внутри swiftSettingsаргумента .targetв вашем Package.swiftфайле. Используйте defineметод (документация Apple) или документацию Swift

targets: [
.target(name: String,
            dependencies: [Target.Dependency],
            path: String?,
            exclude: [String]?,
            sources: [String]?,,
            cSettings: [CSetting]?,
            cxxSettings: [CXXSetting]?,
            swiftSettings: [SwiftSetting]?,
            linkerSettings: [LinkerSetting]?),

Мой выглядит так и работает!

            swiftSettings: [
               .define("VAPOR")
            ]

в моем коде я могу условно скомпилировать, используя это:

#if VAPOR
гарафаджон
источник