Swift: bagaimana cara menggunakan PREPROCESSOR Flags (seperti `#if DEBUG`) untuk mengimplementasikan kunci API?

95

Di Objective-Cdalamnya terkadang berguna untuk menggunakan konstanta string statis untuk menentukan kunci API alternatif (misalnya untuk membedakan antara kunci RELEASE dan DEBUG untuk paket analitik, seperti MixPanel, Flurry, atau Crashlytics):

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

lalu...

[Analytics startSession:API_KEY];

Bagaimana ini diterjemahkan ke Swift, karena kompiler Swift tidak lagi menggunakan preprocessor?

cleverbit
sumber

Jawaban:

161

Apple menyertakan dukungan penuh untuk tanda preprocessor Swift mulai Xcode 8 , jadi tidak perlu lagi menyetel nilai ini di "Other Swift Flags".

Pengaturan baru ini disebut "Kondisi Kompilasi Aktif", yang memberikan dukungan tingkat atas untuk tanda preprocessor yang setara dengan Swift. Anda menggunakannya dengan cara yang persis sama seperti Anda menggunakan "Bendera Swift Lainnya", kecuali tidak perlu menambahkan nilai dengan "-D" (jadi hanya sedikit lebih bersih).

Dari catatan rilis Xcode 8 :

Active Compilation Conditionsadalah setelan build baru untuk meneruskan tanda kompilasi bersyarat ke kompilator Swift. Setiap elemen nilai pengaturan ini diteruskan ke swiftc yang diawali dengan -D, dengan cara yang sama elemen Preprocessor Macrospass to clang dengan awalan yang sama. (22457329)

masukkan deskripsi gambar di sini

Anda menggunakan pengaturan di atas seperti ini:

#if DEBUG
    let accessToken = "DebugAccessToken"
#else
    let accessToken = "ProductionAccessToken"
#endif
Dan Loewenherz
sumber
2
Catatan: Anda tidak boleh menentukan = 1 atau nilai = lainnya. Sebaliknya, Anda hanya perlu menentukan nama bendera. :]
JRG-Developer
@ JRG-Developer Saya tidak setuju, tapi saya tidak yakin bagaimana komentar Anda berlaku di sini.
Dan Loewenherz
9
Ini adalah jawaban yang membantu, tetapi berasal dari latar belakang Objective-C (seperti yang saya bayangkan banyak pengembang iOS), saya berasumsi bahwa saya perlu menentukan =1... Saya kehilangan sedikit waktu untuk mencoba mencari tahu mengapa itu tidak berfungsi ketika saya melakukannya. Jadi, saya pikir saya akan membagikan berita gembira ini untuk membantu orang berikutnya. :] Bagaimanapun, terima kasih atas jawaban Anda di sini!
JRG-Developer
1
@ JRG-Developer, @ Dan Loewenherz saya telah menetapkan kedua DEBUGdi Active Compilation Conditionsdan DEBUG=1di Preprocessor Macrosdan konfigurasi ini tidak bekerja sama sekali. Haruskah saya menghapus DEBUG=1?? Tidak jelas dari komentar di atas.
Bhavin_m
2
@DanLoewenherz Anda benar sekali. Saya telah menetapkan "DEBUG" untuk konfigurasi arsip dalam pengaturan target saya, jadi setiap kali menjalankan pernyataan Debug dan tidak pernah menjalankan kondisi rilis. Siapa pun yang menghadapi masalah, silakan periksa target Anda Build Configurationterlebih dahulu. Periksa jawaban stackoverflow.com/questions/9063100/… ini untuk info lebih lanjut.
Bhavin_m
131

DIPERBARUI: Xcode 8 sekarang mendukung ini secara otomatis, lihat tanggapan @ DanLoewenherz di atas.

Sebelum Xcode 8, Anda masih dapat menggunakan Macro dengan cara yang sama:

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

Namun agar mereka dapat diambil oleh Swift, Anda perlu menyetel "Bendera Swift Lainnya" di Pengaturan Build target Anda:

  • Buka Pengaturan Bangun untuk target Anda
  • Telusuri "bendera swift lainnya"
  • Tambahkan makro yang ingin Anda gunakan, diawali dengan -Dbendera

masukkan deskripsi gambar di sini

cleverbit
sumber
kamu membuat hariku! bagi saya Itu tidak berhasil tanpa -Dawalan
nomnom
5

Sebagai observasi lanjutan, usahakan untuk tidak menyimpan kunci / rahasia api dalam teks biasa di repositori. Gunakan sistem manajemen rahasia untuk memuat kunci / rahasia ke dalam variabel lingkungan pengguna. Jika tidak, langkah 1 diperlukan, jika dapat diterima.

  1. Letakkan "rahasia" dalam file teks biasa di atas dalam repositori terlampir
  2. Buat ../set_keys.shyang berisi daftar export API_KEY_A='<plaintext_key_aef94c5l6>'(gunakan kutipan tunggal untuk mencegah evaluasi)
  3. Tambahkan fase Jalankan skrip yang dapat source ../set_keys.shdan pindahkan ke bagian atas urutan eksekusi
  4. Di Build Settings> Preprocessor Macro, tambahkan ke definisi yang diperlukan seperti API_KEY_A="$API_KEY_A"

Itu menangkap variabel lingkungan ke dalam compiler define yang kemudian digunakan di setiap pemanggilan clang untuk setiap file sumber.

Contoh struktur direktori

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

Dalam paket cepat Anda harus melakukan ini di dalam swiftSettingsargumen ke .targetdalam Package.swiftfile Anda . Gunakan definemetode (dokumentasi Apple) atau dokumentasi Swift

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

Punyaku terlihat seperti ini dan berhasil!

            swiftSettings: [
               .define("VAPOR")
            ]

dalam kode saya, saya dapat mengkompilasi secara kondisional menggunakan ini:

#if VAPOR
garafajon
sumber