Easy iPhone Application Versioning with agvtool
In which a semi-automated system for the versioning of iPhone applications is detailed. Said system ensures that the reader’s apps are always correctly versioned, and his users’ iTunes applications are never confused by an update of his beta builds.
Versioning your iPhone applications properly ensures that your app updates go smoothly, and also that when you make a beta build testers never get into the frustrating state where iTunes refuses to accept it because of versioning conflicts, leaving them to have to delete the older version, and its settings and documents along with it.
The system presented here is largely inspired by Chris Hanson’s “Xcode: Build numbers and versioning with agvtool”. I’m always referring to it when I’m creating new projects, and I thought that people might appreciate a more visual rendition, tailored to iPhone development.
First, some definitions. In this article, I’ll draw a distinction between build number and version number. A version number is the user-readable version string that the users of your app see - “0.4”, “1.1”, “2.5” etc. A build number is just a monotonically increasing integer. You’ll increase it by one when you roll a ‘real’ build that you want to test, and there may be multiple build numbers used between user-visible versions. For example, if you’ve finished version 1.0, and are working on 1.1, you may have intermediate betas that you term “1.1 build 121”, “1.1 build 122” etc. It’s the use of this build number that ensures that iTunes, for example, knows that this “Bodacious Application v1.1” is really a newer version than this other “Bodacious Application v1.1”.
Remember that there is no relationship between the build number and the version number other than that they both increase over time. You can choose when to change both numbers. You’ll probably only want to change the version number before a ‘real’ release, or perhaps major beta. Some people increment the build number on every Xcode build, but, personally, I find this a bit extreme. If you’re in a corporate environment, increasing it before every build-system build is a popular option. In my one-person-team world, I just increase the build number whenever I’m handing a copy of the app to someone else. Increasing it before every checkin to your version control system is another idea. If you’re so inclined, you can also tag the intermediate builds in whatever version control system you’re using with their build numbers, so that you can easily check out the code for any build a bug is found in.
agvtool is Apple’s command-line tool that makes using build and version numbers like this easy. After you’ve got it set up, you can just cd to your top-level project folder and type “agvtool bump -all” to increase the build number, and “agvtool new-marketing-version <new version here>” to update the user-visible version number (e.g. “agvtool new-marketing-version 1.2” to set it to 1.2). agvtool will update all the places in your project that the version numbers are stored, leaving you confident that your beta updates or app store submissions will go smoothly.
Sounds pretty great, eh? It is, once you’ve got it working, but unfortunately Xcode projects are not set up to use the system by default. It’s pretty easy to get it going though.
The first thing you’ll need to do is set up initial values for the versions. Open up your Info.plist file. The “Bundle version” row’s value should be set to your initial build number (this is the monotonically increasing integer, remember). You will need to add a “Bundle version string, short” row. Its value should be the user-visible version number - this is the one that appears as your app’s version in iTunes. If you’re interested, the ‘raw’ keys for these are “CFBundleVersion” and “CFBundleShortVersionString” (you can see the raw keys by Ctrl-clicking and choosing “Show Raw Keys/Values”). After you’ve set these, close the Info.plist window. This is the only time you’ll need to edit these strings by hand, agvtool will take care of it from now on.
Next, you need to tell Xcode you’ll be using agvtool. Open up your project, and double-click on the top-level project icon in the source list. Make sure that “All Configurations” is selected in the “Configuration” drop-down, and find the “Versioning” section. In the row that reads “Versioning System”, edit the value to read “apple-generic”. You’ll also need to edit the “Current Project Version” value. This is another copy of the build number, so set it to the same value you set as your “Bundle Version” in the Info.plist file. agvtool will make sure that this number, and the number in the Info.plist stay in-sync from now on with no manual intervention.
And that’s it! Close the project info window, and you’re set up. To test it out, open a Terminal window, cd to your project directory, and type “agvtool what-version”. You should get your build number back. Typing “agvtool what-marketing-version” should give you, after with some information about looking for it in some archaic places, the user-visible version number.
To increase the build-number (like I mentioned above, at the time of your choosing, for example, just before a checkin, or when you distribute a build to colleagues - you could even set up your automated build system to do this before building, then check in the changes it made to your version control system - although there’s a potential race condition there), just type “agvtool bump -all”.
To change the user-visible version number (again, whenever you choose, for example, before an app store submission, or a widely-distributed beta build), just type “agvtool new-marketing-version <new version here>”.
There’s more to agvtool and Xcode integration than this. If you’re interested, Chris Hanson’s aforementioned “Xcode: Build numbers and versioning with agvtool” is the place to start looking for more. What’s covered above is, however, all you need to know to use agvtool effectively with iPhone apps. I find it extremely useful, and also reassuring - I’m never wondering any more if I’ve remembered to keep all my version information in sync.