The Best of All Possible Xcode Automated Build Numbering Techniques

At Bloglovin, we use an automated build numbering setup in Xcode that sets the build number to the current number of git commits in the active git branch. It has worked mostly well, though our technique has not been without frustrations.

The Frustrating Old Way

The technique we have been using is based on this post by the inexcusably-named “Cocoa is my Girlfriend”1. It works as follows:

  1. A run script grabs the git commit count and echo's it out to a file called InfoPlistWhatever.h. The name doesn’t matter.

  2. The build settings for the target enable Preprocess Info.plist File and set the value of Info.plist Preprocessor Prefix File to our file from step 1.

  3. The file from #1 sets the git commit count as the value of a #define preprocessor variable called CUSTOM_BUILD_NUMBER or something to that effect.

  4. The Info.plist screen in Xcode is updated to use CUSTOM_BUILD_NUMBER instead of an actual build number.

This technique works as advertised, but it has several really annoying drawbacks:

The Best Possible Way

After much Googling, I came across this post by an anonymous commenter. This technique is far better. It avoids all of the pitfalls of our previous technique, and is even easier to set up.

All you need to do to enable this technique is to add a run script build phase any time after “Copy Bundle Resources”:

#
# Set the build number to the current git commit count.
# If we're using the Dev scheme, then we'll suffix the build
# number with the current branch name, to make collisions
# far less likely across feature branches.
# Based on: http://w3facility.info/question/how-do-i-force-xcode-to-rebuild-the-info-plist-file-in-my-project-every-time-i-build-the-project/
#
git=`sh /etc/profile; which git`
appBuild=`"$git" rev-list --all |wc -l`
if [ $CONFIGURATION = "Debug" ]; then
branchName=`"$git" rev-parse --abbrev-ref HEAD`
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild-$branchName" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
else
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $appBuild" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
fi
echo "Updated ${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"

This script uses the PlistBuddy command line tool to edit the build number of the Info.plist in the /foo/DerivedData/bar directory, the target’s build directory. This is why git isn’t dirtied when the build number changes. It doesn’t matter what you’ve entered in your Info.plist screen in Xcode. It also updates the build number for every build, not just the first build after a total clean.

The code above includes some modifications to the code posted by that anonymous commenter. It uses the git commit count for the build number, but if it detects that we’re using our Debug build configuration in Xcode, it suffixes the build number with the current git branch name. This avoids potential build number collisions across feature branches under simultaneous development.2

Update Sep. 14, 2014 - Johan Kool, arguably the man with the coolest name on the Internet, has kindly corrected some potential bugs in my new run script. The corrections have already been applied above.


  1. Seriously. It’s 2014. Rename it. 

  2. At Bloglovin, we have fix or six new feature branches in active development at any given time. Build number collisions happen daily. While not a huge problem, I don’t like that feature-specific builds will be hard to identify in crash logs. This new method of suffixing the build number should alleviate this problem. 

|  10 Sep 2014