Search code examples
iphoneiosxcodeinfo-plist

Three slightly different Apps from one code base


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


Solution

  • 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