Better way of incrementing build number?
Asked Answered
S

22

142

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?

FINAL EDIT: I now do this kind of stuff using a python script which I have just made public on github. It's not well documented but shouldn't be difficult to work out. As a bonus this repo also contains a useful script to automatically bundle 3rd party library into an app bundle.

Sterne answered 13/2, 2012 at 9:43 Comment(13)
If anyone is interested: I modified the script a little to use hexadecimal numbers instead of decimal numbers - gist.github.com/sascha/5398750Attraction
You can add this script as a pre-build action directly, no need to invoke an external script. Do not run this script with a build phase; Xcode will only copy the updated plist every other build.Smocking
Out-of-the-box I got a "permission denied" error so thought I'd point to this Q&A to anyone else that experiences the same: https://mcmap.net/q/16924/-what-permissions-are-required-for-quot-run-script-quot-during-a-build-phase/519030Stillmann
This script fails with an exit code 1. Can anyone help me with this?Transcendentalistic
@Tander Looks like you aren't supplying the plist file as an argument to the script.Sterne
Where would I plast the plist name in the script? - sorry I'm very new to scripts.Transcendentalistic
@Tander See the screenshot in the question (under EDIT 2).Sterne
@Sterne When I change it to the ${PROJECT_DIR}/tools/bump_build_number.sh"${PROJECT_DIR}/${INFOPLIST_FILE}" I get an error saying no such file or folder exists. Where should I place th script?Transcendentalistic
@Tander In a directory called tools, right next to the .xcodeproj.Sterne
I did this: Went to my iOS folder where my app is - created the folder and then tried again in Xcode. Still same error. I must be missing something :(Transcendentalistic
I'd also recommend putting ${PROJECT_DIR} for the path to the script in quotes for the spaces issue. Guess how I found that out. ;)Sup
Note that this will fail if your current CFBundleVersion includes a decimal, e.g. 1.0. Shell scripts can only add integers with the raw + operator. Change to plain 1 and it will work fine.Schweiz
A note for beginners about creating scripts from scratch: to be used in Xcode, you will need to make the .sh/.scpt file executable. This can be done by running chown +x /path/to/file.sh.Dunkle
B
29

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 (i.e., a placeholder in this example) 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.

Barely answered 15/2, 2012 at 14:12 Comment(4)
I don't need the git commit (or tag) in the plist file so a simple incrementing system is fine (as provided by agvtool), however the act of modifying the plist during the build breaks Xcode frequently (since removing the script it hasn't crashed once, when it was crashing every 3 builds or so). Is it possible to put the version info in another plist file and have that included with the bundle and accessible from the App?Sterne
Great script - I'd prefer to combine this with Hugues BR's suggestion to only use it when archiving builds. Keeps the numbers low and ignores however many dev builds are performed between releases.Bilk
What is get_build_number? Is that just some placeholder?Saintsimon
Yes, get_build_number is just a placeholder - updated the answer to clarify.Barely
C
84

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!

We simply set the version number for the built product to the number of Git commits. This won't mess with your source control, since the script only mutates the built product.

Add this "Run Script" build phase to the end of your build phases:

if [ "${CONFIGURATION}" = "Release" ]; then
    buildNumber=$(git rev-list --count head)
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildNumber" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
fi

Set your Info.plist version in your project to whatever you want, it will never get used when building a release build. I set mine to AUTOMATED or DEVELOPMENT so it's clear when I'm running a development build.

That's it! The built app will have a constantly increasing build number. (As long as you always do your builds off the same branch.)

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

Other notes:

  • If you have app extensions in your project, simply set the same build script on those targets too. This will keep all the version numbers automated and in sync. The App Store requires extension versions match your main app.
