Logo for tanaschita.com

Managing different iOS build configurations in Xcode

Learn the possibilities to set up environments like debug, staging and release for your iOS app.

14 Feb 2022 · 4 min read

When developing an iOS application, we most likely will have to setup multiple app environments for the different phases the app goes through like debug, testing and release.

Xcode provides us with the tools to do that. In this article, we'll look at how to manage different build configurations for those environments and how to access them from code.

Let's jump in.

The default Xcode project configuration

When we first create an Xcode project, it automatically creates an app target, two test targets, one scheme and two configurations for Debug and Release.

Xcode project, targets, build settings and scheme
Xcode project, targets, build settings and scheme.

That is already a great start. To add more environments and to setup them to our needs, let's first understand the different concepts Xcode provides.

Sponsorship logo
Using Proxyman to inspect network traffic
Proxyman is a native debugging proxy that can act as a man-in-the-middle between your application and web server. You can use its powerful toolkit to inspect network calls and debug your application on Mac, iOS Simulator, or remote devices effortlessly.
CLICK TO LEARN MORE

Understanding Xcode targets and schemes

Let's start with the most basic one - an Xcode project. An Xcode project contains all the code files, resources and information needed to build a product. A product can be for example the debug or the release version of the iOS app.

Projects contain one or more targets. An Xcode target specifies how to build a product. The instructions for building a product are the build settings and build phases. A project defines default build settings for all its targets. Each target can override those default settings.

An Xcode scheme defines what happens when we execute actions like build, run, test or profile. For example which build configuration to use when we are building the app.

Adding a new configuration

Since Xcode already created the Debug and Release configurations for us, we only need to create one more. For that, we can use the + button in the configurations section. Here, we can choose which of the existing configurations to duplicate.

Adding new configuration
Adding a new configuration.

We duplicate the Debug configuration and name it for example Staging or Testing.

Adding new schemes

Next, we add a scheme per configuration to be able to quickly switch between them when we run the build or the test action in Xcode.

Managing schemes.
Managing schemes in Xcode.

After choosing Manage schemes, we can rename existing schemes and add new ones.

Adding new schemes.
Adding a new scheme.

In our example, we rename the existing one to ExampleApp Debug and create two more named ExampleApp Staging and ExampleApp Release.

Now, we need to go though every action in every scheme and choose the associated configuration to run.

Editing a scheme.
Editing a scheme.

Configuring build settings

With the configurations setup, we can now use them in build settings. Each build setting can have a different value for each configuration.

For example, if we need different app bundle identifiers for each configuration, all we need to do is to change their values for each configuration.

Customizing build settings for each configuration.
Customizing build settings for each configuration.

We can do the same with the app icon or the app name.

User defined build settings

Additionally, we can define our own build settings for each configuration by adding new build settings with the + button.

User defined build settings.
User defined build settings.

As we can see above, we defined a custom build setting called API_URL, so we are able to use different API endpoints for each configuration.

Accessing build settings in code

After doing that, we want to access our custom configured value in code. The first step to do that is to add the custom setting to our Info.plist by referencing the build setting with $(VARIABLE_NAME).

User defined build setting in Info.plist.
User defined build setting in Info.plist.

Now, we can access the configuration value in code as follows:

Bundle.main.object(forInfoDictionaryKey: "API_URL")

And that's basically it. With this approach, we can add as many configuration values as we need.

We can also add a representation of the build configuration to our code for example to be able to activate certain features only for certain environments or to manage those values directly from code. This might look something like this:

struct BuildConfiguration {
enum Environment: String {
case debug = "Debug"
case staging = "Staging"
case release = "Release"
}
let environment: Environment
init() {
environment = Environment(rawValue: Bundle.main.object(forInfoDictionaryKey: "Environment") as! String)!
}
}

Xcode configuration files

Alternatively to managing the values through Xcode's build settings tab, we can use Xcode configuration files to achieve the same results. If you want to learn more about them, check out the article Working with Xcode configuration files.

Sponsorship logo
Using Proxyman to inspect network traffic
Proxyman is a native debugging proxy that can act as a man-in-the-middle between your application and web server. You can use its powerful toolkit to inspect network calls and debug your application on Mac, iOS Simulator, or remote devices effortlessly.
CLICK TO LEARN MORE

Newsletter

Image of a reading marmot
Subscribe

Like to support my work?

Say hi

Related tags

Articles with related topics

core data

persistence

xcode

swift

ios

iOS developer guide on the main aspects of Core Data

Understand the main concepts of the Core Data framework.

19 Sep 2022 · 5 min read

Latest articles and tips

© 2022 tanaschita.com

Privacy policy

Impressum