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:
A run script grabs the git commit count and
echo
's it out to a file calledInfoPlistWhatever.h
. The name doesn’t matter.The build settings for the target enable
Preprocess Info.plist File
and set the value ofInfo.plist Preprocessor Prefix File
to our file from step 1.The file from #1 sets the git commit count as the value of a
#define
preprocessor variable calledCUSTOM_BUILD_NUMBER
or something to that effect.The
Info.plist
screen in Xcode is updated to useCUSTOM_BUILD_NUMBER
instead of an actual build number.
This technique works as advertised, but it has several really annoying drawbacks:
- It dirties git every time you build after the commit count changes.
- If you don’t want it to dirty git, you’ll have to ignore the preprocessor plist file.
- If you ignore the preprocessor plist file, you’ll have to manually create an initial copy of that file or else the first build in Xcode will fail (unless you don’t commit your
.gitignore
file to your git repo, and let the origin continue to track the file at whatever state it happens to be in). - The build number won’t update unless you manually clean and rebuild. This is because Xcode caches the
Info.plist
in a way that can’t be cleared by any other mechanism. I tried many ways around this: scheme build pre-actions, other run scripts, etc. There’s just no other way. Having to manually clean and rebuild defeats the purpose of an automated setup.
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.
-
Seriously. It’s 2014. Rename it. ↩
-
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. ↩