Last Updated: September 03, 2020
·
5.12K
· hash3r

Auto increment version in Xcode

One day I decided to be on one step closer to my dream job position of a "Build Engineer".

So I guess it would be great just to make a cmd+B (or press an Archive for export) and build number (or version) of an app is incremented behind the scene without my help.

Let's increment something!

Before scripting we need to understand how version numbers are assigned and incremented.

The most common versioning system is a SemVer
There is a short description of it:

Given a version number MAJOR.MINOR.PATCH, increment the:
1. MAJOR version when you incompatible API changes,
2. MINOR version when you add functionality in a backwards-compatible manner, and
3. PATCH version when you make backwards-compatible bug fixes.

In Xcode projects we have 2 properties for versioning:

CFBundleVersion (String - iOS, OS X) specifies the build version number of the bundle, which identifies an iteration (released or unreleased) of the bundle. The build version number should be a string comprised of three non-negative, period-separated integers with the first integer being greater than zero. The string should only contain numeric (0-9) and period (.) characters. Leading zeros are truncated from each integer and will be ignored (that is, 1.02.3 is equivalent to 1.2.3).

This property should be upped on every build iteration and script looks like this:

# @desc Auto-increment the build number every time the project is run. 
# @usage
# 1. Select: your Target in Xcode
# 2. Select: Editor -> Sheme -> Edit scheme
# 3. Select: Build -> Pre-action -> + New Run Script Action
# 4. Paste code below in to new "Run Script" section
# 5. Select your target in "Provide build settings from"
# 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}"

Another important version property is a

CFBundleShortVersionString (String - iOS, OS X) specifies the release version number of the bundle, which identifies a released iteration of the app. The release version number is a string comprised of three period-separated integers.

And if we use a SemVer protocol script can look like this:

# @desc Auto-increment the version number (only) when a project is archived for export. 
# @usage
# 1. Select: your Target in Xcode
# 2. Select: Editor -> Sheme -> Edit scheme
# 3. Select: Build -> Pre-action -> + New Run Script Action
# 4. Paste code below in to new "Run Script" section
# 5. Select your target in "Provide build settings from"
# 6. Insure your starting version number is in SemVer format (e.g. 1.0.0)

# This splits a two-decimal version string, such as "0.1.2", allowing us to increment only the third position.
VERSION=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${PROJECT_DIR}/${INFOPLIST_FILE}")
NEWSUBVERSION=$(echo $VERSION | awk -F "." '{print $3}')
NEWSUBVERSION=$(($NEWSUBVERSION + 1))
NEWVERSIONSTRING=$(echo $VERSION | awk -F "." '{print $1 "." $2 ".'$NEWSUBVERSION'" }')
/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $NEWVERSIONSTRING" "${PROJECT_DIR}/${INFOPLIST_FILE}"

If you find out that a SemVer protocol is not your way and you want to increment directly through 3 version number like:

0.1.9 -> 0.2.0
0.9.9 -> 1.0.0

Your script can look like this:

    # @desc Auto-increment the version number through all numbers (only) when a project is archived for export. 
    # @usage
    # 1. Select: your Target in Xcode
    # 2. Select: Editor -> Sheme -> Edit scheme
    # 3. Select: Build -> Pre-action -> + New Run Script Action
    # 4. Paste code below in to new "Run Script" section
    # 5. Select your target in "Provide build settings from"
    # 6. Insure your starting version number is in SemVer format (e.g. 1.0.0)

version=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${PROJECT_DIR}/${INFOPLIST_FILE}")
        major=$(echo $version | awk -F \. '{print $1}')
        minor=$(echo $version | awk -F \. '{print $2}')
        patch=$(echo $version | awk -F \. '{print $3}')

        if [ $patch ==  9 ]; then
            if [ $minor ==  9 ]; then
                ((major++))
                minor="0"
                patch="0"
            else
                ((minor++))
                patch="0"
            fi
        else
            ((patch++))
        fi
        newversion="$major.$minor.$patch"

        /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $newversion" "${PROJECT_DIR}/${INFOPLIST_FILE}"

Some people prefer to use .xcconfig files like a base configuration for different targets.
We can add custom fields for versioning

//  User-Defined
//  {
        APP_SHORT_VERSION = 1.2.3
        APP_BUNDLE_VERSION = 1.2.3
//  }

Picture

Also you can increment version with script

if [ "${CONFIGURATION}" = "Release" ]; then
    version=$(grep -o "VERSION = [0-9]*\.[0-9]*\.[0-9]*" ${SRCROOT}/App.xcconfig | tail -1 | tr -d 'VERSION = ')
    major=$(echo $version | awk -F \. '{print $1}')
    minor=$(echo $version | awk -F \. '{print $2}')
    patch=$(echo $version | awk -F \. '{print $3}')

    if [ $patch ==  9 ]; then
        if [ $minor ==  9 ]; then
            ((major++))
            minor="0"
            patch="0"
        else
            ((minor++))
            patch="0"
        fi
    else
        ((patch++))
    fi
    incremented_version="$major.$minor.$patch"
#   replace version in file
    $(sed -i '' -e "s/${version}/${incremented_version}/" ${SRCROOT}/App.xcconfig)

1 Response
Add your response

Hi @hash3r, I have tried all the versions for CFBundleShortVersionString, and they all add , between minor and patch 2 (two), dots, eg. 1.0.0, the the result is 1.0.0..1 or 1.0 then 1.0..1

thanks! 🙏

over 1 year ago ·