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

В 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 больше не использует препроцессор?

2 ответа

Решение

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

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

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

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

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

#if DEBUG
    let accessToken = "DebugAccessToken"
#else
    let accessToken = "ProductionAccessToken"
#endif

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

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

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

Однако для того, чтобы они были подобраны Swift, вам нужно установить "Другие флаги Swift" в настройках сборки вашей цели:

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

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

В быстрых пакетах это нужно делать внутри 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

В качестве последующего наблюдения постарайтесь не хранить ключи / секреты 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
Другие вопросы по тегам