How to create multiple targets for Xcode iPhone Projects

If you want to build multiple versions of an application from a single Xcode project, you would want to cerate multiple targets. For example, when you want to release a free version and also a paid version, you should create 2 targets in that Xcode project.

This tutorial will cover the how-to and the pitfalls in creating multiple targets.

 

1 Create a New Target

Lets assume we have an application call "Flowers", which is a paid version. And we would want to create a lite version that has some reduced functionality but is free. It is to note that both the paid version and lite version would share the same code, with only some differences.

Firstly, create a new target. Under Groups & Files, right click on Targets > Add > New Target  (Figure 1 below).

Figure 1

Select Application as the new target template.

Enter "FlowersLite" as the target’s name.

Pitfall: When a new target is added, it would not copy over any resources, compiled sources or libraries from the original target! You would need to copy them over manually (drag and drop from Flowers to FlowersLite). If you copy all correctly, you would see figure 2 below. The numbers in brackets indicate number of files, hence they should be the same for both the targets.

Picture 5

 

2 Info.plist

We could define properties, such as application name and icon files, for each of the target. Figure 3 below shows "Flowers-Info.plist" for the full version.

Picture 2

For the lite version, the "FlowersLite-Info.plist" could be changed as necessary. For example, the bundle identifier for the lite version could be "com.just2me.flowerslite" and the Icon file could be "Icon-lite.png" instead (as in figure 4 below).

Picture 3

 

3 Writing Preprocessor Codes

Preprocessor codes are used to determine which code would be used during compile time. You may want different targets to run different section of the codes using preprocessor codes. For illustration, we will add a LITE_VERSION definition to the lite version.

Under Targets, right click FlowersLite > Get Info.

Change Configuration to "All Configurations" (this is important).

In the Preprocessor Macros field, add the flag LITE_VERSION (see figure 5 below). Note: If you don’t see the section "GCC 4.2 – Preprocessing", change the active SDK to base SDK and try again.

Picture 6

With the flag LITE_VERSION defined, we could now write codes that will be compiled for the different targets. An example is shown in figure 6 below.

Picture 7

When the active target is selected and being run, it will work and print correctly.

 

4 Managing Resources

You could copy different resources (having same name but different) to the targets. Resource could refer to xib files, images, etc.

For example, if the lite version has a different default loading screen, you could create another Default.png for the lite version. Note: To make it work, you have to copy the correct Default.png to that target’s "Copy Bundle Resources", and also to remove the incorrect Default.png.

 

5 Build for Distribution

When you are ready to compile the application for submission to iTunesconnect (release distribution), there is one last important thing worth checking.

It was pointed out in section 3 (Writing Preprocessor Code), that you have to change the configuration to "All Configurations" before you make any changes to the target properties (in this tutorial is adding the LITE_VERSION flag). That is important as the same flag is needed for all configurations, including distribution.

PS: I am stressing this last step as I had made this mistake.. and it resulted in my lite version being released as a paid version because the LITE_VERSION flag was only set for Debug, and not for Distribution!! I did not realize this mistake when compiling for Distribution, as I could only compile the app but not run it on simulator/device..

Share and Enjoy
    Tagged with:
    Posted in Development, How-to, iPhone
    • RoberRM

      Thank you very much for the tutorial. It will surely be very helpful. ;)

    • Stu

      To address the concern of accidentally not having LITE_VERSION set as a preprocessor macro (and thus releasing a full version accidentally), I put this little snippet of code into a header file (it only needs to be in one place in the codebase, just make sure it’s common to all configurations):
      #ifndef LITE_VERSION
      #ifndef FULL_VERSION
      #error You probably forgot to specify if this is the Lite or Full version of the app
      #endif
      #endif

      I then set FULL_VERSION explicitly in the paid version (See step 3 above). This means that any configuration that didn’t get a macro of either LITE_VERSION or FULL_VERSION won’t compile.

    • Pingback: Just2us » Blog Archive » Tutorial: Creating multiple targets for … | IPhoneMate

    • Mark P.

      Hi,

      First of all thanks, your tutorial seems to be very straighforward, and so far the best I have seen from some others, it seems to have all I need for my project.

      However I have a question. I create the new target and go through all the steps in step 1. Then when I try to add the target specific resources I have problems. for example as you say: “To make it work, you have to copy the correct Default.png to that target’s ‘Copy Bundle Resources’, and also to remove the incorrect Default.png.”, I am not able to follow your directions, e.g. if I try to copy the .png file first, I get an alert saying it cannot do that. Also, if I first delete the .png file, and then try to copy the new Default.png file. I get the same alert message.

      From what I understand, when creating a new target and copying the original target’s resources, is not actually making a physical copy, but it is acting like a “view” in my perception (e.g. the two groups of resources in the two targets are actually only “references” pointing to the same single resources on disk. So when I first delete the resource on the new target, I am actually only deleting the reference, so when I try to copy another Default.png, I won’t work because of the original .png file still on disk.

      Does this make sense?? :) Sorry on the long post!

      Am I doing something wrong, or missing something?? Your support is greatly appreciated, I guess this is the only thing preventing me from getting me where I want to get to.

      Thank you in advance!

    • http://www.just2me.com samwize

      @Mark

      Yes your understanding is correct. The resources in the targets references to the actual copy.

      Lets say you added both the default.png under Groups & Files. The first in /full/default.png and the second in /lite/default.png.

      Under the new target’s Compiled Bundle Resources, you should delete the default.png, then drag the /lite/default.png to it. There should be no error.

    • Mark P.

      Thanks, I got it. What I was doing was actually checking the “Copy…” checkbox, so the resource was copied physically into the project’s directory, hence the name conflict error. Now when adding a new resource, I save it in a separate directory, and when importing to the project I add it as reference, so I only uncheck the “Copy..” checkbox. This way if I have two resources with the same name for the different targets, I click on Get Info and select the correct target to be added (which is just another way to do the same.)

      Thanks

    • Tal

      Hi,

      Thanks for your post, it’s very useful. There might be something missing though (or maybe I missed something) – After doing the steps above my lite version does not compile.

      I’ve got strange compilation errors concerning CoreData objects:

      /iAppDelegate.h:14: error: expected specifier-qualifier-list before ‘NSManagedObjectModel’
      iAppDelegate.h:15: error: expected specifier-qualifier-list before ‘NSManagedObjectContext’
      ….

      and so on. I tried removing and adding the CoreData framework but that does not fix the problem..

    • http://www.just2me.com samwize

      @Tal
      I am not sure the error is due to the steps here. But you might want to check that the frameworks are in the lite version target > Link Binary With Libraries

    • Tal

      Yeah it’s there. I’ve even removed them and added through ‘add->existing framework’ and it doesn’t work (only in the lite version). Odd.

    • Tal

      Problem solved:
      I couldn’t find what was the difference between the two target’s configurations. However, using ‘duplicate target’ on original target created a target copy which worked just fine with CoreData.

      So.. it seems that ‘duplicate target’ may be a better starting point than ‘add new target’ as it solves non-standard configurations of the first target.

      Cheers

    • Pingback: versatilemind.com » Blog Archive » Setting up multiple targets for iPhone projects

    • Pingback: Creating multi-variants of an iOS app from a single Xcode project – Cybersam

    • Bluebedi

      thanks for the info.
      I’ll tryit out

    • http://twitter.com/jkhowland Joshua Howland

      I know this is a 2009 post, and it is awesome! Thank you so much.

      Is there any chance you could write another post like this for Xcode 4? Or do you know of one?