Native Cross-Plattform-Entwicklung mit Microsoft-Technologien

Continuous Integration mit Xamarin
Keine Kommentare

Fragebogen aus Papier sind eigentlich Relikte aus vergangenen Zeiten – und dennoch sieht man sie an fast jedem Messestand. Die spätere Bearbeitung nimmt Zeit in Anspruch und der Interessent muss geduldig auf eine versprochene Antwort warten. Faktisch nutzt jeder Aussteller jedoch Smartphones. Es bietet sich also an, sämtliche Fragenbogen mit einer geeigneten App zu erfassen, inklusive Goodies wie Visitenkartenscanning, automatisierter Verarbeitung im Back Office und dem anschließenden Versand angeforderter Informationen nach einem Messebesuch.

Ganz so einfach wie eben skizziert ist die Sache jedoch nicht, da iOS, Android und Windows Phone unterstützt werden müssen. Heißt das, dass drei Apps von verschiedenen Teams gebaut werden müssen? Die Antwort lautet: Ja und Nein. Einerseits braucht man für jede Plattform ein eigenes Binary, das bei geeignetem Softwaredesign und Technologie eine große gemeinsame Codebasis haben kann. Andererseits wird Know-how benötigt im Umgang mit plattformspezifischen Eigenheiten wie dem Look and Feel (L&F) oder dem Build and Deployment der App. Im Folgenden wird geklärt, wie auf der Basis von Xamarin ein CI-Build von drei Apps mithilfe des Microsoft Team Foundation Server 2013 (TFS) durchgeführt werden kann und wie sich Teile des Sourcecodes aus drei Plattformen erneut verwenden lassen.

Native-Apps mit Xamarin

Das Xamarin-Produkt hat seine Wurzeln in der Mono-Community und bietet plattformspezifische APIs und Tools für iOS und Android als .NET Framework an. Die Entwicklung erfolgt komplett mithilfe von C#. Dies ermöglicht C#-Entwicklern in der gewohnten Programmiersprache und mit den gewohnten Tools für verschiedene Endgeräte Apps zu entwickeln. Soll eine App für mehrere Pattformen entwickelt werden, dann wird für jede Plattform das spezifische Look and Feel unterstützt. Dabei werden nicht, wie in der Vergangenheit, alle Benutzeroberflächen unter einer einheitlichen Programmierschicht vergraben. Im Gegenteil: Apps auf der Basis von Xamarin fördern die Programmierung auf Basis des spezifischen L&F der jeweiligen Plattform, weil die dafür notwendigen APIs und Frameworks in C# unterstützt werden.

Als Konsequenz für das Projekt ergibt sich, dass Teile der Sourcen für jede Plattform individuell entwickelt werden, während andere Teile auf allen Plattformen wiederverwendet werden können. Aber wie kann eine C#-App auf iOS oder Android laufen?

Xamarin arbeitet so, dass für Android zusätzlich zur App eine Mono Runtime ausgeliefert wird, in der die App auf dem mobilen Endgerät ausgeführt wird. Für iOS wird eine Cross-Compilation durchgeführt und aus dem .NET-Bytecode nativer iOS-Code erzeugt. Wichtig zu erwähnen ist, dass die iOS-App unter Mac und mit der IDE Xcode gebaut sein muss. Leider kann Xamarin an dieser Entwicklungskonstellation für iOS bisher nichts ändern. Mit beiden Ansätzen erhält man also eine native Applikation für die jeweiligen Endgeräte.

Zusätzlich stellt der Hersteller mit Xamarin Studio eine IDE und für Visual Studio Plug-ins zur Verfügung. Auch ein Component Store für Third-Party-Frameworks und eine eigene Test-Cloud für automatisierte Oberflächentests auf physikalischen Endgeräten können genutzt werden.

Stellen Sie Ihre Fragen zu diesen oder anderen Themen unseren entwickler.de-Lesern oder beantworten Sie Fragen der anderen Leser.

Somit vereinigen Xamarin-basierte Apps die Vorteile von hybriden und nativen Apps. Denn auf jeder Plattform wird gegen das native UI entwickelt und die entsprechenden Plattform-APIs genutzt. Dies führt zu einer hohen Performance der App und zur Integration der App ins Look and Feel der jeweiligen Plattform.

Continuous Integration mit Microsoft TFS 2013 und Visual Studio 2013

Tragendes Element während der Entwicklung der App stellt der Microsoft Team Foundation Server 2013 (TFS) dar. Der TFS ist der zentrale ALM-Server. Im Projekt wird seine Sourcecode-Verwaltung, sein Projektmanagement und sein Continuous-Integration-Service genutzt. Auch wenn alle drei Apps auf Xamarin basieren und eine gemeinsame Codebasis haben, so existieren doch drei verschiedene CI-Builds zum Bau der Apps für Windows Phone, iOS und Android. Beginnen wir mit dem Build der Windows-Phone-App (Abb. 1).

