Working with Xcode configuration files
Learn how to manage different iOS build environments with .xcconfig files.
21 Feb 2022 · 3 min read
In the last article on Managing different iOS build environments in Xcode, we used Xcode's build settings tab to setup the build environments develop, staging and release in our iOS application. I recommend to check it out before reading this guide.
In this article, we are going to look at an alternative way to achieve the same results - with Xcode configuration files .xcconfig.
Let's jump in.
Creating configuration files
As a first step, we create one .xcconfig file per configuration. When creating a new file in Xcode, it offers a template named Configuration Settings File.
Each files represents a build configuration. In our case those are Debug.xcconfig, Staging.xcconfig and Release.xcconfig.

The files are empty by default.

Connecting configuration files with build configurations
To connect each .xcconfig file with the corresponding build configuration, we open Xcode's Info tab and configure the Based on Configuration File section for the app target.

As shown above, Xcode offers to select from a list of .xcconfig files we created.
Adding values to configuration files
The next step is to add values to the newly created files, for example the api url that is different for each environment.
Debug.xcconfig
API_URL = https://dev.api.com
Staging.xcconfig
API_URL = https://staging.api.com
Release.xcconfig
API_URL = https://api.com
It may feel unusual, but we don't surround String values with quotation marks in .xcconfig files, even if they contain spaces.
Update: when working with xcconfig files, a common issue is not being able to write URLs due to the double slash in http:// which is interpreted as a comment. A workaround is to use https:/$()/dev.api.com instead.
Accessing configuration values in code
The same way as with user defined build settings, we can now access the configured values in code by first referencing them in the Info.plist with $(VARIABLE_NAME).

And then accessing the value in code with:
Bundle.main.object(forInfoDictionaryKey: "API_URL")
Working with inheritance
To avoid redundancy, there is a possibility to inherit values from project to target level. Let's say, we want to use a different bundle identifier for each environment so they don't override each other when building.
For that, we create a configuration file, for instance called Common.xcconfig, and connect it with the project instead of the target.
In Common.xcconfig, we setup a reusable value for the bundle identifier as follows:
BUNDLE_IDENTIFIER = com.tanaschita.exampleapp
And reuse it in our configuration files with $(inherited):
Debug.xcconfig
#include "Common.xcconfig"BUNDLE_IDENTIFIER = $(inherited).debug
Staging.xcconfig
#include "Common.xcconfig"BUNDLE_IDENTIFIER = $(inherited).staging
That's a nice way to avoid repeating the same values in different files. We can also reference defined values in new ones with $(VARIABLE_NAME).
Conclusion
Using .xcconfig files initially requires a few additional steps to setup, but especially when the list of custom build settings is growing, it might be easier to manage them in separate files.
.xcconfig files also allow us to manage build settings independently from Xcode. They can be modified with any editor, are reusable and friendlier to use with source control.

Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips