How to configure Xcode projects for different environments?

Today, I want to share different configuration techniques for Xcode projects with you for different environments like; development, beta, QA, pilot, production, etc.

First of all, ❗️ do not use targets for environmental configuration purposes.

Let’s start with creating a new Debug and Release configuration for each of our environments. Like; Development Debug, Test Release, QA Release, Test Debug, Production Release, etc.

Also for CocoaPods, we should update .Podfile for newly created configurations.

Let’s create schemes for each configuration sets. Development, Test, QA, Production, etc. Make sure that we’re sharing those schemes and selected the right Build Configurations.

So, how to set different values for different configurations? App Name, Bundle Identifier, API URL, .framework file?

First things first.

Let’s start with basics like App Name, Bundle Identifier, Icon Set Name, etc. Every configuration set has to have a different name, bundle identifier, and maybe icon for easier recognization.

We also need to create our own properties for other purposes. API URL, API Key, maybe another Info.plist, .so, or another framework?

There are 5 ways of achieving this. User-Defined settings, Xcode configuration files, multiple Info.plists, preprocessor macros, and custom script phases.

  1. User-Defined Settings

✅ Easy

⛔️ Not readable, especially on conflicts at .xcodeproj file

⛔ ️Have to pass data to Info.plist

Additional tip before the second option.

❗️Always log your build settings and environment variables. Also, keep your build logs with your .xarchives.

2. Xcode configuration files

✅ Easily readable

✅ Easy to see changes in git

✅ Supports conditional properties

⛔ Have to escape manually

⛔ Have to pass data to Info.plist

3. Using different Info.plists

✅ Semi Readable

✅ Easy to see changes in git

⛔ If you make a change on the project that interests Info.plist. You have to copy change into all of Info.plists.

⛔ Sometimes doesn’t feel right.

4. Preprocessor macros

✅ Most readable choice

✅ Best for quick, non-vital configurations. Like; changing log type for a framework.

✅ Can use the same macro for different configurations and combine them.

⛔ Can be broken with .xcodeproj file merges, changes.

5. Script Phases

✅ Best for changing frameworks, libraries, whole files, etc.

Easier to understand with a Firebase, GoogleService-Info.plist example.

Thank you for reading. If you have any thoughts please feel free to share them in the comments.