/dev/trouble
Eric Roller's Development Blog

Xcode build numbering update

- Posted in General by

Up until today, I have been using a Build Phase script to update the CFBundleVersion in the Info.plist file using a script like this:

#!/bin/bash

if [[ ! -d .git ]]; then
  echo "Error: Git setup not found: ./.git"
  exit 1
fi

# The number of commits in the master branch.
rev=$(expr $(git rev-list master --count) - $(git rev-list HEAD..master --count))

echo "Updating build number to $rev:"

for plist in 
    "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}" 
    ; do
  if [ -f "$plist" ]; then
    echo " -> $(file "$plist")"
    /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $rev" "$plist"
    plutil -lint -s "$plist"
  else
    echo " ?? $plist"
  fi
done

Sadly, with Xcode 15, this stopped working. Whether or not ENABLE_USER_SCRIPT_SANDBOXING was enabled or not, Xcode no longer allowed access to the plist file (or complained about a circular dependency).

So, now I am using a build configuration file to set build number; it needs to be added to the Xcode project, and selected in the project "Configurations". My file contains just:

// proj.xcconfig
CURRENT_PROJECT_VERSION = 0

Also, the Info.plist file needs to be updated to use:

<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>

My new methodology uses a "Build pre-actions" script (added in the target's scheme editor and using the build settings from the target) to update the .xcconfig file before every build:

#!/bin/bash
cd "$SOURCE_ROOT"

if [[ ! -d .git ]]; then
  echo "Error: Git setup not found: ./.git"
  exit 1
fi

# The number of commits in the master branch.
rev=$(expr $(git rev-list master --count) - $(git rev-list HEAD..master --count))

echo "Updating build number to $rev:"

sed -i '' "/CURRENT_PROJECT_VERSION/ { s/[[:digit:]]\{1,\}/$rev/; }" ./*.xcconfig

But since the .xcconfig file is also a revision-controlled file, I reset the value again in a "Build post-actions" script. Similar to using git restore to revert the changes:

#!/bin/bash
cd "$SOURCE_ROOT"
sed -i '' '/CURRENT_PROJECT_VERSION/ { s/[[:digit:]]{1,}/0/; }' ./*.xcconfig

Explanation of the sed code:

  • For any file matching *.xcconfig,
  • modify it "in place" (not creating a backup file),
  • all lines containing "CURRENT_PROJECT_VERSION",
  • substitute one or more digits with $rev or 0.