Abb. 1: Build-System für Windows-Apps

Abb. 1: Build-System für Windows-Apps

Auf dem Entwicklerrechner wird Visual Studio 2013 sowie das Windows-Phone-SDK für die Windows-Phone-Entwicklung vorausgesetzt. Nach Check-in der Sourcen im TFS beauftragt der TFS seinen Build Agent, die aktuellen Sourcen zu bauen. Der Agent ist auf einer separaten Maschine installiert, die in der Verantwortung des Projekts liegt, da der zentrale TFS auch für andere Projekte genutzt wird. So kann projektspezifische Software auf der Agentmaschine installiert werden, ohne dass es zu Seiteneffekten mit anderen Projekten kommt.

Der TFS Build Agent kompiliert die Sourcen, nutzt FxCop für eine statische Codeanalyse und führt Unit Tests durch. Integrations- oder UI-Tests können im Windows Phone Emulator durchgeführt werden. Die erstellten Binaries werden auf einen Fileshare abgelegt und lassen sich im Rahmen des Qualitätsmanagements für umfangreiche Tests verwenden.

Der Build für die Android-Plattform verläuft sehr ähnlich zum Windows Build (Abb. 2). An der Stelle ist der Umgang mit Android sehr pflegeleicht. Zum Entwickeln der eigentlichen Android-App wird auf dem Client zunächst das Android-SDK benötigt.

Abb. 2: Build-System für die Android-App

Abb. 2: Build-System für die Android-App

Visual Studio oder Xamarin Studio können als IDE eingesetzt werden. Spätestens hier beginnt die Entwicklung auf der Basis von Xamarin, während Xamarin bei den Windows-Apps nicht genutzt wird. Der TFS steuert nach einem Check-in den gleichen TFS Build Agent an, der auch für den Windows-Build zuständig ist. Auf der Agentmaschine muss Xamarin und das Android-SDK installiert sein. Tests, die keinen plattformspezifischen Code überprüfen, wurden im vorherigen Windows-Build ausgeführt. Die Android-App wird ebenfalls einer statischen Codeanalyse und einem UI-Test im Emulator unterzogen. Zum Schluss wird das Binary auf einem Fileshare zur Verfügung gestellt.

Der Build der iOS-App ist nicht ganz so einfach in diesem Szenario zu realisieren (Abb. 3). Zunächst wird ein Apple Mac zur Entwicklung benötigt. Zwar kann ein großer Teil der Entwicklung auch mit Visual Studio 2013 durchgeführt werden, aber für GUI-orientiertes Entwickeln oder den Bau der iOS-App ist ein Mac mit der Xcode-IDE eine Voraussetzung. Damit der Entwickler an seine Source im TFS herankommt, wird der GIT-Client „Git-TF“ eingesetzt.

Abb. 3: Build-System für iOS-Apps, schwarze Komponenten benötigen Mac OS

Abb. 3: Build-System für iOS-Apps, schwarze Komponenten benötigen Mac OS

Seit Xamarin-Release 3 (Okt. 2014) kann alternativ die GUI-Entwicklung auch mithilfe der Xamarin-IDE oder mit dem Xamarin-Plug-in für Visual Studio unter Windows durchgeführt werden.

Die entscheidende Frage ist nun: Wie wird ein iOS-Build auf dem Mac durchgeführt? Denn es gibt keinen TFS Build Agent für den Mac. Die kurze Antwort lautet: CI-Build-Server Jenkins verwenden.

Jenkins ist einer der bekanntesten Open-Source-CI-Server, der insbesondere im Java-Umfeld genutzt wird. Durch sein umfangreiches Plug-in-Konzept kann er leicht an verschiedenste Projektanforderungen angepasst werden. Beispielsweise kann er Visual Studio Solutions mithilfe eines MSBuild-Plug-ins bauen und mit dem MSTest-Plug-in Unit Tests durchführen.

Xamarin im Videotutorial

entwickler.tutorialsIn unserem entwickler.tutorial Einstieg in Cross-Plattform-App-Development mit Xamarin zeigt Jörg Neumann, wie Xamarin funktioniert und wie Sie das Maximum aus der Plattform herausholen können. Wer sich jetzt anmeldet, sichert sich das 3-in-1 Gratistutorial – und kann das erste Kapitel des Tutorials kostenlos sehen!

Jenkins-Integration

