Many From One
Building one app from one code base is pretty straight forward (all other complexities of Xcode development notwithstanding, of course). Building more than one app from one code base is a bit less intuitive, however. Recently someone wrote about using git, a source code control tool, to manage multiple app versions. This is an interesting approach, but I think breaks down when you start needing to churn out say… 7 or 8 or more distinct renditions of the same app. It also suffers from then having multiple full copies of the code base to, one for each version. Bug fixes have to be applied to all of them. A current project with which I am involved is facing this challenge now: many apps from one code base. Here’s what we’re doing (so far) to keep the “pain” to a minimum in order to produce 7+ apps at once.
The project in question has an app (or course) that talks to a backend for its content. The app itself, if you strip away the UI, is really a framework for the content. The first incarnation of the app has access to all the content. We are now adding more versions of the app, which we will offer for a lower price or perhaps for free depending on the content available in each, which will provide access to well defined, but limited amounts of the same content. But the framework for all of these apps is really identical to the original app. That is to say, the code for the “smaller” apps doesnt need to be different*, only the content does, which is controlled by how each app interacts with the backend. (* Ok, so there are some changes to the code, but they really have been minimal to make it a little more generalized to support multiple apps.) So how’d we do it?
So far, I have started by duplicating the target of our main app once to prove the concept that we should be able to use multiple targets. That results in a new target with it’s own “Info.plist” equivalent file. That is basically the only new file, which you would expect, since each target will build a unique app with it’s own bundle identifier, bundle name, and all that. Of course, each unique target has it’s own set of build settings, which is a key to making this scheme work.
In our case, each version has an identifying, compiled-in, version number (if you will). So we accomplish that by defining a compile-time macro in the build settings:
Then in code, we can deal with this like so:
[code lang=”objc”]
+(NSInteger)edition
{
#ifdef EDITION
return EDITION;
#else
return 1; // Effective edition of existing app
#endif
}
[/code]
Multiple targets are great, but you might be wondering: how do I build them all at once? The answer is: use the command line! While the Xcode IDE does not seem to offer an easy way to build all targets with once click (which, by the way, would be nice if it did!), you can do this from the command line easily using xcodebuild (the same tool that Xcode actually uses behind the scenes).
The xcodebuild tool includes an option to build all targets. So with a single command, you can build all your targets:
[code]
xcodebuild -alltargets -configuration Debug
[/code]
Xcodebuild has a lot of other options that lets you choose schemes, SDKs, etc. Type xcodebuild -help to see them all, or type man xcodebuild at the command line for the Unix man page, or check the Xcode help system for documentation.
It is worth noting that you can implement Continuous Integration (CI) systems to build your iOS apps, and they will likely include direct use of xcodebuild in a script launched by your CI server. (We don’t do this for this project, but in another life I lead we do.)
As this project progresses over the next few months, I’ll report again on any gotchas we run into, or any pleasant surprises for that matter.
Your thoughts? Let me know in the comments.
Nice post! That’s an interesting solution for build many apps from one base. I must say I’ve never thought of that.
In your case, if I understood well, you need multiple versions to deliver each one the right amount of content from the same backend, right?
But why don’t you use In-Apps purchases or authentication on server for making this “filter”? Is there an special reason for that?
Best,
Marcílio
Actually, we are going to do that too. A single “edition” will contain quite a bit of content, and within any given edition, various “peer” editions will be available for in-app purchase. Buying any edition essentially modifies the list of editions’ content from which a user can see content. Thanks for the comment!
Have you tried creating a Scheme that builds all the targets instead of using xcodebuild? We do multiple enterprise builds from a single code base. For testing / development, a scheme is used that only includes one target. For distribution, a scheme is used that produces archives of all targets.
That’s a great suggestion. Thanks! Schemes are one of those Xcode4 things I need to spend more time with. This project is the first one I’ve done where multiple targets are involved, so I will definitely look again at how schemes can help here. Sounds like that is the way to avoid the command line!