Steven Fisher
Steven Fisher

Reputation: 44876

Update CFBundleShortVersionString in dSYM at build?

I'm using this as a build phase in my project:

export PLISTBUDDY="/usr/libexec/PlistBuddy"

export INFO="${CODESIGNING_FOLDER_PATH}/Info.plist"
export RXREVISION=`git describe --tags | perl -pi -E "s/[^-]+\-([^-]+).*/\1/"`
export RXVERSION=`git describe --tags | perl -pi -E "s/([^-]+)\-[^-]+.*/\1/"`
$PLISTBUDDY $INFO -c "add CFBundleVersion string $RXREVISION"
$PLISTBUDDY $INFO -c "set :CFBundleVersion $RXREVISION"
$PLISTBUDDY $INFO -c "add CFBundleShortVersionString string $RXVERSION"
$PLISTBUDDY $INFO -c "set :CFBundleShortVersionString $RXVERSION"

This works perfectly for updating the build revision in the built application's Info.plist, and it doesn't mutate my source tree.

I have tried putting my Update Version script both at the end and also before the link phase. Either way, it's able to affect changes to the built application, but the dSYM is built from the original source tree.

This mismatch of version numbers between the built app and the built dSYM is a problem. (HockeyApp throws an error here.)

If I update the Info.plist in my source tree, I need to deal with it changing. Which leaves me two options that I can see:

  1. Put Info.plist under source control, and have the script edit it directly. But this means I'll need to check in the changes after each build.
  2. Ignore Info.plist, and have the script edit it directly. But there's plenty of other things in Info.plist that I do want under source control.

How can I get the version in the dSYM updating automatically, too, without having to deal with the Info.plist in my source tree changing every build?

Also, tangentially: How do I see the version in the dSYM?

Upvotes: 6

Views: 2912

Answers (4)

Václav Slavík
Václav Slavík

Reputation: 6660

Here’s the full script for the “Set CFBundleVersion from git” build phase I’m using:

APP_INFO_PLIST="${TARGET_BUILD_DIR}/${INFOPLIST_PATH}"
DSYM_INFO_PLIST="${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist"

BUILD_NUMBER=`git rev-list HEAD --count`

/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "$APP_INFO_PLIST"
if [ -f "$DSYM_INFO_PLIST" ] ; then
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "$DSYM_INFO_PLIST"
fi

(Note it must run after “Copy Bundle Resources” in Xcode 6+. In Xcode 10's new build system, make sure to specify the Info.plist file as part of its input files.)

Upvotes: 2

Brennan
Brennan

Reputation: 11686

I created a script that I can drop into any Xcode project folder and call from a Run Script which will update the Info.plist for the app and the dSYM so that the build number matches. It can then be uploaded to services like HockeyApp and iTunes Connect for TestFlight and the App Store.

I prefer to manage the script outside of Xcode's Run Script because I can edit it more easily and keep the contents of the project file much smaller. I can also version control the script independently of the project file.

The Build Number in this script is set with just the current date. There are other ways to generate a unique build number. One approach is covered on Jared Sinclair's blog which uses the Git hash for the latest commit. The script I am using uses a timestamp which goes down to a minute. I find it useful to know when a build was created and having the build number double as a timestamp I can see the date immediately. And for my purposes it is unique enough.

http://blog.jaredsinclair.com/post/97193356620/the-best-of-all-possible-xcode-automated-build

#!/bin/sh
set -e

# Purpose: Updates Info.plist for app and dSYM to a unique value for each build.

# Usage:
# Add as a Run Script in Xcode Build Phases

# UPDATE_SCRIPT=${PROJECT_DIR}/update_build_number.sh
# if [ -f ${UPDATE_SCRIPT} ]; then
#     sh ${UPDATE_SCRIPT}
# fi

BUILD_NUMBER=`date "+%Y.%m.%d.%H%M"`
APP_INFO_PLIST=${TARGET_BUILD_DIR}/${INFOPLIST_PATH}
DSYM_INFO_PLIST=${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist

if [ -f ${APP_INFO_PLIST} ]; then
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "${APP_INFO_PLIST}"
    echo "Updated ${APP_INFO_PLIST}"
else
    echo "Could not find ${APP_INFO_PLIST}"
fi

# Only the Release Configuration creates the dSYM
if [ "${CONFIGURATION}" = 'Release' ]; then
    if [ -f ${DSYM_INFO_PLIST} ]; then
        /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $BUILD_NUMBER" "${DSYM_INFO_PLIST}"
        echo "Updated ${DSYM_INFO_PLIST}"
    else
        echo "Could not find ${DSYM_INFO_PLIST}"
    fi  
fi

Upvotes: 0

Ivo Jansch
Ivo Jansch

Reputation: 1478

The accepted answer is correct, but doesn't give the actual details on how to modify the plist for the dsym. Adding the following lines to the build script modifies the plist in the dsym:

cd "$BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app.dSYM/Contents"
$PLISTBUDDY -c "Set CFBundleVersion $RXREVISION" Info.plist  

Upvotes: 4

Kerni
Kerni

Reputation: 15339

The dSYM package also has an info.plist in the root folder with similar values. You could probably modify that too in a similar way.

Another option is to define the version number in an extra .xcconfig file and include the version number from the info.plist into it, see here.

You could then also decide which kind of versioning you want or release or test builds, by using multiple independent info.plist files and referencing to different .xcconfig files in the build settings and don't include the one for test builds under source control.

In general I would suggest to do commits for every version change, since this makes the code really reproducible and also uniquely identify it in the source control system.

Apart from that, Apple specifies to set CFBundleVersion to a "monotonically increased string, comprised of one or more period-separated integers", see here. CFBundleShortVersionString is your marketing version, e.g. your goal is to work on version 3.0.

So how about doing the following for a release build: Update CFBundleVersion with the new build number and CFBundleShortVersion with the new marketing version like 3.0 Beta 1 and commit both of them and then tag that commit for release. Version numbers are part of your source like any other meta data, especially if the version number are also used to trigger specific code for compatibility, database upgrades or other things (which is often done).

Upvotes: 1

Related Questions