13

Hy there I would like to have three apps depending, which are based on the same code:

  1. MyAppDevelopment (Builds from Xcode that are deployed to the device)

  2. MyAppPreview (Beta testing)

  3. MyApp (Release)

It should be possible to have all of the three Apps installed on a device and they'd have their own icon to nicely distinguish them visually.

Now I know that I could have three different targets with their respective Info.plist file, but I would rather use Xcode's configurations so that I don't have to maintain three different targets. Is this possible using configurations, the problem is that the App identifier is stored in the Info.plist file, which can be defined per-target...

casperOne
  • 73,706
  • 19
  • 184
  • 253
Besi
  • 22,579
  • 24
  • 131
  • 223

4 Answers4

27

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

Besi
  • 22,579
  • 24
  • 131
  • 223
  • Good job! But did you check your release bundle identifier. is it "com.company.MyApp" or "com.company.MyApp-"? – Rok Jarc Jan 23 '12 at 16:15
  • Please note that instead of using the value `com.company.MyApp-debug` you could substitute the name of the configuration like so: `com.company.MyApp-${CONFIGURATION}` – Besi Jan 23 '12 at 21:25
  • Any help in determining where my build is breaking because only the release version (no changes to the bundle identifier) is working... – ganders Feb 24 '14 at 19:42
  • 1
    @ganders you can check the gist I made (See [my answer below](http://stackoverflow.com/a/10739917/784318)). This might help you if you follow these steps... – Besi Feb 25 '14 at 21:30
4

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 very elegant solution.

Rok Jarc
  • 18,765
  • 9
  • 69
  • 124
  • I like the idea of using configurations since all the build settings can be changed according to those configuration, so if I have configurations and targets I suddenly have a big matrix of configurations vs. targets. So I would prefer to just use configurations and use targets for "more different" artefacts like unittests or a library etc. – Besi Jan 23 '12 at 12:22
  • I see what you mean. But i don't think - hopefully someone will prove me wrong - you'll be able to avoid using targets. 3 different icons, for example, would also mean 3 pairs of icon files - each pair with it's own 'target membership' Jonahs' link is interesing, too. At the end you'll probably have to decide on one approch and stick with it. I'll definetly follow discussion on your question. – Rok Jarc Jan 23 '12 at 12:42
  • 1
    I managed to do it with only configurations. [Check it out](http://stackoverflow.com/a/8974224/784318) – Besi Jan 23 '12 at 15:41
  • The problem is: configurations are the correct way, but Apple doesn't love them, and refuses to make Xcode support them correctly (as you've already noticed, you're having to workaround Xcode bugs). In the long run, Apple will almost certainly change/break/remove configurations again (they did this when going from Xcode 3 to Xcode 4: immediately broke thousands of codebases that were perfectly legal but "Apple didn't like it"). A lot of us were burned before and have learnt to take the route of least resistance: accept Apple's solution (even if its a bad one) – Adam Sep 23 '13 at 13:39
2

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/

Jonah
  • 17,918
  • 1
  • 43
  • 70
  • This is a great blog post. I currently have all server URLs in one file and I really like the idea to have them in a plist file with the ability to have a dictionary for each configuration. I now managed to do also change the app identifier and the icon based on the configuration. See my answer for details. – Besi Jan 23 '12 at 15:45
0

As an addition to my described approach I have implemented the possibility to have different properties or settings per configuration.

I created a gist based on this Tutorial, which I have extended a little bit. I am using it in various projects and am quite happy with it.

The one major addition I have made is the ability to define a master environment, which will be used as a fallback for the other environments if no value is found.

Please check out the Readme.md for detailed instructions how to setup the whole thing.

https://gist.github.com/2782045

Besi
  • 22,579
  • 24
  • 131
  • 223