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
// }
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)
Written by hash3r
Related protips
1 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! 🙏