Keep Secrets Out of Info.plist With xcconfig
Build configuration files keep API keys out of git and let one target ship to staging and production.
Hard-coding a base URL or API key in Swift source means it ends up in version control and forces an edit every time you switch environments. Build configuration files — .xcconfig — fix both problems with nothing but Xcode’s built-in settings system.
An xcconfig file is a plain list of build settings. Create one per environment, assign each to its build configuration under the project’s Info tab, and keep secrets in a separate file that git ignores:
1
2
3
4
5
6
// Config/Shared.xcconfig
API_HOST = api.iosbuffet.com
#include? "Secrets.xcconfig"
// Config/Secrets.xcconfig (in .gitignore)
API_KEY = sk_live_do_not_commit
The #include? form is optional-include: if a teammate hasn’t created their secrets file yet, the build still succeeds. Note that // begins a comment in xcconfig files, so a full URL can’t be written directly — store the host and add the scheme in code.
Reading values at runtime
Build settings aren’t visible to your app by default. Expose the ones you need by adding keys to Info.plist whose values reference the setting, such as APIHost set to $(API_HOST). Then read them once at launch:
1
2
3
4
5
6
7
8
9
10
11
12
enum Config {
static let apiHost: String = value(for: "APIHost")
static let apiKey: String = value(for: "APIKey")
private static func value(for key: String) -> String {
guard let value = Bundle.main.object(forInfoDictionaryKey: key) as? String,
!value.isEmpty else {
fatalError("Missing \(key) — check your xcconfig files")
}
return value
}
}
A word on secrecy
This keeps keys out of your repository, not out of your binary. Anything shipped inside an app can be extracted by a determined user. Truly sensitive credentials belong on a server you control, with the app holding only a short-lived token.
— 30 —