Mit der Einführung von Jenkins in den Build-Ablauf existieren jetzt zwei unabhängige Build-Server. Somit ist die Situation entstanden, dass der Status eines Builds über beide CI-Server ermittelt werden muss. Da der TFS als führender Build-Server bestimmt wurde und als „Single Point of Entry“ für beispielsweise Visual Studio 2013 dient, wird Jenkins untergeordnet in den Build-Ablauf integriert. Ziel der Integration ist es, dass der Jenkins-Server wie ein TFS Build Agent fungiert. Das Vorgehen zur Integration von Jenkins ist kurz beschrieben (Abb. 4):

  1. TFS entscheidet, wann iOS-Build durchgeführt wird
  2. TFS beauftragt Jenkins mit iOS-Build
  3. Jenkins startet iOS Build Slave auf Mac mit Build
  4. iOS-Build Slave führt Build durch, App wird auf Fileshare kopiert
  5. Build-Status und Build-Log wird von TFS abgeholt
  6. TFS verarbeitet das Ergebnis
Abb. 4: Integration von Jenkins in den iOS-Build-Ablauf

Abb. 4: Integration von Jenkins in den iOS-Build-Ablauf

Jenkins kann nahezu komplett über sein REST-API automatisiert werden. Builds können gestartet, der Status kann abgefragt und Logs können abgeholt werden. Dazu wurde ein eigenes Jenkins-Build-Template in TFS angelegt und zusätzlich eine Custom Code Activity entwickelt, die Jenkins in den Build-Ablauf einbindet und das Jenkins-REST-API kapselt.

Cross-Plattform-CI mit TFS

Setzt man jetzt alle drei CI-Build-Verfahren zusammen, dann ergibt sich das Gesamtbild aus Abbildung 5.

Abb. 5: Das gesamte CI-System zum Build der Apps für die drei Plattformen

Abb. 5: Das gesamte CI-System zum Build der Apps für die drei Plattformen

Ein neues Changeset im TFS stößt einen neuen Build-Vorgang an. Zunächst werden die Projekte gebaut, deren Sourcen auf allen Plattformen genutzt werden. Der Build-Schritt enthält auch das Ausführen der Unit Tests, sodass Probleme im gemeinsamen Code frühzeitig erkannt werden. Daraufhin werden die Windows-basierten Apps für Windows RT, Windows Phone 7.5/8 gebaut. Nach erfolgreichem Test der App im Windows Phone Emulator wird die App auf dem Fileshare abgelegt. Schließlich werden die Android-App und die iPhone-App wie oben beschrieben gebaut und die Binaries auf den Fileshare gelegt.

Sourcecode-Wiederverwendung

Eine wichtige Anforderung beim Entwickeln der App war es, eine möglichst hohe Wiederverwendbarkeit von Sourcecode auf allen drei Plattformen zu erreichen. Die Organisation des Sourcecodes in portable Klassenbibliotheken und plattformspezifischen Projekten ist ein erster Schritt. Die plattformspezifischen Projekte enthalten einerseits Sourcecode, der nur für die jeweilige Plattform benötigt wird, andererseits auch Sourcecode in Form von verlinkten Dateien, die aus technischen Gründen für jede Plattform separat kompiliert werden müssen. Visual Studio bietet mit der Projektvorlage „Portable Klassenbibliothek“ eine Möglichkeit an, eine „.DLL“ zu erzeugen, die auf verschiedensten Zielplattformen lauffähig ist. Dies stellt aber nur eine technische Voraussetzung zur Wiederverwendung von Code dar. Ohne eine geeignete Softwarearchitektur und geeignetes Softwaredesign zur Aufteilung der Sourcen in gemeinsame und plattformspezifische Bestandteile wird die Wiederverwendung eine Wunschvorstellung bleiben.

Selbstverständlich gelten alle Regeln des guten Designs auch bei der Entwicklung einer App. Im Sinne der Wiederverwendbarkeit von Sourcecode über verschiedenen Plattformen bieten sich drei Praktiken besonderes an:

  1. Separation of Concerns
  2. Dependency Injection (DI)
  3. MVVM-Pattern

Besteht beispielsweise die Anforderung, mit der Kamera des Mobilgeräts ein Bild aufzunehmen und dieses im Anschluss in einem definierten Ordner auf dem Gerät abzuspeichern, sollten diese zwei Arbeitsschritte (Bild aufnehmen, Zugriff aufs Dateisystem) nicht in einer einzigen Klasse implementiert werden. Stattdessen bietet es sich an, eine Klasse Camera zu entwickeln, die dafür zuständig ist, das Bild aufzunehmen und den entsprechenden Datenstrom, zum Beispiel als Byte-Array, an eine weitere Klasse zum Speichern zu reichen.

