Swift: ¿cómo usar las banderas de PREPROCESADOR (como `#if DEBUG`) para implementar claves API?

95

En Objective-Cocasiones, era útil usar constantes de cadena estática para definir claves de API alternativas (por ejemplo, para diferenciar entre las claves RELEASE y DEBUG para paquetes de análisis, como MixPanel, Flurry o Crashlytics):

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

y entonces...

[Analytics startSession:API_KEY];

¿Cómo se traduce esto en Swift, dado que el compilador Swift ya no usa un preprocesador?

cleverbit
fuente

Respuestas:

161

Apple incluyó soporte completo para los indicadores del preprocesador Swift a partir de Xcode 8 , por lo que ya no es necesario establecer estos valores en "Otros indicadores Swift".

La nueva configuración se llama "Condiciones de compilación activa", que proporciona soporte de nivel superior para el equivalente Swift de los indicadores del preprocesador. Lo usa exactamente de la misma manera que lo haría con "Otras banderas rápidas", excepto que no es necesario anteponer el valor con una "-D" (por lo que es un poco más limpio).

De las notas de la versión de Xcode 8 :

Active Compilation Conditionses una nueva configuración de compilación para pasar indicadores de compilación condicional al compilador Swift. Cada elemento del valor de esta configuración pasa a swiftc con el prefijo -D, de la misma manera que los elementos de Preprocessor Macrospasan a clang con el mismo prefijo. (22457329)

ingrese la descripción de la imagen aquí

Utiliza la configuración anterior así:

#if DEBUG
    let accessToken = "DebugAccessToken"
#else
    let accessToken = "ProductionAccessToken"
#endif
Dan Loewenherz
fuente
2
Nota: usted debe no especificar = 1 o cualquier otro = valor. Más bien, solo necesita especificar el nombre de la bandera. :]
JRG-Developer
@ JRG-Developer No estoy en desacuerdo, pero no estoy seguro de cómo se aplica su comentario aquí.
Dan Loewenherz
9
Esta es una respuesta útil, pero viniendo de un fondo de Objective-C (como imagino que son muchos desarrolladores de iOS), asumí que necesitaba especificar =1... Perdí un poco de tiempo tratando de averiguar por qué no estaba funcionando cuando lo hice. Entonces, pensé en compartir este dato para ayudar al próximo compañero. :] De todos modos, ¡gracias por tu respuesta aquí!
JRG-Developer
1
@ JRG-Developer, @Dan Loewenherz He configurado tanto DEBUGin Active Compilation Conditionscomo DEBUG=1in Preprocessor Macrosy esta configuración no funciona en absoluto. ¿Debo eliminar DEBUG=1? No está claro a partir de los comentarios anteriores.
Bhavin_m
2
@DanLoewenherz Tienes toda la razón. Había establecido "DEBUG" para la configuración del archivo en mi configuración de destino, por lo que cada vez que ejecuta una declaración de depuración y nunca ejecuta la condición de lanzamiento. Cualquiera que esté enfrentando un problema, por favor verifique su objetivoBuild Configuration primero . Consulte esta respuesta stackoverflow.com/questions/9063100/… para obtener más información.
Bhavin_m
131

ACTUALIZADO: Xcode 8 ahora admite esto automáticamente, vea la respuesta de @ DanLoewenherz arriba.

Antes de Xcode 8, aún podía usar Macros de la misma manera:

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

Sin embargo, para que Swift pueda recogerlos, debes establecer "Otras banderas Swift" en la configuración de construcción de tu objetivo:

  • Abra la configuración de compilación para su objetivo
  • Buscar "otras banderas rápidas"
  • Agregue las macros que desee utilizar, precedidas por el -D bandera

ingrese la descripción de la imagen aquí

cleverbit
fuente
¡me has alegrado el día! para mí no funcionó sin -Dprefijo
nomnom
5

Como observación de seguimiento, intente no mantener claves / secretos de la API en texto plano en el repositorio. Utilice un sistema de gestión de secretos para cargar las claves / secretos en las variables de entorno del usuario. De lo contrario, el paso 1 es necesario, si es aceptable.

  1. Coloque los "secretos" en un archivo de texto sin formato en el repositorio adjunto
  2. Cree un ../set_keys.shque contenga una lista de export API_KEY_A='<plaintext_key_aef94c5l6>'(use comillas simples para evitar la evaluación)
  3. Agregue una fase de secuencia de comandos de ejecución que pueda source ../set_keys.shy muévala a la parte superior de la orden de ejecución
  4. En Configuración de compilación> Macros de preprocesador, agregue a las definiciones según sea necesario, como API_KEY_A="$API_KEY_A"

Eso captura la variable de entorno en la definición del compilador que luego se usa en cada invocación de clang para cada archivo fuente.

Estructura de directorio de ejemplo

[10:33:15] ~/code/memo yes? tree -L 2 .
.
├── Memo
│   ├── Memo
│   ├── Memo.xcodeproj
│   ├── Memo.xcworkspace
│   ├── Podfile
│   ├── Podfile.lock
│   └── Pods
└── keys
Miguel Lorenzo
fuente
0

En paquetes rápidos, debe hacer esto dentro del swiftSettingsargumento .targeten su Package.swiftarchivo. Utilice el definemétodo (documentación de Apple) o la documentación de Swift

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

¡El mío se ve así y funciona!

            swiftSettings: [
               .define("VAPOR")
            ]

en mi código puedo compilar condicionalmente usando esto:

#if VAPOR
garafajon
fuente