Three slightly different Apps from one code base

5.1k views Asked by At

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...

4

There are 4 answers

4
Besi On BEST ANSWER

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

4
Rok Jarc On

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.

1
Jonah On

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/

0
Besi On

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