2

I'm trying to create a way to be able to distribute a beta version of my app via Testflight without overwriting the production version. I'd like to be able to know in the code whether it's a beta build or a production build (i.e. somehow define #if BETA_VERSION, similar to the global DEBUG variable), and I'd like to be able to differentiate it with a separate app icon on the springboard, as well as a different app name (i.e. MyApp Beta or similar).

I set up a beta configuration by duplicating my release configuration, and I already have a provisioning profile for AdHoc builds (I've been distributing via Testflight for the last six months or so). I know that to change the app name I need to change the bundle display name property in the project's plist file, but I'm not really sure how to make a separate "profile" to hold all of these changes.

I've tried reading through this article, but I couldn't get it to work and I inadvertently messed up all my provisioning profiles when going through the instructions.

I've been struggling with this for a few weeks now. The details of this process are pretty opaque, so any detailed instructions or pointers are particularly appreciated.

Thank you in advance!

PS it probably doesn't help that I'm really confused about the relationship between targets, schemes, and configurations in Xcode.

Mason
  • 6,893
  • 15
  • 71
  • 115

1 Answers1

2

I use three configurations in my project: Release, Beta and Debug, where Beta is a duplicate of Release. In each of the three configurations, I'm including the following in my target's build settings:

GCC_PREPROCESSOR_DEFINITIONS = $(inherited) CONFIGURATION_$(CONFIGURATION)

What this will do is define a separate preprocessor macro for each configuration. In your code, you can then do the following:

#if defined(CONFIGURATION_Beta)
    // Something that should only happen in Beta builds
#endif

You can define additional build settings per-configuration in the “User-Defined” category (at the bottom of the build settings in Xcode), and then reference them in your Info.plist file. For example, you could define a custom BUNDLE_ID build setting that's different for Release, Beta and Debug builds, and then set the value of CFBundleIdentifier in your Info.plist file to ${BUNDLE_ID}, which would allow you to install Release, Beta and Debug builds side by side on your device.

Update:

If you want to see a good example of how to set all of this up, check out the project configuration in Cheddar for iOS.

Cameron Spickert
  • 5,190
  • 1
  • 27
  • 34
  • Amazing, thanks Cameron! Few follow up questions. 1. I'm not seeing 'User-Defined' in the build settings. The closest thing is in the Preprocessor Macros section (presumably where I can add `BETA=1` if I want). Where should I look? 2. Where does the line `GCC_PREPROCESSOR_DEFINITIONS = $(inherited) CONFIGURATION_$(CONFIGURATION)` actually go in the build settings? I tried adding it to the Preprocessor Macros header, it generated a bunch of stuff. Is that right? 3. After this stuff is done, how can I assign a new icon to the beta builds for the springboard? Thanks! – Mason May 21 '14 at 17:50
  • 1
    The “User-Defined” area is at the bottom of your target's build settings. Click on the project file in the left sidebar, then click on your target, select the “Build Settings” tab and scroll all the way down. If you don't see the section, click the “+” at the top of the screen (next to “Levels”). You should see something like this: http://cl.ly/image/142Y1G3H2U3i – Cameron Spickert May 21 '14 at 17:52
  • 1
    The “Preprocessor Macros” setting is the right one to use for `GCC_PREPROCESSOR_DEFINITIONS` (the latter is just the raw key you would use in a `.xcconfig` file). – Cameron Spickert May 21 '14 at 17:53
  • Does the BUNDLE_ID build setting require a wildcard app ID? Based on your screenshot, it looks like it does. Mine is hardcoded (lack of foresight on my part). What's the best way to deal with this? – Mason May 21 '14 at 18:06
  • 1
    Nope, no wildcard necessary. Just define `BUNDLE_ID` to be whatever you want in your build setting, and then replace the value of `CFBundleIdentifier` with the string `${BUNDLE_ID}` in your Info.plist file. – Cameron Spickert May 21 '14 at 19:07
  • 1
    If your bundle IDs all use the same prefix, you should be able to use your team provisioning profile to install all of your test apps on devices. Otherwise, you can create separate app IDs and provisioning profiles in the developer portal. – Cameron Spickert May 21 '14 at 19:08
  • 1
    Oh, and regarding the app icon—if you use asset catalogs, you can use the “Asset Catalog App Icon Set Name” build setting to different icons for each build configuration. If you don't use asset catalogs, you'll need to define another custom build setting with your icon file names and include them in your Info.plist. Here's what the asset catalog build settings look like: http://cl.ly/image/0U3a2I1K0738 – Cameron Spickert May 21 '14 at 19:11
  • 1
    Added to the main answer as well, but you should check out [Cheddar for iOS](https://github.com/nothingmagical/cheddar-ios) for a great example of how to set all of this up. – Cameron Spickert May 21 '14 at 19:13
  • Just did all of this, works perfectly. Thanks so much! – Mason May 24 '14 at 01:18