Contagious answered 15/7, 2014 at 5:24 Comment(11)
Keeping version numbers out of the version-controlled plist file is the best way to do it, especially if you have a brach per release and sometimes need to merge or cherry-pick. Thanks!Illfounded
You could use git rev-list --count HEAD instead of git rev-list HEAD | wc -l | tr -d ' '.Alameda
Hmm. I found that if you use fastlane to upload automatic builds this way, you get: ERROR ITMS-90058: "This bundle is invalid. The value for key CFBundleVersion [DEVELOPMENT] in the Info.plist file must be a period-separated list of at most three non-negative integers."Karolynkaron
When you say beginning and end of the build, where exactly in the build phases should these scripts go? Are all build phases not executed to build the archive? How do you ensure that the git rev-list value goes into the archive but that the change to the plist is reverted after the build is done?Pickar
I'm not sure exactly where it should go, I put the first script as the first build phase, and the last script as the last build phase and it works for me.Contagious
But you cannot commit Info.plist as once you do the build number is out-of-date. This type of solution, which isn't new, only works if you generate a file that is not tracked under version control and Info.plist is always tracked.Extradite
You definitely can commit Info.plist using this solution – that's the entire point. Info.plist is always set and checked in with the version number set to "DEVELOPMENT", it's temporarily changed during the build process and then afterward set to "DEVELOPMENT" again so Info.plist is stable.Contagious
Great solution! I changed "DEVELOPMENT" in the final step to be "•••\ AUTOMATED\ IN\ BUILD\ PHASES" - as that is much more informative. Also in the first step I added an update to the Settings bundle.Gallup
I think I prefer the build number to reset for each released version (which I always tag after archiving). So, I ended up using this https://mcmap.net/q/130481/-git-count-commits-since-tag for the build number.Gallup
Just updated this to only happen in release mode, which prevents it from interfering with SwiftUI previews. Ugh...Contagious
Further updated to only require a single build phase, by modifying the built product instead of source control. Much simpler and more reliable!Contagious
W
39

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

Scripts that I modified over time.

xcode-versionString-generator.sh,

xcode-build-number-generator.sh

As these gist are helping the dev community, I made GitHub project out of it. So let's develop it well. 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 into new "Run Script" section
# 5. Drag the "Run Script" below "Link Binaries With Libraries"
# 6. Ensure 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}"
Wimer answered 18/3, 2013 at 18:12 Comment(4)
This will always increment the build number, where as I wanted it only to increment if a source file changes. It's just the script I currently use with fewer safety checks and is less discerning of what has changed.Sterne
XCode 5: Editor (menu bar) → Add build phase → Add Copy Files Build Phase:Ballot
@Sterne : You can run this script as post commit hook. This scenario it will only increase build number when you do commit your code to repo. Answer below from LostInTheTrees is something more that you may wanna do.Wimer
The shell scripts linked to by @Alix are now quite different to the ones posted here. To increment the build number only when doing an archive build you can use a gist I have made, very much based on Alix's scripts above, here: gist.github.com/mattpotts/abcffea6d08ad45739efDunkle
B
29

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 (i.e., a placeholder in this example) 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.

Barely answered 15/2, 2012 at 14:12 Comment(4)
I don't need the git commit (or tag) in the plist file so a simple incrementing system is fine (as provided by agvtool), however the act of modifying the plist during the build breaks Xcode frequently (since removing the script it hasn't crashed once, when it was crashing every 3 builds or so). Is it possible to put the version info in another plist file and have that included with the bundle and accessible from the App?Sterne
Great script - I'd prefer to combine this with Hugues BR's suggestion to only use it when archiving builds. Keeps the numbers low and ignores however many dev builds are performed between releases.Bilk
What is get_build_number? Is that just some placeholder?Saintsimon
Yes, get_build_number is just a placeholder - updated the answer to clarify.Barely
L
14

This whole entry was extremely helpful. I used this trick but set up my script as a post-commit hook in GIT, so CFBundleVersion is incremented after every successful commit. The hook script goes in .git/hooks. A log is left in the project directory.

This meets my most basic criterion. I want to be able to pull a version from GIT and rebuild the exact build I had previously. Any increment done during the build process does not do this.

