31

What is a Build number and what is its use? Is it the same as version number?

John Topley
  • 113,588
  • 46
  • 195
  • 237
Peter V
  • 2,478
  • 6
  • 36
  • 54
  • 2
    Based on @cdashers code i added a simple script to github for everybody to use. https://github.com/rbosch/Xcode-BuildNumber – Roger Nov 17 '13 at 23:40

9 Answers9

20

Additionally, if you add CFBuildDate as a string and CFBuildNumber as a string into your info.plist, the following shell script (when added to your run script build phase /bin/bash will automatically update your build number and date:

    # Auto Increment Version Script
buildPlist=${INFOPLIST_FILE}
CFBuildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBuildNumber" $buildPlist)
CFBuildNumber=$(($CFBuildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CFBuildNumber $CFBuildNumber" $buildPlist
CFBuildDate=$(date +%Y%m%d%H%M%S)
/usr/libexec/PlistBuddy -c "Set :CFBuildDate $CFBuildDate" $buildPlist
cdasher
  • 3,083
  • 1
  • 19
  • 20
  • 1
    On Xcode 4, I changed `CFBuildNumber` to `CFBundleVersion ` so it number would show in the `Build` field in the Targets Summary editor. – Ross May 31 '12 at 15:56
  • 3
    I changed incrementing the CFBuildNumber in the plist, to setting the CFBundleVersion to `buildNum=\`git log --oneline | wc -l\`` to pull a build identifier out of git – Kenny Winker Aug 16 '12 at 08:55
  • 1
    @KennyWinker better use `git rev-list HEAD --count` – pronebird Dec 23 '13 at 16:18
  • Make sure this step is as high as possible on the list of "Build Phases" otherwise what you see in app will be inacurate. – Lukasz 'Severiaan' Grela Jun 10 '14 at 07:26
  • Also when I tried with CFBuildDate as string then empty string is stored, when I set CFBuildDate to be date with format suggested by Rogier then date is saved but it is not overridden by next builds - it shows only first build date - does anyone had the same? – Lukasz 'Severiaan' Grela Jun 10 '14 at 09:10
  • It was me being daft:) I wanted to "format" code and put spaces around "=" so instead of `CFBuildDate=$...` I had `CFBuildDate = $...`. And the date was not saved only one time but it was default set by XCode when I changed type from string to date. – Lukasz 'Severiaan' Grela Jun 10 '14 at 09:25
  • Huh? Why does this answer start "additionally"? How does it answer the question? – Mark Amery Jan 25 '16 at 11:17
17

I'm using Xcode 4.3.3 (4E3002) and managed to have build number (CFBundleVersion) automatically increased every build with the following steps:

  1. Select the menu item Product/Edit Scheme... (Command+<)
  2. Expanded the Build phase
  3. Select Pre-actions
  4. Clicked on the plus sign to add "New Run Script Action"
  5. Entered "/bin/bash" as the "Shell"
  6. Select one of the targets in "Provide build settings from"
  7. Entered the following code:

    buildPlist=$SRCROOT/$INFOPLIST_FILE
    PlistBuddy="/usr/libexec/PlistBuddy"
    
    CFBundleVersion=`$PlistBuddy -c "Print CFBundleVersion" $buildPlist`
    CFBundleVersion=$(($CFBundleVersion + 1))
    $PlistBuddy -c "Set :CFBundleVersion $CFBundleVersion" $buildPlist
    

Have fun!

rmartinsjr
  • 539
  • 4
  • 6
  • WOW!!! This is perfect for my issue: automatically increasing CFBundleVersion and retrieving it by code without odd behavior... +1 and many thanks!!! – Giuseppe Garassino Jan 21 '13 at 23:09
  • In XCode 4.5 on OS X 10.8 I found that $SRCROOT/$INFOPLIST_FILE doesn't work, whereas $INFOPLIST_FILE is OK. – helioz Feb 26 '13 at 03:36
13

Many people use the build number to track the total number of times a project is "built" (simply compiled for small projects, maybe some more involved process for larger ones).

The build number is an absolute value incremented every build. A version number, on the other hand, is an arbitrary "label" or "tag" used as shorthand for a specific build number.

So say you've built your project 123 times, your build number is "123", but you might decide to refer to that as "version 1.0" for simplicity sake. If you build another 20 times to fix a bug, your build number is 143, but your version is "1.01" or "1.1" or whatever you decide to name it.

I've also seen projects that base their build numbers on source control. So a CVS/SVN team might use the revision number as their build number. I've also seen git projects that use the SHA of the latest commit as a build number (although some management tools assume the build number is an incremental value — and obviously in the case of SHAs, it's not).

jemmons
  • 18,605
  • 8
  • 55
  • 84
5

The Build number is an internal number that indicates the current state of the app. It differs from the Version number in that it's typically not user facing and doesn't denote any difference/features/upgrades like a version number typically would.

Think of it like this:

  • Build (CFBundleVersion): The number of the build. Usually you start this at 1 and increase by 1 with each build of the app. It quickly allows for comparisons of which build is more recent and it denotes the sense of progress of the codebase. These can be overwhelmingly valuable when working with QA and needing to be sure bugs are logged against the right builds.
  • Marketing Version (CFBundleShortVersionString) - The user-facing number you are using to denote this version of your app. Usually this follows a Major.minor version scheme (e.g. MyAwesomeApp 1.2) to let users know which releases are smaller maintenance updates and which are big deal new features.

To use this effectively in your projects, Apple provides a great tool called agvtool. It allows you to easily set both the build number and the marketing version. It is particularly useful when scripting (for instance, easily updating the build number on each build or even querying what the current build number is). It can even do more exotic things like tag your SVN for you when you update the build number.

To use it:

  • Set your project in Xcode, under Versioning, to use "Apple Generic".
  • In terminal
    • agvtool new-version 1 (set the Build number to 1)
    • agvtool new-marketing-version 1.0 (set the Marketing version to 1.0)

See the man page of agvtool for a ton of good info

Bdebeez
  • 3,542
  • 3
  • 31
  • 32
  • One thing I had to make sure of, and maybe using `avgtool new-version` does this, is that if you want agvtool to set the CFBundleVersion ("Build" in the Summary tab or "Bundle Version" in the Info tab) and you want it to set the CURRENT_PROJECT_VERSION, they both already have to be defined to something. agvtool won't set them otherwise. – devguydavid Feb 12 '13 at 21:16
4

If you want to use a DATE field for CFBuildDate, use:

# get UTC date
CFBuildDate=$(date -u +"%a %b %d %T GMT %Y")

btw great tip from cdasher

Roger
  • 7,535
  • 5
  • 41
  • 63
4

Build Number is for minor updates(usually get pretty high 1 at the beginning and can end at 1000), ex: if you change a couple lines of code but doesn't change the logic or make new features in your update. Version Number is for rather large updates ex: new features in your app. Then you can change it from 1.8 to 2.0.

Finn Larsen
  • 2,201
  • 17
  • 26
2

This works for me in Xcode 6:

cd ${SOURCE_ROOT}
buildPlist=${SOURCE_ROOT}/${PROJECT_NAME}/${PROJECT_NAME}-Info.plist
PlistBuddy="/usr/libexec/PlistBuddy"

buildNumber=`git rev-list HEAD --count`
buildNumber=$(($buildNumber + 1))

$PlistBuddy -c "Set :CFBundleVersion $buildNumber" $buildPlist
Kiran
  • 1,067
  • 1
  • 11
  • 25
2

This works in Xcode 6 and also modifies the dSYM info dictionary, only when archiving:

if [ "${CONFIGURATION}" = "Release" ]; then

buildPlist="${SOURCE_ROOT}/${PROJECT_NAME}/${PROJECT_NAME}-Info.plist"

PlistBuddy="/usr/libexec/PlistBuddy"

CFBundleVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}")
CFBundleVersion=$(($CFBundleVersion + 1))

$PlistBuddy -c "Set :CFBundleVersion $CFBundleVersion" "$buildPlist"
$PlistBuddy -c "Set :CFBundleVersion $CFBundleVersion" "$INFOPLIST_FILE"
$PlistBuddy -c "Set :CFBundleVersion $CFBundleVersion" "${DWARF_DSYM_FOLDER_PATH}/${WRAPPER_NAME}.dSYM/Contents/Info.plist"
fi
edwardmp
  • 6,339
  • 5
  • 50
  • 77
  • A comment would have sufficed; no need for a new answer where all you are doing is adding quotes. – trojanfoe Feb 25 '15 at 14:22
  • I can't neatly paste this in a comment, is less readable when newlines are stripped – edwardmp Feb 25 '15 at 14:23
  • I modified some other things – edwardmp Feb 25 '15 at 14:37
  • There is an easier way: Create a build target and use it to run the original script to modify the `Info.plist` file. Then make the normal Xcode project target dependent on this new script target. That will avoid the issue you are trying to avoid. This was used as far back as Xcode 4.2 which used to crash if you messed with the `Info.plist` using *Build Phase* scripts. [Related](http://stackoverflow.com/questions/9258344/better-way-of-incrementing-build-number). – trojanfoe Feb 25 '15 at 14:57
  • The blogpost is from 2014 so I doubt it was only necessary in Xcode 4.2 and earlier... – edwardmp Feb 25 '15 at 14:59
  • @edwardmp, I presume the dsym is generate during compile. Assuming this script is run post-compile, then would not the dsym package build number be out of synch by +1? – Electro-Bunny Mar 02 '15 at 22:30
1

CFBundleVersion (Bundle version) - aka Marketing version which will be shown on your product's page on Appstore.

CFBundleShortVersionString (Bundle versions string, short) - bundle number, usually used as a minor version which can be seen by TestFlight users only

Here's how can you get them in Swift (4+) programmatically:

let buildNumber = Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as? String,
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString")

I needed the marketing version in my shell script once and here's how I got it using xcode build tools:

xcodebuild -showBuildSettings -project ${SDK_PROJECT} | sed '1d;s/^ *//;s/"/\\"/g;s/ = \(.*\)/="\1"/;s/ = /=/;s/UID.*//' > xcodebuild-env.tmp
source xcodebuild-env.tmp

echo "${MARKETING_VERSION}"
Henadzi Rabkin
  • 6,834
  • 3
  • 32
  • 39