Improve Your Project Builds by Leveraging xcconfig Files
Managing Xcode project settings can get complicated as your app grows. One powerful, handy tool to simplify this process is the xcconfig file. In this post, we’ll explore what xcconfig files are, why you should use them, and how to implement them in your Xcode projects.
An Xcode configuration file, xcconfig
, is a plain text file that contains build settings for your project. Whether you’re working solo or as part of a team, mastering xcconfig files can streamline your workflow and make your project more robust.
From several other advantages, I’ll highlight the following:
It lets you manage your build settings in one centralized location. This makes it easier to find, update, or remove settings without sifting through Xcode’s often cluttered UI.
You can separate your configuration settings from your actual code. This makes your codebase cleaner and easier to read, as you don’t have to dig through lines of code just to tweak a setting.
Storing settings in xcconfig files helps minimize the chances of running into merge conflicts when using version control systems. By isolating settings from the project file, you avoid messy conflicts that often need manual resolution.
Let’s now take a look at the syntax and structure of xcconfig files. We’ll cover the basics, as well as some more advanced topics.
At its core, an xcconfig file is a list of key-value pairs. Each line sets a configuration key to a specific value. And, to use a variable you’ve defined, wrap it in parentheses and precede it with a dollar sign.
// Setting the Bundle Identifier
PRODUCT_BUNDLE_IDENTIFIER = com.example.MyCoolApp
// Setting the Product Name
PRODUCT_NAME = $(APP_NAME)
Whitespace generally doesn’t matter in xcconfig files, making it flexible to format. You can align values neatly or leave space around the equals sign for better readability.
CODE_SIGN_IDENTITY = iPhone Developer
To keep things organized, you can include one xcconfig file in another using the #include
directive. This way, you can have base configurations that are extended by more specific ones. It’s worthy pointing out that variables defined in the including file will override those in the included file.
// Base.xcconfig
COMMON_FLAGS = -Wall
// Debug.xcconfig
#include "Base.xcconfig"
OTHER_SWIFT_FLAGS = $(COMMON_FLAGS) -DDEBUG
// Release.xcconfig
#include "Base.xcconfig"
OTHER_SWIFT_FLAGS = $(COMMON_FLAGS) -DRELEASE
There’s no big secret to getting started with xcconfig files. You can create one in a few simple steps.
First up, open your Xcode project and go to the ‘File’ menu. Select ‘New’ > ‘File’, or use ⌘ + N, then choose ‘Configuration Settings File’ to create your new xcconfig file.
I created 3 files: Debug, Release and Shared.
Now, head over to your project settings by clicking on the project name in the navigator. Under ‘Configurations’, you’ll find a list of your build configurations like ‘Debug’ and ‘Release’. Assign your xcconfig file to the desired configuration here.
To make sure everything’s set up correctly, try moving a simple setting, like the bundle identifier, to the xcconfig file. Then, on your Info.plist
file, replace the bundle identifier with the variable you just created. If everything’s working, you should see the new bundle identifier in the ‘General’ tab of your target settings. Build your project and verify that the setting takes effect.
Here are some more advanced topics to help you get the most out of these special files.
You can override xcconfig settings directly from the command line during build time. This is useful for temporary changes or for settings that need to be dynamic.
xcodebuild -project MyCoolApp.xcodeproj -scheme "MyCoolApp" PRODUCT_BUNDLE_IDENTIFIER=com.example.NewIdentifier
You can use xcconfig files in tandem with pre-build or post-build scripts to automate complex build setups.
In xcconfig files, you can access environment variables from your system, allowing you to integrate external data into your build configuration. For example, you can use stored credentials.
From all the companies I’ve worked for, I’ve seen a few common use cases for xcconfig files. Let’s take a look at some of them.
One of the most popular use-cases is managing different build environments like Debug, Internal, and Release. You can set up separate xcconfig files for each, making it easy to switch between them.
If your project has multiple targets, like an app and its corresponding widgets or extensions, xcconfig files help you share common settings across all targets. This ensures consistency and reduces duplication.
When working in a team, isolating settings from the main project file with xcconfig smooths collaboration by reducing the risk of merge conflicts, as mentioned before.
xcconfig files can also be a part of your CI/CD pipeline, allowing you to set or override build settings dynamically during automated builds.
If you’re working on a project that includes various modules or libraries, xcconfig files can help you manage settings for each one separately, providing a clean and modular approach to configuration.
Let’s wrap it up with some best practices.
Keeping your xcconfig files organized in a dedicated folder will facilitate management, especially as your project grows. Consistent naming is also key.
Good commenting within the xcconfig files can save you and your team a lot of headaches later on. Clearly explain what each setting is for and why specific values are used.
Always keep your xcconfig files under version control. This not only tracks changes but also lets you revert to previous configurations if something goes wrong.
Try to segregate settings based on their function or scope. For example, keep build-related settings separate from code signing settings.
As your project evolves, your settings will too. Periodically audit your xcconfig files to remove obsolete settings and update existing ones.
Be mindful of the complexity you’re introducing. Only use advanced features like conditional statements when really necessary.
Development Menu for the Rescue
A modern approach in app software development involves adding a development menu to the app. This feature is commonly found in larger companies, like Trade Republic, and is designed to streamline the development process.
Rather than navigating through the app or sifting through code for minor adjustments, the menu serves as a centralized hub. Within it, you can visually examine and interact with various elements of your app, such as UI components, color palettes, behaviors, and fonts. Additionally, you can easily change the values of feature flags and also use it as a playground for testing new technologies. At Trade Republic, our development menu is in SwiftUI, even though our app uses UIKit. My personal projects also feature a SwiftUI development menu.
The development menu is solely for development purposes and may not adhere to the same software quality and development rules as the actual app. Based on certain directives, it is stripped out from the versions of the app released on the App Store or Google Play. However, companies may still enable it in internal builds of the app.
It’s like having a secret lab for your app.