This is part in a series of blog articles explaining some of the interesting technical hurdles we encountered while building our new iPad puzzle game Flockwork.
We’ll soon be launching a Free version of Flockwork, so I wanted to explain how best to set up your Xcode projects if you’re planning to support two versions. The goals were:
- 1. Keep everything in a single Xcode project
- 2. Make it easy to share code and assets
- 3. Keep file sizes of the compiled apps as small as possible
1. Setting up a second target
The first step is to duplicate your existing target (for example MyAwesomeGame). Right/command click the target and choose Duplicate.
OK, what did Xcode just do?
- It created a new target called MyAwesomeGame copy
- It added a new Info.plist
- It autocreated a new scheme for building the project
First you’ll want to rename things more sensibly. Press ENTER with the new scheme highlighted and name it MyAwesomeGameFree.
Next, go into Build Settings for the MyAwesomeGameFree target and filter for two settings: first change “Product Name” to MyAwesomeGameFree.
Next, change the “Info.plist file” setting to MyAwesomeGameFree-Info.plist.
Of course, now you’ll also need to rename the file to match. You can also move it to a more sensible group, as Xcode dumps it in the root of the project by default.
Now is also a good time to modify the Info.plist, you may want to change:
- the Bundle Identifier (to match whatever you created in iTunes Connect)
- the icon files and default launch image
- Bundle display name
Finally you can rename the autocreated scheme – go to Product>Manage Schemes and rename the scheme to MyAwesomeGameFree.
Time to test it works! Choose the correct scheme from the dropdown, and run!
2. Detecting the target at runtime
It’s likely there won’t be too much difference between your paid and full versions: for example in Flockwork, most of the game is similar, but we only have 20 levels in the free version versus 80 levels in the paid version. For places in the code where you need different behaviour, you can do a runtime switch. We defined a boolean like this:
#define IsFree ([[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"] isEqualToString:BUNDLE_ID_FREE])
Then it’s easy to write code like this:
NSString *path = IsFree?@"levels_free.plist":@"levels_full.plist";
3. Selecting which assets will be included in each target
Now you have multiple targets, you need to be careful when adding new files to the project. You’ve probably seen this dialog many times. When you add a new file to the project, you’ll now need to ensure the correct targets are checked: make sure both targets are checked if its a file used in both versions, but only one target is checked if its only used in one version.
What about files which are already added to your project? If you go to Build Phases>Copy Bundle Resources you can see a list of all the files compiled into the target. It’s important to remove any you’re not using. For example, leaving in a full-screen splash from the full versions in your free version could easily add 2MB to your final app size. If you’re trying to get under the 50MB over-the-air download limit, that’s a lot!