Here is my script:

#!/bin/sh
#
# post-commit
#
# This script increments the CFBundleVersion for each successful commit
#

plist="./XYZZY/XYZZY-Info.plist"
buildnum=$(/usr/libexec/Plistbuddy -c "Print CFBundleVersion" "$plist")
if [ -z "$buildnum" ]; then
    exit 1
fi
buildnumplus=$(expr $buildnum + 1)
/usr/libexec/Plistbuddy -c "Set CFBundleVersion $buildnumplus" "$plist"

echo $(date) "- Incremented CFBundleVersion to" $buildnumplus >> hookLog.txt
Lookin answered 7/2, 2013 at 17:38 Comment(1)
I have the same requirement, which is why the build number is only incremented if a source file has been modified. I have found this to work very well and haven't had to make changes to the bump_build_number.sh script since creation.Sterne
F
14

I don't know which way is the best, but I will post Apple's answer just in case anybody is searching for it...

According to this Apple's Q&A post:

Automating Version and Build Numbers Using agvtool

The version and build number keys respectively specify the marketing and internal versions of your application. agvtool is a command-line tool that allows you to automatically increment these numbers to the next highest number or to a specific number.

The build number identifies an unreleased or released version of your application. It is stored in your application’s Info.plist as CFBundleVersion(Bundle version).

You must complete the following steps in your Xcode project:

  1. Enable agvtool

Navigate to the Build Settings pane of your target, then update it for all your build configurations as follows:

  • Set Current Project Version to a value of your choosing.

Your Xcode project data file, project.pbxproj, includes a CURRENT_PROJECT_VERSION (Current Project Version) build setting, which specifies the current version of your project. agvtool searches project.pbxproj for CURRENT_PROJECT_VERSION. It continues running if CURRENT_PROJECT_VERSION exists and stops running, otherwise. Its value is used to update the build number.

  • Set Versioning System to Apple Generic.

By default, Xcode does not use any versioning system. Setting Versioning System to Apple Generic ensures that Xcode will include all agvtool-generated version information in your project.

Set Versioning System to Apple Generic

  1. Set up your version and build numbers

agvtool searches your application’s Info.plist for your version and build numbers. It updates them if they exist and does nothing, otherwise. Make sure that the CFBundleVersion (Bundle version) and CFBundleShortVersionString (Bundle versions string, short) keys exist in your Info.plist as seen in the image below:

Set up your version and build numbers

Quit Xcode, then navigate to the directory containing your .xcodeproj project file in the Terminal application before running any of the following commands. The .xcodeproj project file contains project.pbxproj, which is used by agvtool. (This is the part you can run in a script instead of command line.)

Updating the Version Number

To update the version number to a specific version, run

xcrun agvtool new-marketing-version <your_specific_version>

Ex: Update the version number to 2.0

xcrun agvtool new-marketing-version 2.0

Updating the Build Number

To automatically increment your build number, run

xcrun agvtool next-version -all

To set the build number of your application to a specific version, run

xcrun agvtool new-version -all <your_specific_version>

Ex: Set the build number to 2.6.9

xcrun agvtool new-version -all 2.6.9

Bonus:

To view the current version number, run

xcrun agvtool what-marketing-version

To view the current build number, run

xcrun agvtool what-version
Ferret answered 25/2, 2016 at 2:35 Comment(3)
Problem with this one is agvtool will abort the xcode build so it can't be integrated as a script in the build phases.Labor
Couldn't you just put bump via agvtool in the scheme's build pre-actions?Plenipotent
I added it as a Post-action script for building in the scheme. That way it increments after the build is successful and doesn't cancel out the build.Thach
B
11

FWIW - this is what I'm currently using to increase the build number only for release builds (which includes archiving). Works fine under Xcode 5.1.

Just copy/paste the snippet into a Run script build phase directly in Xcode:

buildnum=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$PRODUCT_SETTINGS_PATH")

