Make your Life as a Developer easier with Xcode Buildscripts

Nothing has the potential to leave your brain in a comatose state faster than stupid, repetitive tasks. Luckily, every developer worth their salt knows a way to avoid them: the shell script. We do not care that writing this script may take more time than directly dealing with those maddeningly annoying and seemingly never ending tasks we’re trying to avoid. It protects our sanity.

Building a shell script is not only a way out of any hopeless situation, it also helps to standardize recurring tasks such as the automated marking of individual commits in Git or incrementing the build number in Xcode. They are especially useful when working with iTunes Connect, since every release – whether it is a beta or a sore release – must be uniquely defined so as not to fail due to a “duplicate binary” error.

Xcode lets you define your own build phases

You can change the order of the phases via drag-and-drop, and double-clicking on the generic name of a phase lets you change it. It is important that you run the script we are building here prior to the “compile sources” phase, since the project’s build number will be hardcoded into the created archive during that phase.

xcode build phasen definieren

the script consists of 4 phases:

1. build status

You can request the status of the current build via the global configuration variable.

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

You can find an overview of all Xcode variables in the Apple documentation.

2. check Git

In order to be able to make a clean commit later, any unsaved changes in the working tree must be avoided. Therefore, you should request the current Git-status and check for a certain string in the output.

GitStatus=$(/usr/bin/git status | /usr/bin/grep "nothing to commit, working directory clean“)

If this string does not appear, the GitStatus variable is empty and the following check will make the build fail with a custom error message through the ‘exit’ command.

echo "error: Please, commit all your changes before archive can be created."
exit 1

Xcode gives you two possibilities for creating custom error messages: error and warning. The text output with ‘echo’ just needs to start with one of these two keywords followed by a colon in order for the IDE to interpret it correctly.

3. Info.plist

The Info.plist is contained in every Xcode project and lets you save information permanently. The global variable INFOPLIST_FILE gives you access and the program Plist Buddy allows you to edit and save the file. The current build number is saved under the key CFBundleVersion. This key is retrieved, incremented by 1 and saved. It’s also possible to define your own keys in the .plist file and to retrieve and set them with the tools described here.

# get plist 
buildPlist=${INFOPLIST_FILE} 
# increment build number 
CFLBuildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" $buildPlist) 
CFLBuildNumber=$(($CFLBuildNumber + 1)) 
/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $CFLBuildNumber" $buildPlist

Regrettably, the current version of Xcode does not allow for non-numerical values in the build number field. Therefore, it’s unfortunately not possible to save any further meta info in the form of a hash.

4. tagging the build version

The last step is creating a distinct commit which is tagged with the generated build number.

# update git
  /usr/bin/git add .
  /usr/bin/git commit -a -m "Created Archive with Build #$CFLBuildNumber."
  /usr/bin/git tag $CFLBuildNumber

Pushing is consciously omitted here. This is done so that, in case of an error, changes to the version control can be made locally before making them available to other developers.

TL;DR

Build scripts allow for a simple automation of recurring tasks and thus reduce error potentials endangering a smooth (automated) software programming process. In connection with continuous integration/deployment processes, they allow for an exact adaptation to the given circumstances and standards.

xcode build phase automatisieren

the complete code

 # Auto Increment Version Script
if [ ${CONFIGURATION} == "Release" ]
then
# check git
  GitStatus=$(/usr/bin/git status | /usr/bin/grep "nothing to commit, working directory clean")
  if [ ${GitStatus} == "" ]
  then
    echo "error: Please, commit all your changes before archive can be created."
    exit 1
  fi
# get plist
  buildPlist=${INFOPLIST_FILE}
# increment build number
  CFLBuildNumber=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" $buildPlist)
  CFLBuildNumber=$(($CFLBuildNumber + 1))
  /usr/libexec/PlistBuddy -c "Set :CFBundleVersion $CFLBuildNumber" $buildPlist
# update git
  /usr/bin/git add .
  /usr/bin/git commit -a -m "Created Archive with Build #$CFLBuildNumber."
  /usr/bin/git tag $CFLBuildNumber
fi