build-configurations-and-xcconfig
Settings
have multiple values, one for each Build Configuration
. Check Base SDK, for example. A build configuration is like an environment.
You define Build Configurations
globally, at the project level
. Xcode creates two configurations for you: Debug
and Release
.
Apple defines an Xcode scheme as follows: “An Xcode scheme defines a collection of targets to build, a configuration to use when building, and a collection of tests to execute.”
Creating a new target automatically creates a new scheme that goes with it.
The WidgetExtention scheme, for instance, defines how Xcode will build, run, test, profile, analyze and archive the widget target. It also defines which build configurations to use with these actions.
To configure and create test builds of the app
, you need a staging
build configuration.
As you can see, you can use configuration files at the project level
as well as at each target level
, for each environment.
Base.xcconfig
1
2
3
4
5
6
7
8
APP_NAME = Ninja Counter
BASE_BUNDLE_IDENTIFIER = <your bundle identifier>
// referece syntax: $(OTHER_BUILD_SETTING_NAME)
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER)
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon
Debug.xcconfig
1
2
3
4
5
#include "Base.xcconfig"
APP_NAME = $(inherited)Dev
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon-NonProd
It’s a best practice to set general build settings at the project level. Then, reuse those settings in different configurations to avoid redundancy. In this case, you’ll change APP_NAME
in each build configuration to inherit from the base value.
Release.xcconfig
1
2
#include "Base.xcconfig"
...
WidgetBase.xcconfig
1
2
3
#include "Base.xcconfig"
PRODUCT_BUNDLE_IDENTIFIER = $(BASE_BUNDLE_IDENTIFIER).widget
WidgetDebug.xcconfig
1
2
3
#include "Debug.xcconfig"
#include "WidgetBase.xcconfig"
...
WidgetStaging.xcconfig
1
2
3
#include "Staging.xcconfig"
#include "WidgetBase.xcconfig"
...
WidgetRelease.xcconfig
1
2
#include "Release.xcconfig"
#include "WidgetBase.xcconfig"
Adding Conditions
Base.xcconfig
Syntax: BUILD_SETTING_NAME[condition=value] = VALUE.
1
ONLY_ACTIVE_ARCH[config=Debug][sdk=*][arch=*] = YES
Here, you set ONLY_ACTIVE_ARCH
to YES when the app builds in Debug configuration. As a result, it speeds up build times by building only the active architecture.
Setting the conditional value to an asterisk means any value. The setting you added above applies for any sdk and any architecture, but only for the Debug configuration.
Accessing Settings From Code
To access a build setting from code, you first need to add a reference property in Info.plist. Open NinjaCounter’s Info.plist and add a custom property named:
Config.swift
1
2
3
4
5
6
7
8
9
enum Config {
static func stringValue(forKey key: String) -> String {
guard let value = Bundle.main.object(forInfoDictionaryKey: key) as? String
else {
fatalError("Invalid value or undefined key")
}
return value
}
}