if [ "$CONFIGURATION" = "Release" ]; then
buildnum=$((buildnum + 1))
echo "Build number updated to $buildnum"
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $buildnum" "$PRODUCT_SETTINGS_PATH"
fi;
Bilk answered 31/3, 2014 at 20:15 Comment(2)
How can you increment CFBundleVersion? In Xcode 5.1 it's a string formatted like "1.0"?Saintsimon
Finally someone doing it right :) Why would I care about each and every build I run on my dev device? Releases (and releases to testers) count, not the "hmm, move that 2px to the left" builds.Underdrawers
B
7

Thanks for the script. It works great.

My Info.plist is in a subdirectory with a name containing spaces so I had to modify the Run Script with quotes around the plist path:

${PROJECT_DIR}/tools/bump_build_number.sh "${PROJECT_DIR}/${INFOPLIST_FILE}"

and the shell script in the same way with quotes around all the paths:

#!/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
Bombshell answered 2/7, 2012 at 23:19 Comment(2)
Yeah that makes sense. Glad you find it useful; I've been using ever since with no problems at all under Xcode 4.{2,3,4,5}.Sterne
I would have saved myself a few hours if I saw this answer! Also, note that hte build number must not have a decimal, or BASH will croke.Shotten
D
6

The script I'm currently using is very much based on Alix's, above. My adaptation, below, adds a check to only do the auto-increment on a release/archive build.

Without that change there will be version control conflicts as each developer will be incrementing the build number at their own rate. And the fact that the git history would be unnecessarily polluted with the build number changing all the time.

# xcode-build-bump.sh
# @desc Auto-increment Xcode target build number every time the project is archived
# @src stackoverflow.com/a/15483906
# @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)

if [ "Release" != "${CONFIGURATION}" ]
then
    exit 0
fi

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}"

It's also available (in a slightly easier to copy and paste format) as a GitHub gist.

Dunkle answered 28/3, 2015 at 18:9 Comment(0)
Z
5

I would recommend the use of autorevision.

Xcode allows for a header file (which can be auto generated at build time and not in the vcs its self) to provide values that will be expanded in the info.plist at build time. You can find a walkthrough for setting this up on the autorevision website.

Autorevision has an output type geared towards these types header files to help in exactly these situations.

Zachery answered 29/8, 2013 at 2:47 Comment(3)
Autorevision doesn't appear to bump a build number, as required?Sterne
Assuming that one only builds on a new commit then VCS_NUM should be what you are looking for (see autorevision.h for an example).Zachery
Vienna-Info.plist and Vienna-All.xcconfig are a good example of how one can set this up in any xcode project.Zachery
M
4

One issue with some of these solutions is that Launch Services only recognizes four five major digits in the bundle version. I have a project with a build number that's in the thousands, so I wanted to use some of the less significant digits.

This Perl script increments all Info.plists in the project, not just the one for the current target, so the build numbers all stay in lockstep. It also uses one patch digit and two minor digits, so build 1234 is given version 1.23.4. I use it as a pre-build behavior, so it applies to all projects I build.

The script is pretty brute-force, but it does work for me.

#!/usr/bin/perl

use strict;
use warnings;
use v5.12.0;

use Dir::Iterate;

