Another one of those, “I’m going to post it so I know where to find it next time” posts. 🙂
This was largely taken from a post at the iPhoneDevSDK forums, but I’ve clarified a few things, handled a few pitfalls that you might run into, and added some pretty pictures.
So you made an iPhone game or app and it’s selling in the iTunes App Store. Now you want to make a free “lite” version to get more people to know about it and drive sales to the paid app. Or maybe even put some ads in the free version. People get the free version, like the functionality, want to get rid of the ads or get access to the extra features / levels of the full version and pay up. And if they don’t, you hopefully at least make a few bucks from ad revenue. A common scenario. But what’s the best way to go about programming such a thing?
OK, you could take the most obvious, brute force method possible – copy the project, make a new project, disable some features, put in your ads, and release. Great. Now you have two separate code bases to keep up. Find and fix some bugs in the main version, you now get to double your pleasure and track them down and fix them in the lite version. You could use version control to make a lite version branch, which at least allows you to merge changes across branches, but that’s still gonna get messy.
So you really want to keep it in one project, one code base. Fortunately, there’s a pretty easy way to do this. If you’ve been working with XCode, making iPhone apps more complex than Hello World, you’ve seen the “Targets” item in the Groups and Files panel. The one that looks like it was sponsored by a certain retail chain.
And in there, is usually a single item with the same name as your app. You have probably double clicked that numerous times to set various build properties. What you can do is to make another target for the lite version of your app. So let’s make a new target.
What you DON’T want to do is right click on the Targets item and say “Add New Target…” That will cause you about 27 minutes of frustration trying to figure out where the settings are that we will soon set.
The RIGHT way to do it is to right click on the existing target and choose “Duplicate”. If your original target was called “MyCoolGame”, that’s going to give you a new target called “MyCoolGame copy”. Rename that to “MyCoolGameLite” or “…Free” or whatever suits you.
Now, in your Resources folder, you should see a new plist file called “Info copy.plist”. You probably want to change this to “InfoLite.plist” or something of the sort. These renaming changes aren’t technically necessary, but if you are the type of person who leaves files named “whatever_copy” sitting around in a finished project, don’t even talk to me! 🙂
Now, in the settings drop down in the top left, you’ll see an “Active Target” setting listing your two targets. Select the new lite version target. At this point, you also want to set the Active SDK section in that dropdown to whatever setting has “(Project Setting)” next to it. The “Active Configuration” section is not important, set it to whatever you want.
Note that the active target icon will now have a little green circle with a checkbox on it. Double click on the new active target to open up the target info panel. Go to the Build tab, and down to the Packaging section. Make sure the dropdown in the top left of this panel says “All Configurations”. Here, you want to verify that the changes you made to the name of the InfoLite.plist file show up here. And you want to change the product name to show that it’s a lite/free version.
Warning here: this Product Name is what shows up under the icon on the device. If it’s too long, you’re likely to see something like “MyCoo…Lite” instead of “MyCoolGameLite”. Play with the name a bit to get something that indicates it’s a lite version, is short enough to fit under the icon, and still still ties your lite app to the full app.
Then, still in the info panel, jump over to the Properties tab. Here you can set an alternate icon for your lite version. For your main version, you probably have an icon file specified here named something like “Icon.png”. You can edit this icon to put a little “LITE” stamp or whatever on it, saving it as something like “IconLite.png”. Add that new icon file to your project and specify it here.
Now we go back to Build tab. This next setting can be tricky because if you didn’t follow the instructions exactly, you won’t even see where to set it. It’s important that:
1. The Active SDK is set to whichever item shows “(Project Setting)”.
2. The Active Target is set to the Lite version target.
3. The configuration dropdown in the info panel is set to “All Configurations”.
4. Also, if you created a new target instead of duplicating the existing target, you will waste plenty of time trying to get to the next step.
So, assuming you did everything just right, in the target info panel, Build tab, you should be able to scroll down and get to a section called “GCC 4.0 – Language”. In there, you’re going to see an empty field called “Other C Flags”. Edit this field to add something like “-DLITE_VERSION”:
Note that setting this will also set “Other C++ Flags”. No problem. The -D I believe stands for define, and is essentially the same as adding a precompiler definition called LITE_VERSION, just as if you had typed this into your code:
#define LITE_VERSION
This definition will be available anywhere in any of the code for your project. But ONLY if you are compiling to the lite version target. Now comes the fun part. In your code, where you want to distinguish features that go in the full or lite version, you can use:
#ifdef LITE_VERSION
If that’s true, you’re compiling the lite version, if not, you are making the full version. Here’s an example. Say you have an app that has some special features that you get to via a “Pro Features” button. In the lite version, you want this button disabled, or maybe even just not there at all. As a matter of fact, in the lite version, you want a button that links to the app store to let the user easily purchase the full version of the app. Of course, if the user has the full version, they shouldn’t ever see this button. You create both of these buttons and hook up their respective behaviors, and then you do something like this:
[c]- (void)viewDidLoad {
[super viewDidLoad];
#ifdef LITE_VERSION
[proFeaturesButton setHidden:YES];
[buyFullButton setHidden:NO];
#else
[proFeaturesButton setHidden:NO];
[buyFullButton setHidden:YES];
#endif
}[/c]
Now you just set active target to the main version, compile, set to lite version, compile again. Same code base, two versions. Yay!
Now that’s a rather simple example. You may want to make something more robust, and ideally you will structure your code so that there are not #ifdef/#else/#endif directives sprinkled all over your code. But that’s how it works, and hopefully this post has gotten you started on the mechanics of it.
Thanks for the handy post. I’ll be sure to be using this snippet when I start to make iPhone apps/games. I’m learning next month when I have the mac/phone combo and I’m really excited to get into it. I’ve just bought the Beginning iPhone Development and the Red Book on your recommendation.
I’ll my eye on this blog as it should be handy learning from an Actionscript perspective.
So keep up posting good Actionscript and iPhone info 🙂
As always, very useful stuff, and right when I need it.
OT: If my nearly completed app is successful I’m going to want to make a flash mobile version. Does anyone know of a Actionscript framework for creating iphone style table/cell navigation?
Another small tip that works well this setup (especially if you didn’t plan for the lite version and have half a dozen provisioning profiles for development, ad hoc, etc.): you can set the app id (in each target’s info) independently for each target and you can set the code signing settings (in each target’s build settings) independently for each configuration/target combo. Then when you want to build, say, the Ad Hoc version of MyCoolGameLite, it’s just a matter of picking the right combination of SDK / Configuration / Target from the menu at the top left 🙂
Just what I needed. Thanks a million.
Hi Keith,
well done! Thanks a lot for this detailed tutorial.
It’s working fine for me with building and testing the app with the simulator and the iphone. But when I am trying to submit the application to the appstore I am getting the following error with the Application Loader:
“Application failed codesign verification”
I used a different provision certificate and also a different bundle name. Do you have any ideas? Spent a lot time on this issue :/
How are you doing the preparation for the appstore?
Thanks
Tom
Thanks for this great article! I have one question though: Let’s say your main (paid) app is already at version 1.2. When submitting your new “lite” app to Itunes Connect, will you be calling it v1.2 right from the start or will the lite version have its own versioning?
Great information! I am using it now to help release my free version.
Thank you!
-Mike
[Luke, Thanks for the additional information regarding id’s and configurations – I will be using it!]
[Rob, I have the same issue but have simply decided to keep the versions in sync.]
Thank you for the tutorial. Could you tell me whether I should use different AppID fo Full version and Lite version of my application? I would like to have both versions in AppStore.
Thank you for the awesome instructions. I was able to create a lite version for my app in less than 3 hours. It took 1 hour to follow your instructions carefully, 1 hour to make my own custom code change, and another 1 hour to submit the app to Apple.
I had one minor thing I had to change before ITC would accept my binary.
The Bundle Identifier needed to be different from the full version app (I thought I had a provision set up using the * to include all my apps, but anyways…)
Thank you again for sharing the instructions!!
Thank you again, the lite version I created in 3 hours following your instructions just got approved in less than 48 hours!
i knew roughly how to do it but this saved me half the time and pain for sure! thx!
Fantastic blog! This answered my problem completely.
One thing I’d like to clarify is regarding your para:
“Warning here: this Product Name is what shows up under the icon on the …your lite app to the full app.”
This is not completely true. The string displayed under the app icon can be altered in the info.plist. Just modify (or add) the key “Bundle display name” to whatever you want the string to be displayed.
Cheers!
The duplicated target contains the *-Info.plist file from the original (which I assume is function as designed). But would you not want to distribute with the *Info-plist copy (of whatever name you called it?). And you’d therefore have to modify the new target’s ‘Copy Bundle Set’? Have I got that right?
Great article! One question though – I have an app where the user stores some settings using the [NSUserDefaults standardUserDefaults] and also the app allows the user to record some sound files. I found that when I run the lite version and make settings and record sounds then run the full version, these appear to be in different “sandboxes” or something because each app is storing it’s own settings and sound files. How do developers normally deal with moving from a lite version to the full version while keeping all settings and things like sound files written to the application documents directory intact? Thanks.
Nice…thanks for the tips, Keith. Definitely helped me out.
Thank you for the explanation! It only took me a little more than one hour to split the project and it works perfectly.
Hi, I’m having some trouble getting this to work.
After duplicating my target, I changed “Info copy.plist” to “InfoLite.plist”, and changed the “Info.plist File” entry to InfoLite.plist in the build section.
When I clicked on “Properties”, it said “The source plist file (used to generate Info.plist) has non-standard content and needs to be edited as a text file. The inspector fields, which you usually see here, cannot be used as the file could not be parsed, given the non-standard content.”
When I open InfoLite.plist, it has exactly the same content as Info.plist (as should be expected since it is a copy). When I try to build, it fails with the following error: The file “InfoLite.plist” couldn’t be opened because there is no such file.
Great Article!
One note about Default.png (not mentioned in the article)
You can use a different Default.png in Lite version storing it a folder like “Resources-Lite” and target just for lite (as normal Default.png is target to normal build)
(The same thing should be with the iTunes Icon for Ad-Hoc distribution)
At the same way you can store the Icon.png in the lite resource folder and use the same name as the full product icon.
(excuse me for my poor english)
Excellent tut.
I’ll try it out today.
Thanks
Note, don’t put any spaces between lite and your program name… for some reason there’s a bug with xcode that won’t show the stupid plist in the properties if you do that.
Hi Bobo,
I don’t suppose you found a way to resolve this problem.
I made the same mistake and even restoring from backup I still keep getting the same problem. Obviously some files left lying around.
very useful tutorial! thank you