Better way of incrementing build number?

I have been using a shell script as part of my Xcode build process to increment the build number within the plist file, however it's making Xcode 4.2.1 crash frequently (with an error about the target not belonging to a project; I'm guessing the changing of the plist file is confusing Xcode in some way).

The shell script did this so that the build number is only incremented by agvtool when a file is newer than the plist file (so just building didn't increment the value):

if [ -n "`find ProjDir -newer ProjDir/Project-Info.plist`" ]; then agvtool -noscm next-version -all; else echo "Version not incremented"; fi

Is there a way to increment the build number (in the plist file, or anywhere else) that doesn't break Xcode?

EDIT : Here is my final solution, based on the suggestion of @Monolo. I created the following script in ${PROJECT_DIR}/tools (sibling to the .xcodeproj directory):

#!/bin/sh

if [ $# -ne 1 ]; then
    echo usage: $0 plist-file
    exit 1
fi

plist="$1"
dir="$(dirname "$plist")"

# Only increment the build number if source files have changed
if [ -n "$(find "$dir" ! -path "*xcuserdata*" ! -path "*.git" -newer "$plist")" ]; then
    buildnum=$(/usr/libexec/Plistbuddy -c "Print CFBundleVersion" "$plist")
    if [ -z "$buildnum" ]; then
        echo "No build number in $plist"
        exit 2
    fi
    buildnum=$(expr $buildnum + 1)
    /usr/libexec/Plistbuddy -c "Set CFBundleVersion $buildnum" "$plist"
    echo "Incremented build number to $buildnum"
else
    echo "Not incrementing build number as source files have not changed"
fi

EDIT 2 : I have modified the script to incorporate @Milliways suggestion.

I then invoked the script from Xcode target 'Build Phases' section: Xcode构建阶段截图

EDIT 3 : As per @massimobio's answer, you'll need to add quotes around the plist argument if it contains spaces.

EDIT 4 : Just to update that my preferred method of invoking this build script is now to create a separate target and make the app target dependant upon this Bump Build Number target. This ensures that it is invoked before the app target does anything with the plist (I've noticed that it likes to process the plist at the start of the build). I've also switched to a purely python-based solution that keeps the version number in a separate file, and writes version source files, as this is more useful for cross-platform products (ie Visual Studio under Windows can invoke the script, and obviously cmake/make-type builds can do so also). This has the benefit that the build number is always the same even under different platforms, and it's also possible to update the Visual Studio Resource.rc file with the current version/build as well.

Here is the python script I currently use to update Info.plist files within Xcode project.


If I understand your question correctly, you want to modify the Project-Info.plist file, which is a part of the standard project template of Xcode?

The reason I ask this is that Project-Info.plist normally is under version control, and modifying it means that it will be marked as, well, modified.

If that is fine with you, then the following snippet will update the build number and mark the file as modified in the process, where get_build_number is some script to get the (possibly incremented) build number that you want to use:

#!/bin/sh

# get_build_number is a placeholder for your script to get the latest build number
build_number = `get_build_number`

/usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${build_number}" ProjDir/Project-Info.plist

PlistBuddy allows you to set any key in a plist file, not just the version number. You can create all the plist files you want, and include them in the resources if needed. They can then be read in from the bundle.

As to your need to show the version in the about pane and other places, you can also look into setting CFBundleGetInfoString and CFBundleShortVersionString .


I've messed around with a lot of the answers on this question, and none of them quite satisfied me. However, I finally came up with a mixture that I really like!

There are two steps, one at the beginning and one at the end of your build phases.

At the beginning:

# Set the build number to the count of Git commits
buildNumber=$(git rev-list HEAD | wc -l | tr -d ' ')
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"

At the end:

# Set the build number to "DEVELOPMENT"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion DEVELOPMENT" "${PROJECT_DIR}/${INFOPLIST_FILE}"

Looking at the Info.plist in Xcode you'll see the version number is "DEVELOPMENT", but the built app will have a constantly increasing build number. (As long as you always do your builds off the same branch.)

Setting the version number back to a constant string at the end prevents the Info.plist file from being changed by building the app.

Why I like this method:

  • Easy
  • Doesn't pollute Git version history
  • CFBundleVersion is totally automatic
  • The pretty version number can be modified whenever I want

  • I have used this glist its awesome and works as expected. https://gist.github.com/sekati/3172554 (all credit goes to original author)

    Sctipts that I modified over the time.

    xcode-versionString-generator.sh,

    xcode-build-number-generator.sh

    As these gist are helping dev community. I thought to made github project out of it. So lets develop it good. Here is the github project: https://github.com/alokc83/Xcode-build-and-version-generator

    I have updated the code for both script little bit of enhancement. instead of using below grab the latest from github

    For Version :

    # xcode-version-bump.sh
    # @desc Auto-increment the version number (only) when a project is archived for export. 
    # @usage
    # 1. Select: your Target in Xcode
    # 2. Select: Build Phases Tab
    # 3. Select: Add Build Phase -> Add Run Script
    # 4. Paste code below in to new "Run Script" section
    # 5. Check the checkbox "Run script only when installing"
    # 6. Drag the "Run Script" below "Link Binaries With Libraries"
    # 7. Insure your starting version number is in SemVer format (e.g. 1.0.0)
    
    # This splits a two-decimal version string, such as "0.45.123", allowing us to increment the third position.
    VERSIONNUM=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${PROJECT_DIR}/${INFOPLIST_FILE}")
    NEWSUBVERSION=`echo $VERSIONNUM | awk -F "." '{print $3}'`
    NEWSUBVERSION=$(($NEWSUBVERSION + 1))
    NEWVERSIONSTRING=`echo $VERSIONNUM | awk -F "." '{print $1 "." $2 ".'$NEWSUBVERSION'" }'`
    /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $NEWVERSIONSTRING" "${PROJECT_DIR}/${INFOPLIST_FILE}"
    

    For build:

    # xcode-build-bump.sh
    # @desc Auto-increment the build number every time the project is run. 
    # @usage
    # 1. Select: your Target in Xcode
    # 2. Select: Build Phases Tab
    # 3. Select: Add Build Phase -> Add Run Script
    # 4. Paste code below in to new "Run Script" section
    # 5. Drag the "Run Script" below "Link Binaries With Libraries"
    # 6. Insure that your starting build number is set to a whole integer and not a float (e.g. 1, not 1.0)
    
    buildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")
    buildNumber=$(($buildNumber + 1))
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${PROJECT_DIR}/${INFOPLIST_FILE}"
    
    链接地址: http://www.djcxy.com/p/58248.html

    上一篇: xcode中的'摘要'选项卡不可见?

    下一篇: 更好的方式增加内部版本号?