Recipe: Automatic Version Number, Build Number & Build Date Handling

Dealing with build and version numbers in applications whether for Desktop MacOSX or iPhone applications always seems like a bit of a black art, here’s the short version of how to set up a consistent and maintainable  system for dealing with version numbers in Xcode.

The Basics:

  • There are two distinct kinds of version numbers in iPhone and MacOSX apps:
    • User readable version numbers –  these are what you typically see in about boxes. This is often called the “marketing version number,” like “OS X version 10.6.6.” It’s a convenient string for public consumption.
    • The Build Number – this is the “real” version number that represents the a milestone in your distribution of the product you are releasing – for example, you may be planning a marketing release of MyGreatApp version 1.5, but before you get there you will have a number of builds that get sent out to your beta testers, as you fix bugs or add feature your take a snapshot at a given point and release a new build for testing. This may seem counter intuitive but think about  large software product like Mac OSX:  Apple may release many builds of OSX before the release a “final” build that represents a given “marketing version” of the shipping product (which itself cold contain many, many components each with their own build numbers).  If you have ever gotten MacOSX developer seeds they may all have the same “version number” (e.g., 10.6.3) but vary in the build number.
    • Addition many developers insert a Build Date – this is literally the date/time stamp of when a binary was compiled; this could be useful when sending crash reports or even as part of a “contact us” form that the user uses to drop you a support note where the program version info is included
  • All of these elements are stored as entries a Plist file attached to an Xcode target.
  • Almost anything that you can create at a target level that exists as bundle style file can have a distinct version number that you can manage.  This includes iPhone static libraries, OSX frameworks, Bundles, Plugins, and of course iOS and desktop apps. Stand-alone BSD libs and C++ style libraries cannot use this mechanism, but  instead can use more traditional  embedded versioning appropriate to these library formats.
  • Version numbers in PLists are updated by agvtool (the Apple Generic Versioning Tool) that can increment all the standard parts of a traditional components version number (major, minor, release type)
  • Build numbers and Build Dates are updated by script “build phases” that you add to your target

Setting it up:

When you create a new project or a new target in a project, in addition to all the supporting source code files, and potentially NIB/XIB files there will be an Info.plist file whose prefix is the name of the actual target.  So if you’re creating an iPhone or MacOS X desktop app named “MyGreatApp” the Info.plist file will be MyGreatApp-Info.plist

In your Xcode project open the Resources group and find the Info.plist file and double-click on  it.

You should see a display similar to this:

The default Info.plist file

This is the generic out-of the box version of the plist file; to this we need to add a short version string identifier (the marketing version)that the agvtool will increment at our request. To to this, click on any line in the current list and click the “+” symbol a the end of the line which will add a new entry.  A pulldown menu will become available, and select “Bundle versions string, short” and set its value to “1.0″.  The result should look like this:

Adding elements toi the Info.plist file

To support automated build number, date and versioning will need to add 4  other plist items to this list:

  • Add a “Versioning System” item, and set its value to “apple-generic”
  • Add a “Current Project Version” item an set its initial value to 1
  • Add a “CFBuildNumber” entry, set its initial value to zero
  • Add a “CFBuildDate” entry, you can leave its initial value blank

To add values to a plist, click on the last item in the list, a plus-sign will appear on the right of the row, click on it and a new row will by added.

Once the new row exists, click on its title and a drop-down menu will appear from which you can select the new type of entry. You can also type the name of one of the entries above Xcode will do the right thing.  Pressing the TAB key will take you to the content area where you can enter the values for the new field.

Save this plist file  and repeat the process for any other targets whose version/build numbers you want to maintain.

Scripting the build number/date

Automating the build number and build date is accomplished by the addition on a new build phase to your target.  Application targets typically have  3 build hases:

  • Copy Bundle Resources
  • Compile Sources
  • Link Binary with Libraries

These are pretty self-explanatory; the new build phase we’re going add is a “script” phase that will allow us to run a BASH shell script that will be operating on the Plist we want to update.  To add this new build phasae, right-click on your target’s name (in our example its the MyGreatApp target) and select NewRun  Script Phase from the sub-menu:

Adding a new script phase

You can call it whatever you like, I call mine “Update Build Number” just to its clear.

Next, you will want to double-click on the new script phase line and add the following to the script content area:

# Auto Increment Version Script
buildPlist=${INFOPLIST_FILE}
CFBuildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBuildNumber" $buildPlist)
CFBuildNumber=$(($CFBuildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBuildNumber $CFBuildNumber" $buildPlist
CFBuildDate=$(date)
/usr/libexec/PlistBuddy -c "Set :CFBuildDate $CFBuildDate" $buildPlist

Make sure that the “Shell” is set to /bin/bash and save the script.

Your target is now all set to have its build number and build date set set automatically.  The nice thing about this method that it’s internal to Xcode from the point of view of file modifications; there are other ways to change info in the Info.plist but they often will leave you and your SCM at odds if you do auto-checkins on build because the plist file will be modified after the SCM checkin-has occurred.

If you want  see it in action, simply build your project.  Once the build is complete, look at the Info.plist file and you’ll see something like this:

Infor Plist Screen shot

Build number and date automatically updated

Of course, since these values are in your app’s bundle you can easily get them programmatically:

    
NSString *appVersionNumber = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
NSString *buildNumber = [[[NSBundle mainBundle] infoDictionary] valueForKey:@"CFBuildNumber"];
NSString *buildDateString = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBuildDate"];
NSDate   *buildDate = [dateFormatter dateFromString:buildDateString];

for use in your about screen, as part of info needed to talk to your back end servers, etc…

What About the “Marketing Version” Number?

The typically user visible marketing version number is something you’ll only increment when you are making a new release that will, for example, be uploaded to the AppStore  and delivered to your customers.  You don’t want to do it every tim you build, or very quickly you’ll go from a “version 1.0″ to a “Version 1517.7″ … which is certainly not what you want.  So, when it does come time to bump this version number you’ll use avgtool.

Apple’s agvtool is  typical Unix application, it takes all its instructions  on what to do in the form of command line arguments.  Like most command line programs it also has built-in help that can be displayed by simply runing gh program without any arguemnt, for example:

locahost% agvtool
Operation specifier required.
agvtool - Apple-generic versioning tool for Xcode projects
usage:
agvtool help
agvtool what-version | vers [-terse]
:
:
<lots of command line options omitted>

Incrementing the version number is as easy as the command  agvtool next-version

The only thing you need to remember is to use this tool when the Xcode project is closed, or your changes could be lost.  And, of course you will need to check this change into you SCM as well since unlike the build number/date updating above this has to happen outside of any internal Xcode scripting.

GD Star Rating
loading...
Recipe: Automatic Version Number, Build Number & Build Date Handling, 9.0 out of 10 based on 9 ratings
Twitter Digg Delicious Stumbleupon Technorati Facebook Email

About David Spector

He’s written for C|Net’s Tech Republic, InformationWeek, Fortune, WIRED and various other publications both online and in traditional print media.David HM Spector is a software developer, writer, and entrepreneur specializing in MacOSX/iOS development, and social network applications. His consulting company is Zeitgeist Information Systems, canonically known as “Zeitgeist.” (And, no, he's got nothing to do with The Zeitgeist Movie...)Connect with me on LinkedIn

Comments are closed.

Performance Optimization WordPress Plugins by W3 EDGE