Xcode Build Settings — User Defined Settings — iOS Manage multiple configuration and environments with Single target

Kavitha Kumarasamy
4 min readMar 5, 2018

--

As an iOS developer, we are aware we have to maintain different environments like Development, Release, Free Version, Paid Version, Beta and so on. For that, we have to maintain different app icons, server URLs, bundle display name, bundle identifier, license key. The motive for maintaining all these environments is because we would hit different Server URL, license Key, app icon and so on for different environments and for testing different versions of our app.

We end up doing either of these or sometimes all of these:

1. To create different targets, one for Production, another for Test Environment and so on.
2. Having different bundle id, icon and bundle display name on to the respective Info.plist.
3. Set global variable (or) ‘enum’ with server and production URL and related checks.
4. Boolean values (or) macro (or) variables to check different conditions inside the app.

Typically something like this:

#if DEVELOPMENT
let SERVER_URL = “http://yourdevserver.com/"
let API_TOKEN = “1234567”
#else
let SERVER_URL = “http://yourproductionserver.com/"
let API_TOKEN = “7654321”
#endif

This can be avoided for certain cases like having same code base and logic for all environments.

Speaking of which, the code, logic, frameworks all being same, we have a solution with Xcode Build settings, which most of us are unaware. The better approach would be to use single target but handle multiple environments using User-Defined Settings for your target. This approach eliminates the need to maintain separate Info.plist files and you won’t have to add podfile sections. ‘User Defined Settings’ in Xcode comes handy for these type of build configurations and environments.

We can have a look at below link for general Xcode Build settings. https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Build_Settings.html
for Xcode build settings.

Install Debug, Release, Paid or Free Versions side by side:

Let’s see this by creating a sample project and adding a User Defined Settings to understand better.

To create a User Defined Settings for the Bundle Name,
1. Create an Xcode project.
2. Select your Target (KEnvManagement is my target name.)
2. Then go to the Build Settings tab. On the top, select the +(next to All,Combined, Levels on the top) and choose “Add User-Defined Setting” (or) Editor Menu -> Add Build Settings -> Add User Defined Settings. This will create a new entry for us.
3. Give the setting a name of “KEnv_BundleName”, “KEnv_BundleIdentifier, “KEnv_ServerURL”,”KEnv_LicenseKey”. The setting name can be anything, but I find it best to prefix with something meaningful to the project.
4. Expand the entry to show all of the environments. Enter your values for each configuration you have set up. For example, Debug and Release in our case. (Refer, Fig 1.1 — Adding User Defined Settings)

Fig 1.1 — Adding User Defined Settings

5. After User Defined Setting is added, we’ll need to update the Info.plist to use the values we set up. So go to Info.plist and change the value for “Bundle Name” to ${KEnv_BundleName}. Add ‘+’ and go ahead to add your keys like ServerURL, LicenseKey.
6. Now, for Bundle Identifier, Server URL, License Key add values with ${KEnv_BundleIdentifier}, ${KEnv_ServerURL}, ${KEnv_LicenseKey} respectively. Typically your Info.plist should look like below.

Fig 1.2 — Info.Plist

7. Now we just need to create schemes based on environments instead of targets.

You can now run each scheme and allow both instances of your app to be installed simultaneously. From Info.plist respective values for our User Defined Settings parameters will be taken. I have created two schemes.

Fig 1.3 — Schemes

Here are the screenshots for installing Debug and Release versions side by side on the same simulator with single target, different schemes and different configurations:

Fig 1.4 — Release and Debug app on the simulator.

I have got the required values from Info.plist [Bundle.main.path(forResource: “Info”, ofType: “plist”)] with dictionary values for ServerUrl, Bundle Name, License Key and displayed in my sample app. Respective values from Build Settings will be fetched from User Defined Settings and those will be used by the app.

Fig 1.5 — Debug and Release apps with respective values fetched from User Defined Settings.

So the next time you find yourself creating a new Target, determine if it’s really necessary, or if User-Defined Settings can give you what you need. Creating different targets can be the least approach in any case.

--

--

Kavitha Kumarasamy

iOS freak | mobile developer | front end developer | Reactjs | React-Native | dancer | A Mother | Marvel fan | Cyclist | Table Tennis enthusiast | a learner.