Monday, April 4, 2011

iOS Dev, Beta & Production builds installed side-by-side

A development and testing pattern I adopted early on for my iOS projects was to configure projects such that development, ad hoc test and release builds could all be installed on my device at the same time. This allows for side-by-side testing and easy comparison of the builds, each being at different states of completion at any point in time.

For example, this iPhone screen snapshot demonstrates dev, beta & release builds of my hobby project River Level installed side-by-side.

Dev, beta & release builds of River Level installed side-by-side
iOS differentiates apps by their Bundle Identifiers (CFBundleIdentifier) which are defined in the Project-Info.plist.  A Bundle Identifier looks like a reverse DNS address, e.g. "". What I like to do is to set the Bundle Identifier to different values for each build configuration, thus allowing each to be installed separately. I don't do this manually, though, as I'll explain below.

Note that some iOS features – like Push Notifications, Game Center and In-App Purchase – require the Bundle Identifier to match the value configured in iTunes Connect so you can test these features. In those cases this technique won't be effective, unless you set up multiple app instances in iTunes Connect for each build configuration.

The other parameter I customise per build configuration is the Bundle Display Name (CFBundleDisplayName). This is the app name as displayed on the home screen. iOS doesn't require these names to be unique, so if you changed the Bundle Identifiers without changing the Display Names you would end up with multiple instances of your app all with the same name and icon, making it difficult to work out which build is which.

My convention is to append "∆" to dev builds and "ß" to ad hoc builds.

To customise the Bundle Identifier and Bundle Display Name per build the process is:

  • Append ${BUNDLE_ID_SUFFIX} to the "Bundle identifier" in Project-Info.plist.
  • Append ${BUNDLE_DISPLAY_NAME_SUFFIX} to the "Bundle display name" in Project-Info.plist.
Custom variables appended to Bundle Display Name and Bundle Identifier values

Note that with no other changes these variables will be expanded to empty strings and so will have no effect. This is how I handle Release builds, so they are submitted to the App Store with standard values.

The next step is to define the custom values for each build configuration.  My convention is:

Development (Debug) builds:

Ad Hoc builds:

Release builds:
  Neither of these settings is defined.

The place to put these settings is in each relevant Build Configuration of the Project. Note: some people edit the build configuration for their Target, but I recommend only doing this if you need a setting specifically for a build target.  If you only have one target, edit the build settings for the whole Project.  That way, if you add Targets later they will inherit the Project build settings.

To add custom settings to build configurations, in Xcode 3:

  • Select menu "Project" / "Edit Project Settings"
  • Select "Build" tab
  • Select a build configuration in the Configuration list (e.g. "Debug")
  • Select "Add User-Defined Setting" from the command list (bottom left corner pulldown)
  • Add a user-defined setting for each of "BUNDLE_DISPLAY_NAME_SUFFIX" and "BUNDLE_ID_SUFFIX" with the values you choose.
  • Repeat this for each build configuration that you want to install separately to the others.

User-defined settings for a Debug build configuration
In Xcode 4, the process is similar, although the UI has changed.  Select your project; select the "Build Settings" tab, then select "Add Build Setting"/"Add User-Defined Setting". You can set the values for Debug and Ad Hoc at the same time with the new UI.

To see any user-defined settings, scroll the build settings table to the bottom; or use the "Show" list to filter only "User-Defined Settings" (Xcode 3).

To delete a user-defined setting, highlight the setting and hit the delete key.

That's it. Now re-build and install and the app should appear separately to the other builds. Feel free to install as many different builds as you feel like.


  1. This works very well. However, do you have any issues debugging from Xcode on the device? When I build for Device/Debug the production version of the app launches, not the ∆ version. It seems like Xcode is sending some wrong info, but I can't seem to find the setting

  2. @dmorrow: I don't remember ever seeing that problem where the wrong build is debugged. If you work out what was wrong let me know in case anyone else hits the problem.

  3. 1. There is a problem when you need a title translation. It just doesn't work because overwritten by InfoPlist.strings values.

    2. And a nice tip: if you don't need to change "Bundle identifier" you can set different Product Names in project settings. :)

  4. Year I ran into the push-notification certificate issue :(
    I'm going to try to create 3 different appids... stupid Apple.

  5. @Chris Miles Thanks for sharing this info.

    Currently I am using Xcode 4.6 and I added Debug and Release setting but where should i set Ad-Hoc setting?

    In XCode-5 this has changed.