Swift: comment utiliser les indicateurs PREPROCESSOR (comme `#if DEBUG`) pour implémenter les clés API?

95

Il Objective-Cétait parfois utile d'utiliser des constantes de chaîne statiques pour définir des clés API alternatives (par exemple pour différencier les clés RELEASE et DEBUG pour les packages d'analyse, comme MixPanel, Flurry ou Crashlytics):

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

puis...

[Analytics startSession:API_KEY];

Comment cela se traduit-il par Swift, puisque le compilateur Swift n'utilise plus de préprocesseur?

astucieux
la source

Réponses:

161

Apple a inclus la prise en charge complète des indicateurs de préprocesseur Swift à partir de Xcode 8 , il n'est donc plus nécessaire de définir ces valeurs dans «Autres indicateurs Swift».

Le nouveau paramètre est appelé «Conditions de compilation actives», qui fournit une prise en charge de niveau supérieur pour l'équivalent Swift des indicateurs de préprocesseur. Vous l'utilisez exactement de la même manière que vous le feriez avec "Other Swift Flags", sauf qu'il n'est pas nécessaire de mettre la valeur avant "-D" (donc c'est juste un peu plus propre).

À partir des notes de version de Xcode 8 :

Active Compilation Conditionsest un nouveau paramètre de construction pour passer des indicateurs de compilation conditionnelle au compilateur Swift. Chaque élément de la valeur de ce paramètre passe à swiftc préfixé par -D, de la même manière que les éléments de Preprocessor Macrospasse à clang avec le même préfixe. (22457329)

entrez la description de l'image ici

Vous utilisez le paramètre ci-dessus comme ceci:

#if DEBUG
    let accessToken = "DebugAccessToken"
#else
    let accessToken = "ProductionAccessToken"
#endif
Dan Loewenherz
la source
2
Remarque: vous ne devez pas spécifier = 1 ni aucune autre valeur =. Au contraire, vous devez simplement spécifier le nom du drapeau. :]
JRG-Developer
@ JRG-Developer Je ne suis pas en désaccord, mais je ne sais pas comment votre commentaire s'applique ici.
Dan Loewenherz
9
C'est une réponse utile, mais venant d'un arrière-plan Objective-C (comme j'imagine que de nombreux développeurs iOS le sont), j'ai supposé que je devais spécifier =1... j'ai perdu un peu de temps à essayer de comprendre pourquoi cela ne fonctionnait pas quand je l'ai fait. Alors, j'ai pensé partager cette information pour aider le prochain. :] Quoi qu'il en soit, merci pour votre réponse ici!
JRG-Developer
1
@ JRG-développeur, je Loewenherz @ Dan ont mis à la fois DEBUGdans Active Compilation Conditionset DEBUG=1en Preprocessor Macroset cette configuration ne fonctionne pas du tout. Dois-je supprimer DEBUG=1?? Pas clair d'après les commentaires ci-dessus.
Bhavin_m
2
@DanLoewenherz Vous avez absolument raison. J'avais défini "DEBUG" pour la configuration de l'archive dans mes paramètres cibles, donc à chaque fois qu'il exécute une instruction Debug et n'exécute jamais la condition de publication. Toute personne confrontée à un problème, veuillez d'abord vérifier votre cible Build Configuration. Consultez cette réponse stackoverflow.com/questions/9063100/… pour plus d'informations.
Bhavin_m
131

MISE À JOUR: Xcode 8 prend désormais en charge cela automatiquement, voir la réponse de @ DanLoewenherz ci-dessus.

Avant Xcode 8, vous pouviez toujours utiliser les macros de la même manière:

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

Cependant, pour qu'ils soient récupérés par Swift, vous devez définir "Autres indicateurs Swift" dans les paramètres de construction de votre cible:

  • Ouvrez les paramètres de construction pour votre cible
  • Rechercher "autres indicateurs rapides"
  • Ajoutez les macros que vous souhaitez utiliser, précédées du -Ddrapeau

entrez la description de l'image ici

astucieux
la source
tu as fait ma journée! pour moi ça n'a pas fonctionné sans -Dpréfixe
nomnom
5

Comme observation de suivi, essayez de ne pas conserver les clés / secrets d'API en texte brut dans le référentiel. Utilisez un système de gestion des secrets pour charger les clés / secrets dans les variables d'environnement de l'utilisateur. Sinon, l'étape 1 est nécessaire, si elle est acceptable.

  1. Mettez les "secrets" dans un fichier en clair ci-dessus dans le référentiel englobant
  2. Créez un ../set_keys.shqui contient une liste de export API_KEY_A='<plaintext_key_aef94c5l6>'(utilisez un guillemet simple pour empêcher l'évaluation)
  3. Ajouter une phase source ../set_keys.shd'exécution de script qui peut et la déplacer vers le haut de l'ordre d'exécution
  4. Dans Paramètres de construction> Macros de préprocesseur, ajoutez aux définitions si nécessaire, telles que API_KEY_A="$API_KEY_A"

Cela capture la variable d'environnement dans la définition du compilateur qui est ensuite utilisée dans chaque appel de clang pour chaque fichier source.

Exemple de structure de répertoire

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

Dans les packages swift, vous devez le faire à l'intérieur de l' swiftSettingsargument to .targetdans votre Package.swiftfichier. Utilisez la defineméthode (documentation Apple) ou la documentation Swift

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

Le mien ressemble à ça et ça marche!

            swiftSettings: [
               .define("VAPOR")
            ]

dans mon code, je peux compiler conditionnellement en utilisant ceci:

#if VAPOR
garafajon
la source