for my $plist_file(grepdir { /-Info.plist$/ } '.') {
    my $build = `/usr/libexec/PlistBuddy -c "Print CFBundleVersion" '$plist_file'`;
    chomp $build;

    next unless $build;

    # Strip dots
    $build =~ s/\.//g;
    $build =~ s/^0//g;

    # Increment
    $build++;

    # Re-insert dots
    $build =~ s/^(\d{0,4}?) (\d{0,2}?) (\d{0,1}?)$/$1.$2.$3/x;

    # Insert zeroes
    $build =~ s{(^|\.)\.}{${1}0.}g;

    system qq(/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $build" '$plist_file');
}
Metheglin answered 16/5, 2013 at 10:19 Comment(3)
The post you're quoting states that 'Effectively, LS expects the following format: nnnnn[.nn[.nn]][X] where n is a digit 0-9, square brackets indicate optional components, and X is any string not starting with a digit. X is ignored when present.' - so that's 99999 builds. Should be sufficient for most projects..?Bilk
@Bilk I apparently misread that as four digits. Oops. (Still, if your development style involves lots of tweaking and rebuilding, it's not inconceivable that you could reach 100,000 builds after years of development on a project.)Metheglin
@BrentRoyal-Gordon True - I've tweaked my build script to increment builds only for release configs.. even though I've probably never reached anywhere near 10k builds even with my 10+ year legacy product it does kind of feel good to have loads of head room with new Cocoa projects ;-)Bilk
P
4

You could use Apple's generic versioning. Basically all you have to do is call agvtool next-version -all from within the directory that hosts your .xcproj file. For more details check out the url above.

Paternal answered 31/8, 2015 at 17:38 Comment(1)
The problem with this solution is that calling agvtool from within a script in the project will cancel your build. It's not a good solution unless you can find a workaround for this.Urbanna
R
3

Building on Wil Gieseler's solution, I had just one change I wanted to make. His solution puts the count of git commits into the build number. Useful, but still kind of a pain to find the actual commit that created that build. I didn't care too much whether the build number was monotonically increasing, and so I dropped that requirement so that I could more easily access the commit that generated a given binary.

To that end, I modified his first script to the following:

# Set the build number to the decimal conversion of the short version of the current git SHA

# Get the short version of the current git SHA in hexadecimal
SHA=$(git rev-parse --short @)
# Uppercase any alphabetic chars in SHA (bc doesn't like lowercase hex numbers)
UPPERCASE_SHA=$(tr '[:lower:]' '[:upper:]' <<< "$SHA")
# Use bc to convert the uppercase SHA from hex to decimal
BUILD_NUM=$(bc <<< "ibase=16;obase=A;$UPPERCASE_SHA")
# Set our build number to that
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUM" "${PROJECT_DIR}/${INFOPLIST_FILE}"

# To convert a build number back to a usable git SHA, run the following, substituting the build number for <build number>
# bc <<< "ibase=10;obase=16;<build number>"

This converts the short version of the current git SHA into decimal. Hexadecimal characters don't play nicely with Apple's build number requirements, which is why I had to do this. To convert it back, you'd simply run something like this:

SHA=$(bc <<< "ibase=10;obase=16;<build number>")

in bash, where <build number> is the build number you got from a binary. Then, just run git checkout $SHA, and there you go.

Because this is an adaptation of Wil Gieseler's solution, as mentioned above, you'll also need the following post-build script:

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

which keeps your git history clean.

Rigidify answered 23/3, 2015 at 22:27 Comment(2)
So how does that work, given you will be writing the git info into Info.plist, which itself is tracked by git?Sterne
@Sterne As I mentioned at the top of the answer, this answer is an adaptation of Wil Gieseler's solution. As such, it requires the same post-build script used there. I've added that to the answer explicitly.Rigidify
K
2

I tried the modified procedure and it did not work, because:-

  1. Xcode 4.2.1 changes the xcuserdata subdirectory in .xcodeproj

  2. git notes the previous change in Project-Info.plist

The following modification causes these to be ignored and only flags genuine changes:-

if [ -n "$(find $dir \! -path "*xcuserdata*" \! -path "*.git" -newer $plist)" ]; then
Kharkov answered 9/4, 2012 at 5:17 Comment(0)
R
2

You may want to do this only when you archive (and upload to TF for example). Otherwise your version number might go up really quick..

In the scheme (Product / Edit Scheme / Archive / Pre-Actions) you can add a script that will be executed only when you archive.

Also, you might want to reset build number each time you increment the app version.

Last thing, if you use archive instead, you can safely disable:

# if [ -n "$(find "$dir" \! -path "*xcuserdata*" \! -path "*.git" -newer "$plist")" ]; then
...
# else
    # echo "Not incrementing build number as source files have not changed"
# fi

As the build number will be incremented only when you archive...

EDIT: Correct what I said, pre-actions in archive happen after build (but before archiving), so build number will be increment for next archive... But you can create a new scheme and add this action in the build (pre-actions) section of this new scheme. and use this scheme when you want to create a new build

Raguelragweed answered 18/12, 2012 at 3:23 Comment(1)
Yeah it is going up quickly (5500+ at the moment), but that isn't a problem for me; it's just a number. It's interesting just how many times Cmd-B/Cmd-R gets hit before anything even works though...Sterne
C
2

I use the last SVN revision for the build number. If you change the Info.plist in the build directory, you won't affect the source Info.plist:

# use the last SVN revision as the build number:
Info_plist="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Info.plist"
defaults write "${Info_plist}" CFBundleVersion `svn stat -u | awk '/'"Status against revision:"'/ {print $4}'`
Chaves answered 29/9, 2014 at 17:12 Comment(0)
G
2

Heres an updated version. This works as of Xcode 9.3.1, iOS 11.

Click on 'Build Phases' from your application target, click the + icon to add a new run script, and in the box, paste this code.

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}"

