Build Numbers

Your Xcode project’s targets each keep track of their current build number. Typical usage would be to increment that number each time you actually build your project. However, Xcode doesn’t automatically provide this feature. Also, if you’ve uploaded an app to the AppStore I’m sure you’ve forgotten to increment your build number at least once and had to repeat the entire archive and upload process just to change a two to a three in the target’s settings.

So I decided to write a shell script that will automatically increment this value for me.

1   if [[ $INFOPLIST_FILE =~ '^/Users' ]]; then
2     location=$INFOPLIST_FILE
3   else
4     location=${PROJECT_DIR}/${INFOPLIST_FILE}
5   fi
6   getBuildNumber () {
7     echo $(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$location")
8     return
9   }
10  buildNumber=$[ $(getBuildNumber) + 1 ]
11  /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "$location"

I’ll explain this line by line.

Lines one through five:

$INFOPLIST_FILE and $PROJECT_DIR are build settings imported into the shell environment for you by Xcode. The former pointing to the location of your project directory and the latter pointing to the location of your info.plist file.

However, if you do some custom configuration to your info.plist file, you could end up changing the build setting. The build setting is normally relative (i.e. myProject/info.plist) but I have some projects where the path is absolute (i.e. /Users/me/projects/myProject/myProject/myProject.plist). So the first if statement checks if you have an absolute path or a relative one and defines the location variable accordingly.

Lines six through nine

Here we simply define a function getBuildNumber that uses Xcode’s PlistBuddy command line tool. As you can guess from the name, it helps you access plist settings. Check man PlistBuddy if you want specifics, but this line gets the CFBundleVersion from the plist at $location and sends it to stdout. Clearly enough, this just gets the bundle version (aka the build number) from the plist and echos it out to stdout. I declare this function for testing purposes where I call it a handful of times, you can just call this inline if you wish.

Line 10

This line calls the function, adds one to it and stores it to the variable buildNumber. Straight forward enough.

Line 11

This line just uses the same PlistBuddy utility to set the incremented build number.


Now, how do you use it? I put this file at /Users/me/bin/incrementXcodeBuild. I also include that folder in my path, though it’s position their isn’t useful as it relies on the injected Xcode environment variables.

Now we have to configure Xcode to use it. Open your .xcproject or .xcworkspace and click the project in the navigator, then click your target and then Build Phases. Then click the “+” and “New Run Script Phase.” Expand the “Run Script” entry and type this in the script entry box:

if [[ $USER == 'yourUsernameHere' ]]; then

All this that we have just added will run the script at the end of the build process for your app. Build Phases is more or less a list of actions that Xcode does during the build process. So we added a final step of calling this script.

The script just above first checks if it is being ran on your user account. If so, it calls our incrementXcodeBuild script. I perform this check in order to avoid calling this script if the build is being ran on Travis or Xcode Server as I upload via fastlane from my MacBook Pro.

And that’s it! Hope you found this useful!