Diese zweite Klasse versieht man mit einem Interface und versorgt die Camera-Klasse mittels Dependency Injection mit einer Instanz dieses Interface. Somit können Camera-Klasse und das IFileSystem-Interface im plattformübergreifend genutzten Code implementiert sein, während zur Laufzeit eine plattformspezifische IFileSystem-Implementierung genutzt wird.

Zur Gestaltung des User Interface greift Xamarin jedoch auf die nativen Möglichkeiten der jeweiligen Plattformen zurück – iOS oder Android. Dies schränkt allerdings die Möglichkeit zur Wiederverwendung von Code zunächst auf die – nicht oberflächennahe – Businesslogik der App ein. Den gängigen Design-Patterns zur Anbindung von Businesslogik an die Oberfläche (wie Model View Controller oder Model View ViewModel) zufolge sollte der Code einer App in drei Teile mit unterschiedlichen Aufgaben organisiert werden:

  • View: enthält Oberflächenelemente wie TextBoxen und Buttons, sowie Darstellungslogik und Animationen
  • Model: enthält das domänenspezifische Datenmodell sowie die dazugehörige Businesslogik
  • ViewModel: dient als Verbindungsschicht zwischen View und Model; bereitet die Daten des Models so auf, dass die View sie leicht anzeigen kann und gibt nur noch Daten nach außen, die in der View auch benötigt werden; außerdem enthält das ViewModel so genannte „Commands“, mittels der die View Businessprozesse anstößt; das ViewModel dient der View als Abstraktionsschicht, um das Model zu orchestrieren; das ViewModel hält in der Regel keine Referenz auf „seine“ View, nur die View kennt „ihr“ ViewModel und baut zur Anzeige von Daten Data Bindings zwischen ihren Oberflächenelementen und Eigenschaften des ViewModels auf

Standardmäßig lässt sich in Xamarin-Apps nur der Model-Teil des Codes plattformübergreifend nutzen. Die Views werden mit den plattformspezifischen Tools entwickelt und weder Android noch iOS bieten das unter Windows Phone oder Windows 8/RT übliche Data Binding an, um Oberflächenelemente an die Daten zu binden. Ohne die Möglichkeit, Data Bindings aufzubauen, müsste allerdings auch die verbindende ViewModel-Schicht plattformspezifisch entwickelt werden.

Dies lässt sich beispielsweise durch den Einsatz des MvvmCross-Frameworks vermeiden. Es rüstet für iOS und Android die Möglichkeit zum Data Binding nach. Zudem bringt es ein plattformübergreifend nutzbares API für Dependency Injection sowie Navigation mit und ist über Plug-ins erweiterbar. Es vereinheitlicht außerdem den Code, der beim Start der Anwendung die nötigen Initialisierungsaufgaben übernimmt – den so genannten Glue-Code.

Fazit

Mit geeigneter Konzeption und Implementierung kann der TFS 2013 auch in einem Multi-Plattform-Projekt zum Bau von Apps verwendet werden. Das Einbinden von Android-Builds ist aufgrund der Offenheit der Android-Entwicklungsumgebung sehr einfach zu realisieren. Die Integration des iOS-Builds erfordert einen höheren Aufwand, der immer zur Einbindung eines Builds auf einem Mac führt. Letztlich ist es dennoch möglich, einen plattformübergreifenden CI-Prozess mit einem hohen Automatisierungsgrad zu erreichen – ohne dass die Entwickler die gewohnten Pfade von Visual Studio, TFS und C# verlassen müssen.

Xamarin hat sich in diesem Projekt als zuverlässige technologische Basis für die Entwicklung von Cross-Plattform-Mobile-Apps bewiesen. Xamarin verspricht einen Grad der Wiederverwendbarkeit des Sourcecodes, der bei 75 Prozent liegt. In beschriebenem Projekt wurde dieser Wert bestätigt und sogar leicht überschritten. Entwicklern mit C#-Know-how eröffnet sich somit die Möglichkeit, ihre Erfahrungen auf die iOS- und Android-Plattform anzuwenden.

Windows Developer

Windows DeveloperDieser Artikel ist im Windows Developer erschienen. Windows Developer informiert umfassend und herstellerneutral über neue Trends und Möglichkeiten der Software- und Systementwicklung rund um Microsoft-Technologien.

Natürlich können Sie den Windows Developer über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist der Windows Developer ferner im Abonnement oder als Einzelheft erhältlich.

Aufmacherbild: business people hand via Shutterstock.com / Urheberrecht: TCmakephoto

Unsere Redaktion empfiehlt:

Relevante Beiträge

X
- Gib Deinen Standort ein -
- or -