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