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.

Titelbild

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 man per Drag-and-Drop ändern. Es ist wichtig, dass man das hier erstellte Script vor der „Compile Sources“-Phase ausgeführt. Da man in dieser die Buildnummer des Projekts hart in das gebaute Archive schreibt und durch einen Doppelklick auf den generischen Namen der erstellten Phase, kann man diesen ändern. 

xcode build phasen definieren

Das erstellte Script besteht aus vier Phasen:

1. Build Status

Die globale Configuration Variable kann den Status des momentanen Builds abfragen.

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

Eine Übersicht aller von Xcode bereitgestellten Variablen kann man in der Apple Dokumentation finden. 

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 IDE ihn richtig interpretieren kann.

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 auf das Programm PlistBuddy und 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 man im Fall eines Fehlers lokal Änderungen an der Versionskontrolle vornehmen kann. Bevor man diese tatsächlich anderen Entwicklern zur Verfügung stellt.

Zusammenfassung

Build Scripts ermöglichen eine einfache Automatisierung sich wiederholender Aufgaben. Sie 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