Home | Developer Blog

Automated build numbering in Xcode

One thing I like to do in any development project is generate a build number, and I want it to be an automated process. This number represents the version of the source code that was used for the build. Coupled with source code control, this enables you track the version of the source code that corresponds to a customer’s installation of the product. In a large team with centralized builds, you typically increment the build number on every centralized build, whether they are kicked off on a time basis, or a check-in basis. For a single developer project, it’s nice to be able to increment the build number for every build you make locally. Here’s a simple way to enable automated build numbering in Xcode for a single developer project.

First, you need to create a file in the project that contains the build number. Create a file in the project called buildnumber.xcconfig with the following single line in it:

BUILD_NUMBER = 1

It’s convenient to use an .xcconfig file for this purpose, as the build number will then be available as a variable that you can use directly in the Info.plist file. In order to include this .xcconfig file in your build, go to Project > Edit Project Settings and go to the Build tab. In the bottom right corner change Based On to buildnumber, as shown below.

Project Build Settings

Next you need to add a shell script to the build process that will update this file incrementing the build number every time it is run. Find your target executable in Xcode, as shown below.

Add Run Script Phase

Right click on the target (ExampleBuildNumber in the example shown above) and choose Add » New Build Phase » New Run Script Build Phase. We are going to use a simple inline Perl statement to increment the build number. Fill in the dialog as follows:

Run Script Dialog

Note that Output Files includes the modified file buildnumber.xcconfig and the Info.plist file. This ensures that build dependencies work correctly. For ease of copy/paste, here’s the shell script:

/usr/bin/perl -pe 's/(BUILD_NUMBER = )(\d+)/$1.($2+1)/eg' -i buildnumber.xcconfig

After you close this dialog, make sure that the new Run Script entry under your target is the first item in the build process. If it isn’t, simply drag it to the first position. Your target build phases should look something like this:

Finished Adding Run Script Phase

Now edit the Info.plist file in your project setting the following key values:

<key>CFBundleVersion</key>
<string>${BUILD_NUMBER}</string>
<key>CFShortVersionString</key>
<string>Version 1.0</string>

As you can see, CFBundleVersion will now contain your build number, and CFShortVersionString should contain your actual application version number.

To make use of these values you’ll want to create a method that returns a complete version string, constructed from the Info.plist file contents. For example:

- (NSString*) version
{
    return [NSString stringWithFormat:@"%@ (Build %@)",
                  [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFShortVersionString"],
                  [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]];
}

You can either use this method directly, or place the method in a controller, and bind an NSTextField directly from your user interface to it.

Comments

  1. Matthew Schinckel wrote:

    To do it with the Mercurial revision number:

    sed -E ’s/(BUILD_NUMBER = )[0-9]+[\+]?/\1′`/usr/local/bin/hg id -n`’/’ tmp_build_no
    mv tmp_build_no buildnumber.xcconfig

  2. Matthew Schinckel wrote:

    Whoops, forgot to escape my bits:

    sed -E ’s/(BUILD_NUMBER = )[0-9]+[\+]?/\1′`/usr/local/bin/hg id -n`’/’ <buildnumber.xcconfig > tmp_build_no
    mv tmp_build_no buildnumber.xcconfig

Post a Comment