Incrementing Build Numbers in Xcode

I admit, I'm a sucker for numbers. When I release a project, it'd be kind of cool to know how many times I've built it. With that in mind, and with a good deal of help from my friend Quinn and a couple of online tutorials, I was able to come up with a neat little script that can do just that.

Here's what you need to do:

  1. Select the target you're working with, and add a new "Run Script Phase" to it
  2. Paste the following code into the script box:
    1. #!/bin/bash
    2. buildNumber=$(/usr/libexec/PlistBuddy -c "Print DDBuildNumber" Info.plist)
    3. buildNumber=$(($buildNumber + 1))
    4. /usr/libexec/PlistBuddy -c "Set :DDBuildNumber $buildNumber" Info.plist
  3. Compile with impunity

The idea is simple: It uses your project's Info.plist file to store an integer value under the key "DDBuildNumber". Every time you build, it grabs that number, increments it, and saves it back to the plist.

A caveat: It seems like Xcode is caching Info.plist, so you may not see the change reflected immediately in Xcode. However, if you open Info.plist from the Finder (or just Quick Look it), you'll see that the number has changed.

Cheers!

Dave

Comments

Build number increment

Thanks for the script, especially for the use of PlistBuddy.
Seems like the best tool for hacking the info.plist.
I had been using sed and defaults(1) but this is much cleaner.
defaults(1) also has a nasty habit of modifying the target file permissions to 600 (on 10.6 anyway).

Jonathan Mitchell

www.mugginsoft.com

Extended the concept ...

Thank you! Brilliant!

I've extended this concept a bit to make it easier to have auto-incrementing build numbers and a version number available. A key factor for me was simplicity and ease of management for resetting the build numbers or incrementing version numbers from a single location.

I've added a 'prefix' and the same auto-increment numbering, and combined this to ensure that each build generates a unique version number which is easily managed.

Create 2 keys:
CFBuildVersion - Put any 'prefix' you would like to have in here (like "1.0")
CFBuildNumber - Start your Build Numbering with 0 (Reset when you change BuildVersion)

Also, the latest XCode projects use a ${PROJECT_NAME}-Info.plist file instead, so added that as a pseudo-parameter.

  1. #!/bin/bash
  2. # Auto Increment Version Script
  3. buildPlist="Project-Info.plist"
  4. buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBuildVersion" $buildPlist)
  5. buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBuildNumber" $buildPlist)
  6. buildNumber=$(($buildNumber + 1))
  7. /usr/libexec/PlistBuddy -c "Set :CFBuildNumber $buildNumber" $buildPlist
  8. /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildVersion.$buildNumber" $buildPlist
  9. /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $buildVersion.$buildNumber" $buildPlist

That's it ... now it will auto-generate version numbers and version strings in the form #.#.#

Regards,
Robert.

Is it still suppose to work in Xcode 3.2.3 ?

Hello,

When I found this page I was pretty sure my problems were over but ...
I did all the steps in this page but the build stage in Xcode saus /bin/sh runscript stage failed
(of course i removed the /bin/sh of the line above to replace with /bin/bash)

The problem I have is that he is not finding the keys ... I create them so they are in but somehow not "identified"

Any help/clue would be appreciated ;)

Thanks

GH From Paris

Expanded to work with the latest Xcode

In the New build phase run script Info window, put this line:

  1. ./Resources/plistVersionIncrement

In the Resources directory of your project (assuming you have a Resources directory, if not, create one)
put this script called: "plistVersionIncrement"
  1. #!/bin/bash
  2. #
  3. # @(#)  Increment the version number in the project plist.
  4. #               Note:   The project plist could be in directory
  5. #                               "Resources" or the project root.
  6. #                               Personally, I avoid clutter in the project root.
  7. #               Enjoy! xaos@xm5design.com
  8. #
  9. PROJECTMAIN=$(pwd)
  10. PROJECT_NAME=$(basename "${PROJECTMAIN}")
  11. #
  12. if [[ -f "${PROJECTMAIN}/Resources/${PROJECT_NAME}-Info.plist" ]]
  13. then
  14.         buildPlist="${PROJECTMAIN}/Resources/${PROJECT_NAME}-Info.plist"
  15. elif [[ -f "${PROJECTMAIN}/${PROJECT_NAME}-Info.plist" ]]
  16. then
  17.         buildPlist="${PROJECTMAIN}/${PROJECT_NAME}-Info.plist"
  18. else
  19.         echo -e "Can't find the plist: ${PROJECT_NAME}-Info.plist"
  20.         exit 1
  21. fi
  22. #
  23. buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${buildPlist}" 2>/dev/null)
  24. if [[ "${buildVersion}" = "" ]]
  25. then
  26.         echo -e "\"${buildPlist}\" does not contain key: \"CFBundleVersion\""
  27.         exit 1
  28. fi
  29. IFS='.'
  30. set $buildVersion
  31. MAJOR_VERSION="${1}.${2}.${3}"
  32. MINOR_VERSION="${4}"
  33. buildNumber=$(($MINOR_VERSION + 1))
  34. buildNewVersion="${MAJOR_VERSION}.${buildNumber}"
  35. echo -e "${PROJECT_NAME}: Old version number: ${buildVersion} New Version Number: ${buildNewVersion}"
  36. /usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${buildNewVersion}" "${buildPlist}"

