Swift: come utilizzare i flag PREPROCESSOR (come `#if DEBUG`) per implementare le chiavi API?


95

A Objective-Cvolte era utile utilizzare costanti di stringa statica per definire chiavi API alternative (ad esempio per distinguere tra chiavi RELEASE e DEBUG per pacchetti di analisi, come MixPanel, Flurry o Crashlytics):

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

e poi...

[Analytics startSession:API_KEY];

Come si traduce in Swift, dal momento che il compilatore Swift non utilizza più un preprocessore?

Risposte:


161

Apple ha incluso il pieno supporto per i flag del preprocessore Swift a partire da Xcode 8 , quindi non è più necessario impostare questi valori in "Other Swift Flags".

La nuova impostazione si chiama "Condizioni di compilazione attiva", che fornisce il supporto di primo livello per l'equivalente Swift dei flag del preprocessore. Lo usi esattamente come faresti con "Other Swift Flags", tranne che non è necessario anteporre il valore con una "-D" (quindi è solo un po 'più pulito).

Dalle note di rilascio di Xcode 8 :

Active Compilation Conditionsè una nuova impostazione di compilazione per passare i flag di compilazione condizionale al compilatore Swift. Ogni elemento del valore di questa impostazione passa a swiftc con il prefisso -D, nello stesso modo in cui gli elementi di Preprocessor Macrospass a clang con lo stesso prefisso. (22457329)

inserisci qui la descrizione dell'immagine

Usi l'impostazione sopra in questo modo:

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

2
Nota: è necessario non specificare = 1 o qualsiasi altro = valore. Piuttosto, devi solo specificare il nome della bandiera. :]
JRG-Developer

@ JRG-Developer Non sono in disaccordo, ma non sono sicuro di come il tuo commento si applichi qui.
Dan Loewenherz

9
Questa è una risposta utile, ma provenendo da un background Objective-C (come immagino siano molti sviluppatori iOS), pensavo di dover specificare =1... Ho perso un po 'di tempo cercando di capire perché non funzionava quando l'ho fatto. Quindi, ho pensato di condividere questo bocconcino per aiutare il prossimo. :] Comunque, grazie per la tua risposta qui!
JRG-Developer

1
@ JRG-Developer, @Dan Loewenherz Ho impostato sia DEBUGdentro Active Compilation Conditionsche DEBUG=1dentro Preprocessor Macrose questa configurazione non funziona affatto. Devo rimuovere DEBUG=1?? Non è chiaro dai commenti sopra.
Bhavin_m

2
@DanLoewenherz Hai assolutamente ragione. Avevo impostato "DEBUG" per la configurazione dell'archivio nelle mie impostazioni di destinazione, quindi ogni volta che esegue un'istruzione di debug e non esegue mai la condizione di rilascio. Chiunque stia affrontando un problema, controlla prima il tuo obiettivo Build Configuration. Controlla questa risposta stackoverflow.com/questions/9063100/… per maggiori informazioni.
Bhavin_m

131

AGGIORNATO: Xcode 8 ora lo supporta automaticamente, vedi la risposta di @ DanLoewenherz sopra.

Prima di Xcode 8, era ancora possibile utilizzare le macro allo stesso modo:

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

Tuttavia, affinché possano essere raccolti da Swift, devi impostare "Altre bandiere Swift" nelle Impostazioni di costruzione del tuo bersaglio:

  • Apri Impostazioni build per il tuo target
  • Cerca "altre bandiere rapide"
  • Aggiungi le macro che desideri utilizzare, precedute dalla -Dbandiera

inserisci qui la descrizione dell'immagine


hai reso la mia giornata! per me non ha funzionato senza -Dprefisso
nomnom

5

Come osservazione successiva, cerca di non mantenere chiavi / segreti API in testo normale nel repository. Utilizzare un sistema di gestione dei segreti per caricare le chiavi / i segreti nelle variabili di ambiente dell'utente. In caso contrario, è necessario il passaggio 1, se accettabile.

  1. Metti i "segreti" in un file di testo in chiaro sopra nel repository allegato
  2. Creare un ../set_keys.shche contenga un elenco di export API_KEY_A='<plaintext_key_aef94c5l6>'(utilizzare virgolette singole per impedire la valutazione)
  3. Aggiungere una fase di esecuzione dello script in grado di source ../set_keys.shfarlo e spostarlo all'inizio dell'ordine di esecuzione
  4. In Impostazioni build> Macro preprocessore, aggiungi a definisce come necessario come API_KEY_A="$API_KEY_A"

Ciò cattura la variabile di ambiente nella definizione del compilatore che viene successivamente utilizzata in ogni chiamata clang per ogni file sorgente.

Esempio di struttura di directory

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

0

Nei pacchetti swift devi farlo all'interno swiftSettingsdell'argomento a .targetnel tuo Package.swiftfile. Usa il definemetodo (documentazione Apple) o la documentazione Swift

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

Il mio sembra così e funziona!

            swiftSettings: [
               .define("VAPOR")
            ]

nel mio codice posso compilare in modo condizionale usando questo:

#if VAPOR
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.