There are more than 15,000 apps in the app store and hundreds are added daily. You need a way to show off your awesome creation to the millions of potential buyers.
One of the most effective marketing tools for small fish is releasing a free version of the app. To do that, you could copy the whole project, but then you would be duplicating code, maintaining it in two places and what if there’s an update?
In this post I’ll show you a better way: building two versions of your app from the same xcode project using targets and some other magic. Source code for the sample project is available here: twoForOne.
I’ve built a very simple app, it displays an image in UIImageView and has two buttons. Looks like this:
This is the pay-for version. The free version will have a different image (blue) and the expensive button will be hidden. This will demonstrate how to use a different set of resources (red image vs blue image) and how to modify code (hide button) at compile time based on which target is active.
First we’ll add a new build phase to the target. This will allow us to modify the background and icon resources later. It’s easier to add it now because we only need to do it for one target (it will be automatically duplicated with the target.) Right click on the target and select Add / New Build Phase / New Run Script Build Phase (you can click on the screen shot to see it better).
Type ./targetSetup in the script window. targetSetup is the script that does the work; we’ll create it later.
Take the Run Script build phase and move it to the top of the stack. We want this to run before any other build phase.
Now duplicate the target and name the new target twoForOneFree (right click on the target and select duplicate). (If you don’t have a right button on your mouse, go and get one. Those stupid soap bar mice are so not cool anymore… were they ever?):
Notice that xcode made a duplicate of the Info.plist file:
Info copy.plist is not a very nice name, so rename it to InfoFree.plist. You also have to tell the target to use the renamed plist, so open the info window for the twoForOneFree target (right click on the target and choose get info- you see how much nicer it is that you have a right mouse button?), make sure that you are looking at All Configurations and All Settings and type info into the search box. Change the Info.plist file setting to point at InfoFree.plist:
In the same info window change the product name to twoForOneFree (this will be the name of the .app and by default this is what the iphone will display under the icon.) Type product name in the search box to find the setting quickly:
The compiler doesn’t know which target is active, so we’ll define a directive that will be easy to use in code to create version specific modifications (this is what we’ll use to hide the expensive button). Still in the same window, search for other c. If you find a key called Other C Flags, you are in luck: set it to -DTWOFORONEFREE and skip the next paragraph.
If not, you need to create one. At the bottom of the window click the settings (gears) button and select Add User-Defined Setting and type OTHER_CFLAGS for the key and -DTWOFORONEFREE for the value:
This instructs the compiler to define the TWOFORONEFREE macro for this target.
Look at lines 18-20 intwoForOneAppDelegate.m. We use an #ifdef directive to hide the expensive button if this macro is defined:
Obviously you;ll need to do more than hiding a button. You can use this same approach to do other modifications to the free version. You can also define a TWOFORONE macro on the twoForOne target for more flexibility (you can use that macro to add features that the free version doesn’t have.)
Now we’ll look at modifying resources. We want the free version to have a different bacground and also a different icon. I created two versions of the background, you can see them in the Images folder:
The UIImageView uses bg.png. The other two files, bg_red.png and bg_blue.png are not added to the xcode project (you can add them, but it’s not necessary). I want to copy bg_red.png to bg.png when building the expensive version and bg_blue.png to bg.png for the free build.
Similarly, there is a Icon_red.png and Icon_blue.png at the project level, one of those will be copied to Icon.png to get the correct icon.
We already added the run script build phase that calls the targetSetup script. Now let’s create s shell script. Right click on Resources (so much milage out of that new right mouse button!) and select Add / New File. From the dialog select the Other category (all the way at the bottom) and then the Shell Script type:
In the next dialog enter targetSetup for the name and uncheck both targets (we don’t want this script to be copied into any of the targets at build time):
The script itself is very simple. It copies the correct bg file and Icon file based on the selected target (the build process conveniently sets an environment variable with the target name).
echo .targetSetup: $TARGET_NAME
if ($TARGET_NAME == “twoForOne”) then
cp Icon_red.png Icon.png
cp Images/bg_red.png Images/bg.png
if ($TARGET_NAME == “twoForOneFree”) then
cp Icon_blue.png Icon.png
cp Images/bg_blue.png Images/bg.png
That’s it! Just set the desired target and you can build the expensive or free version from the same project:
Here are some screenshots. You can see that even the icons are different (as expected):