Xcode Buildscripts erleichtern den Entwickleralltag

Nichts versetzt das Hirn schneller in komatöse Zustände als stupide, repetitive Aufgaben. Glücklicherweise kennt jeder gute Entwickler hier einen Ausweg: das Shellscript. Dabei ist es vollkommen egal, ob die Erstellung des Scripts potenziell mehr Zeit benötigt, als die direkte, nervenzerrende, in den Wahnsinn treibende, Bewältigung von Sisyphos-Aufgaben. Denn sie verschont deine Nerven.

Die Scripterstellung eignet sich jedoch nicht nur als Ausweg in hoffnungslosen Situationen, sondern auch zur Standardisierung von wiederkehrenden Aufgaben, wie der automatisierten Markierung einzelner Commits in Git oder der Erhöhung der Buildnummer in Xcode. Dies ist vor allem im Zusammenhang mit iTunes Connect praktisch, da jede ausgelieferte Version, egal ob Beta- oder Storerelease, eindeutig bezeichnet sein muss, damit ein Upload nicht am „Duplicate Binary“-Error scheitert.

Xcode bietet die Möglichkeit eigene Build Phasen zu definieren.

Die Reihenfolge der einzelnen Phasen kann per Drag-and-Drop geändert werden. Es ist wichtig, dass das hier erstellte Script vor der „Compile Sources“-Phase ausgeführt wird, da in dieser die Buildnummer des Projekts hart in das gebaute Archive geschrieben wird. Durch einen Doppelklick auf den generischen Namen der erstellten Phase kann dieser geändert werden. 

xcode build phasen definieren

Das erstellte Script besteht aus vier Phasen:

1. Build Status

Über die globale Configuration Variable kann der Status des momentanen Builds abgefragt werden.

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

Eine Übersicht aller von Xcode bereitgestellten Variablen kann in der Apple Dokumentation gefunden werden. 

2. Check Git

Um später einen sauberen Commit machen zu können, ist es nötig, dass keine ungesicherten Änderungen im Working Tree vorhanden sind. Hierzu wird der momentane git-Status abgefragt und überprüft, ob ein bestimmter String im Output vorkommt.

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

Kommt dieser nicht vor, ist die Variable GitStatus leer und die folgende Überprüfung lässt den Build, mit einer custom Error-Message, durch den exit Befehl scheitern.

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

Xcode bietet zwei Möglichkeiten für eigene Fehlermeldungen: error und warning. Der mit echo ausgegebene Text muss lediglich mit einem dieser Schlüsselwörter gefolgt von einem Doppelpunkt beginnen, damit er von der IDE richtig interpretiert wird.

3. Info.plist

Die Info.plist ist Bestandteil jedes Xcode-Projekts und biete eine Möglichkeit Informationen dauerhaft zu speichern. Die globale Variable INFOPLIST_FILE erlaubt den Zugriff; das Programm PlistBuddy das Lesen und Schreiben der Datei. Die aktuelle Buildnumber ist unter dem Key CFBundleVersion gespeichert. Dieser wird ausgelesen, um 1 erhöht und wieder zurück geschrieben. Es ist ebenso möglich eigene Keys im .plist File zu definieren und diese mit den hier beschriebenen Werkzeugen auszulesen und zu setzen. 

# 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

Leider verbietet Xcode in der aktuellen Version nicht-numerische Werte in dem Feld Buildnumber. Daher ist es leider unmöglich weitere Meta-Informationen in Form eines Hashes zu hinterlegen.

4. Taggen der Build version

Der letzte Arbeitsschritt ist das Erstellen eines dezidierten Commits, welcher mit der generierten Buildnumber getaggt wird.

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

Es wird bewusst auf einen Push verzichtet. Dies geschieht, da im Fall eines Fehlers lokal Änderungen an der Versionskontrolle vorgenommen werden können bevor diese tatsächlich anderen Entwicklern zur Verfügung gestellt werden.

Zusammenfassung

Build Scripts ermöglichen eine einfache Automatisierung sich wiederholender Aufgaben und reduzieren so Fehlerquellen, die einen reibungslosen Ablauf der (automatisierten) Softwareerstellung gefährden. Im Zusammenhang mit Continuous Integration/Deployment Prozessen erlauben sie eine genaue Anpassung an die gegebenen Verhältnisse und Vorgaben.

xcode build phase automatisieren

Der vollständige 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