Go into the Info.plist file and set the 'Bundle version' to 1, and the 'Bundle versions string, short' to 1, you should be set.

Build the project with Info.plist in view, and you should see the Bundle version (Build number) change.

  • Note that as of Xcode 9.3.1, you will not be able to see these changes from the general tab, but will see the changes when you archive a build, and in Info.plist
Gurney answered 19/5, 2018 at 0:11 Comment(0)
G
2

I feel like I've found my tribe. Tribe, I hope you're amused by VersionX.

A decade ago while working on a workspace that had over 25 Xcode projects in it I took the opportunity to automate the version and build string updates to a degree which might seem absurd, if you're maintaining only a project or two with occasional updates.

VersionX:

  • is aware of the build type (Release / Debug)
  • gathers information at build time from the repository (git support included, but can be customized for hg, svn, or whatever you use)
  • provided for easily customizable fancy marketing version strings (which had much more variation before the App Store imposed a convention) so you could automatically increments strings which included symbols for a "beta" using a git tag convention, for example.
  • includes a class populated with instance variables containing version and commit information. This is useful for populating your about panel and constructing logging strings, crash reports, or user email bug reports with pre-populated information.

It was fun to make. I learned a boatload about the Xcode build system.

Here's an example of the type of fancy Version and Build strings VersionX could automatically generate.

VersionX 1.0.1 β7 (c5959a3 “Clean”)

Marketing Version: VersionX 1.0.1 β7 The "1.0.1 is derived from the tag for the commit, while The “Beta 7” is automatically generated by the commit count, or build count (for example).

Build Version: (c5959a3 “Clean”) Displays the short commit hash, and informs you that the build directory had zero uncommitted changes.

VersionX (source at GitHub) - a baroque system for automatically incrementing version and build strings in Xcode projects.

The VersionX Documentation.

Goodell answered 19/9, 2018 at 16:26 Comment(0)
E
1

You might want to check out a new tool I've been developing called Xcodebump. It can handle updating both CFBundleShortVersionString and CFBundleVersion. As a final step it will also checkin to git and tag the commit to match up with those CFBundle values.

The Xcodebump project is located here:

https://github.com/markeissler/Xcodebump

Emir answered 24/5, 2014 at 17:34 Comment(0)
G
1

I update build number by following method.

$INFO_FILE is the path of the plist file. And $build_number is a new build number for this building.

/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $build_number" "${INFO_FILE}"

Generally, my $build_number is composed by major and minor parts. The minor is come from project information. So I describe how to generate the major part.

## Composed by `major` and `minor`. 
## `minor` is parsed from project information. It's another story.
## Examples: `21.1`, or `21.1.3`
build_number="${major_number}.${minor_number}"