This works very well with Xcode V3.2.2

Thank you for getting me started with this script.

Xaos (xaos@xm5design.com)

XM5 Design Inc.

Expanded to Root.plist

Thanks! This was such a time-saver to find. I made a slight modification to also write the updated version number to my Settings bundle.

  1. #!/bin/bash
  2. # Auto Increment Version Script
  3. # Found here: <a href="http://davedelong.com/blog/2009/04/15/incrementing-build-numbers-xcode<br />
  4. #<br />
  5. #" title="http://davedelong.com/blog/2009/04/15/incrementing-build-numbers-xcode<br />
  6. #<br />
  7. #">http://davedelong.com/blog/2009/04/15/incrementing-build-numbers-xcode<br />
  8. #<br />
  9. #</a> Set the paths to the build and settings Plist
  10. buildPlist="${PRODUCT_NAME}-Info.plist"
  11. settingsPlist="Settings.bundle/Root.plist"
  12.  
  13. # Get the existing buildVersion and buildNumber values from the buildPlist
  14. buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBuildVersion" $buildPlist)
  15. buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBuildNumber" $buildPlist)
  16.  
  17. # Increment the buildNumber
  18. buildNumber=$(($buildNumber + 1))
  19.  
  20. # Set the version numbers in the buildPlist
  21. /usr/libexec/PlistBuddy -c "Set :CFBuildNumber $buildNumber" $buildPlist
  22. /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildVersion.$buildNumber" $buildPlist
  23. /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $buildVersion.$buildNumber" $buildPlist
  24.  
  25. # Set the version numbers in the settingsPlist (Your path to the key you store your version number may vary, mine is in item 0)
  26. /usr/libexec/PlistBuddy -c "Set :PreferenceSpecifiers:0:DefaultValue $buildVersion.$buildNumber" $settingsPlist

Info.plist refresh issue ...

Oh yeah, XCode does cache the plist file, but it's easy to view the updates/changes to verify the script operation.

Close the window (Command - Shift - W), and re-open it. Xcode will display the updated values.

Regards,
Robert.

Thank you both, Dave and

Thank you both, Dave and Robert, this post is exactly what I was looking for, and the script provided is flawless.

Distributed?

This works great if you're a one man team. Any ideas on how to manage this on a distributed system? I'd like to avoid checking in the plist every time I build.

Use a template file

Well, the script I posted is modifying the Info.plist file in-place, which means that your VCS is going to see that it has changed. Obviously, you don't want your VCS to ignore the file, because there occasionally are legitimate changes to the file you want saved. What I'd probably do in this case is use move the Info.plist file to Info.plist.template, check the template into my VCS, and then generate the Info.plist file in the script from the template, and compile using the generated Info.plist. That way your VCS can ignore the Info.plist file and it's often-changing build numbers, but you'd still have a checked-in version (the template).

Latest XCode project update

Hi there, thnx a lot for the script, is very neat, here's a little update I made to handle some new project settings:

  1. buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" ${PRODUCT_NAME}-Info.plist)
  2. buildNumber=$(($buildNumber + 1))
  3. /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" ${PRODUCT_NAME}-Info.plist

that's it, pretty much the same and is working like a charm again

Expanded again for Device and AdHoc/AppStore only

Hi, guys,

Thank you all!

Your awesome posts and replies saved a lot of my time! My requirement might a little bit different with yours. I need the build number to be auto increased in every AdHoc/AppStore build. So, I made a little tweak as below.

  1. # Auto Increment Version Script
  2.  
  3. conf=${CONFIGURATION}
  4. arch=${ARCHS:0:4}
  5. # Only increase the build number on Device and AdHoc/AppStore build
  6. if [ $conf != "Debug" ] && [ $conf != "Release" ] && [ $arch != "i386" ]
  7. then
  8.         buildPlist=${INFOPLIST_FILE}
  9.         buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBuildVersion" $buildPlist)
  10.         buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBuildNumber" $buildPlist)
  11.         buildNumber=$(($buildNumber + 1))
  12.         /usr/libexec/PlistBuddy -c "Set :CFBuildNumber $buildNumber" $buildPlist
  13.         /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildVersion.$buildNumber" $buildPlist
  14.         /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $buildVersion.$buildNumber" $buildPlist
  15. fi

If anybody has same requirement, hope my little work could help.

Thanks, everyone.

Tonny Xu@Tokyo

use :CFBundleVersion in variable

Also using plistbuddy for some time, I still have a question.

Now I build a complete commando string and add that.

What I want is actualy using a string var instead of 'hardcodin' the key :CFBundleVersion

I would like to see

  1. /usr/libexec/PlistBuddy -c "Set ${key} ...."

but I cant get it to work