Three slightly different Apps from one code base Three slightly different Apps from one code base xcode xcode

Three slightly different Apps from one code base


Using different targets for different editions of Apps provides more flexibility and lets you easily change the bundle identifier and the icon etc once you specify a different plist file per target. However, the configurations are more deeply integrated with Xcode and you can adjust any build setting per configuration.

After some more research I figured out how to get the best of both worlds with just one target:

  • Create the desired configurations in Xcode: ProjectName > ProjectName > Info. For example:
    • Debug
    • Preview
    • Release
  • Now these three configurations are available for all the build settings.
  • The three Apps should co-exist on a device.I want to be able to have all three versions of the App on one device, for this all three types need a different bundle identifier. The original Identifier could be com.company.${PRODUCT_NAME:rfc1034identifier}.

    • To achieve this go to MyProject > MyApp (Target) > Build settings and click on the button (+) Add Build Setting
    • Add the new key ${APP_ID} and set the values like this and note that the release configuration should not have a suffix:

      APP_ID > 'com.company.MyApp-debug'       > 'com.company.MyApp-preview'       > 'com.company.MyApp'
    • Now in your Info.plist change the Bundle Identifier value to ${APP_ID}
  • You can do the same with the Bundle Display Name or the Icon attribute so that you can easily distinguish the app at one glance.

  • You can set Preprocessor macros for your configurations in order to be able to detect the current configuration in your code. This is done by default for the debug configuration: DEBUG=1.

Advantages

  • Since the three Apps have their own identifier, you won't override the latest preview build when testing the current App in Xcode.
  • Nicely integrated into Xcode and offers a high flexibility
    All build settings can now individually be changed per configuration
  • New configurations can easily be added by cloning existing configurations within Xcode
  • No need for additional targets
    Targets are IMHO better for completely different artifacts like libraries or testing targets that have a different code base.
  • The configurations can be used in code if required.
  • Different Service URLS etc. can be used for different environments. See this great post (Thanks to Jonah!) that shows how to do this using a special plist file.
  • No use of any hacky scripts which are hard to maintain

Disadvantages

  • With using targets it would be possible to exclude some frameworks from a type of App. So for example you could exclude some analytics library from the debug edition of your App.

  • Update: You can't use substitutions like com.company.${PRODUCT_NAME:rfc1034identifier} for User defined Build Settings. So you'll have to write out the bundle whole bundle identifier in this case.

  • Update: Some settings which should be made "configuration aware" move to the User-Defined section of the Build Settings, which might feel unusual for some developers.

The result

Result http://i.minus.com/jbwPgEiBra39dL.png


If you want all three apps installed on the device at the same time then you just have to use three separate identifiers = three targets with their info.plist.

I dont't really see a problem 'maintaing' three separate targets in one project. I do it all the time (with two targets, but nevertheless). It's actually a veryelegant solution.


In my applications I've often added a "run script" build step to copy an environment specific plist into place before building the app. With that approach I can swap the entire Info.plist so that I can change app identifiers based on build settings. I usually set the environment to build based on some environment variable which can be set or changed in the build target's settings.

Some of my coworkers took an alternate approach which does allow you to use Xcode configurations to determine the app's environment but I don't think that will allow you to change the application identifier: http://blog.carbonfive.com/2011/06/20/managing-ios-configurations-per-environment-in-xcode-4/