I have 2 strategies to decide the $build_number.

First Strategy

This strategy uses the git tag count to decide the major of build number. If there are 53 tags of the project, it will return 53 by following shell script.

Generally, it's increasing. And it will force the developer to put a git tag before publishing.

major_number=$(git tag -l | wc -l | grep -oE "\d+")

Second Strategy

Let Jenkins CI system decide the major part. It has an environment variable BUILD_NUMBER. It is increasing automatically when building on the CI system. This information is useful to trace the project history on the CI system.

major_number=${BUILD_NUMBER}
Gauss answered 2/8, 2016 at 7:15 Comment(0)
D
1

I find it most convinient to use Automating Version and Build Numbers Using agvtool.

Try this:

  1. Configure it as described in Apple's documentation linked above.
  2. Add script as Pre-action to Project -> Edit Scheme... -> Archive (or other if you prefer)
  3. Set: Provide build settings from <your_app_target>

The script (first line is optional):

exec > ${PROJECT_DIR}/prebuild.log 2>&1
cd ${PROJECT_DIR}
xcrun agvtool next-version -all
cd -
Designation answered 24/2, 2019 at 5:50 Comment(1)
Also using this but in post action. Pre sometime fails.Matthaus
R
0

Here's my solution. If you're like me: terminal friendly, like ruby, like semantic versioning, try this.

Make a file named Rakefile which contains this:

require "xcodeproj"
require "versionomy"

XCODEPROJECT = "MyProject.xcodeproj"
INFOPLISTFILE = "MyProject/MyProject-Info.plist"

$UPDATES = [:major,:minor,:tiny]
$UPDATES.each { |part|
  desc "increment #{part} part of version"
  task "increment:#{part}" do |task|
    version=`/usr/libexec/Plistbuddy -c "Print CFBundleVersion" #{INFOPLISTFILE}`.chomp
    version=Versionomy.parse(version)
    version=version.bump(part)

    # I use the same string for CFBundleVersion and CFBundleShortVersionString for now
    `/usr/libexec/PlistBuddy -c "Set :CFBundleVersion #{version}" #{INFOPLISTFILE}`
    `/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString #{version}" #{INFOPLISTFILE}`
    print "version upgraded to #{version}\n"
  end
}

Prepare: gem install xcodeproj versionomy

Run: rake increment:major or rake increment:minor or rake increment:tiny whenever you want.

Rexrexana answered 28/7, 2014 at 11:12 Comment(0)
M
0

Let's do this in Apple's own way. It will increase the build number after each successful build

I will guide you through 5 images, just go through it.

  1. Select 'Edit Scheme...' from the dropdown, when you select your Project name located in right side to the Stop_build_button. Check First Step

  2. From leftSide menu expand the 'Build' option and select 'Post-actions' Check Second Step

  3. Here you can add your desired Codes(Scripts) you want to execute after successful build of your program. It is the place where we have to add a little amount of code to make our automation work perfectly. >> 1. select the 'add (+)' button from leftSide corner to add new script file >> 2. Now from the drop down select 'New Run Script Action' Check Third Step

  4. It has 3 fields >> 1. shell is already assigned for you >> 2. now for 'Provide you build settings from' Select your Project Name. >> 3. Theres a big field to add your Script, just copy and past this code there : Check Fourth Step

    PLIST="${PROJECT_DIR}/${INFOPLIST_FILE}" PLB=/usr/libexec/PlistBuddy LAST_NUMBER=$($PLB -c "Print CFBundleVersion" "$PLIST") NEW_VERSION=$(($LAST_NUMBER + 1)) $PLB -c "Set :CFBundleVersion $NEW_VERSION" "$PLIST"

  5. After completing the 4th step just select 'Close' to close the window and we have to do the last step, Goto your 'plist.info' file in Project file menu and make sure 'Bundle Version' key under 'Key' Section most contain a Numeric Value Check Fifth Step

Minivet answered 3/4, 2020 at 3:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.