Swift: jak używać flag PREPROCESSOR (takich jak „#if DEBUG”) do implementacji kluczy API?

100

W Objective-Cbyło czasami warto używać statycznych stałych ciągów zdefiniować alternatywne klucze API (na przykład odróżnić zwolnić i klucze debugowania dla analityki pakietów, jak MixPanel, Flurry lub Crashlytics):

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

i wtedy...

[Analytics startSession:API_KEY];

Jak to się przekłada na Swift, skoro kompilator Swift nie używa już preprocesora?

sprytny
źródło

Odpowiedzi:

168

Firma Apple zapewniła pełną obsługę flag preprocesora Swift od Xcode 8 , więc nie jest już konieczne ustawianie tych wartości w „Inne flagi Swift”.

Nowe ustawienie nosi nazwę „Aktywne warunki kompilacji” i zapewnia obsługę na najwyższym poziomie odpowiednika flag preprocesora w języku Swift. Używasz go w dokładnie taki sam sposób, jak „Inne flagi Swift”, z wyjątkiem tego, że nie ma potrzeby poprzedzania wartości znakiem „-D” (więc jest to trochę czystsze).

Z informacji o wersji Xcode 8 :

Active Compilation Conditionsto nowe ustawienie kompilacji do przekazywania flag kompilacji warunkowej do kompilatora Swift. Każdy element wartości tego ustawienia przechodzi do swiftc z prefiksem -D, w taki sam sposób, w jaki elementy Preprocessor Macrospass to clang z tym samym prefiksem. (22457329)

wprowadź opis obrazu tutaj

Używasz powyższego ustawienia w następujący sposób:

#if DEBUG
    let accessToken = "DebugAccessToken"
#else
    let accessToken = "ProductionAccessToken"
#endif
Dan Loewenherz
źródło
2
Uwaga: należy nie określił = 1 lub jakąkolwiek inną = wartość. Zamiast tego wystarczy podać nazwę flagi. :]
JRG-Developer
@ JRG-Developer Nie zgadzam się, ale nie jestem pewien, jak odnosi się tutaj twój komentarz.
Dan Loewenherz
9
To pomocna odpowiedź, ale wychodząc z tła Objective-C (jak wyobrażam sobie wielu programistów iOS), założyłem, że muszę określić =1... Straciłem trochę czasu, próbując dowiedzieć się, dlaczego to nie działa kiedy to zrobiłem. Więc pomyślałem, że podzielę się tą ciekawostką, aby pomóc następnemu facetowi. :] W każdym razie, dzięki za odpowiedź tutaj!
JRG-Developer
1
@ JRG-Developer, @Dan Loewenherz Ustawiłem zarówno DEBUGin jak Active Compilation Conditionsi DEBUG=1in Preprocessor Macrosi ta konfiguracja w ogóle nie działa. Czy powinienem usunąć DEBUG=1? Nie wynika to z powyższych komentarzy.
Bhavin_m
2
@DanLoewenherz Masz całkowitą rację. W ustawieniach docelowych ustawiłem „DEBUG” dla konfiguracji archiwum, więc za każdym razem, gdy uruchamia instrukcję Debug i nigdy nie uruchamia warunku wydania. Każdy, kto ma problem, najpierw sprawdź swój cel Build Configuration. Więcej informacji znajdziesz w tej odpowiedzi stackoverflow.com/questions/9063100/… .
Bhavin_m
132

AKTUALIZACJA: Xcode 8 obsługuje teraz to automatycznie, zobacz odpowiedź @ DanLoewenherz powyżej.

Przed Xcode 8 nadal można było używać makr w ten sam sposób:

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

Aby jednak zostały one odebrane przez Swifta, musisz ustawić „Inne flagi szybkiej” w ustawieniach budowy celu:

  • Otwórz ustawienia kompilacji dla swojego celu
  • Wyszukaj „inne szybkie flagi”
  • Dodaj makra, których chcesz użyć, poprzedzone -Dflagą

wprowadź opis obrazu tutaj

sprytny
źródło
sprawiłeś, że mój dzień! dla mnie Nie działało bez -Dprzedrostka
nomnom
5

Jako dalsza obserwacja, staraj się nie przechowywać kluczy / kluczy interfejsu API w zwykłym tekście w repozytorium. Użyj systemu zarządzania sekretami, aby załadować klucze / sekrety do zmiennych środowiskowych użytkownika. W przeciwnym razie krok 1 jest konieczny, jeśli jest akceptowalny.

  1. Umieść „sekrety” w pliku zwykłego tekstu powyżej w załączającym repozytorium
  2. Utwórz, ../set_keys.shktóry zawiera listę export API_KEY_A='<plaintext_key_aef94c5l6>'(użyj pojedynczego cudzysłowu, aby zapobiec ocenie)
  3. Dodaj fazę skryptu uruchamiania, która może source ../set_keys.shi przenieś ją na górę kolejności wykonania
  4. W Ustawieniach kompilacji> Makra preprocesora, w razie potrzeby dodaj definicje, takie jak API_KEY_A="$API_KEY_A"

To przechwytuje zmienną środowiskową do definicji kompilatora, która jest później używana w każdym wywołaniu clang dla każdego pliku źródłowego.

Przykładowa struktura katalogów

[10:33:15] ~/code/memo yes? tree -L 2 .
.
├── Memo
│   ├── Memo
│   ├── Memo.xcodeproj
│   ├── Memo.xcworkspace
│   ├── Podfile
│   ├── Podfile.lock
│   └── Pods
└── keys
Michael Lorenzo
źródło
0

W szybkich pakietach musisz to zrobić wewnątrz swiftSettingsargumentu do .targetw swoim Package.swiftpliku. Użyj definemetody (dokumentacja Apple) lub dokumentacji Swift

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

Mój wygląda tak i działa!

            swiftSettings: [
               .define("VAPOR")
            ]

w moim kodzie mogę warunkowo skompilować za pomocą tego:

#if VAPOR
garafajon
źródło