Zur nativen App mit Webtechnologien

App-Entwicklung mit JavaScript
Kommentare

In diesem Jahr feierte das iPhone seinen 7. Geburtstag. Apples Flaggschiff hat einen Stein ins Rollen gebracht, der noch lange nicht an Geschwindigkeit verloren hat. Jeder braucht Apps – und das ist auch für uns Webentwickler gut. Also greifen wir auf PhoneGap, Sencha Touch oder jQuery Mobile zurück. Dass es mithilfe von Titanium Mobile auch anders geht, möchte Ihnen dieser Artikel näher bringen.

Wenn man als Webentwickler vor die Aufgabe gestellt wird, eine Handy- oder Tablet-App zu programmieren, möchte man am liebsten seine vorhandenen Kenntnisse nutzen. Als Erstes wird man bei der Recherche auf PhoneGap und Apache Cordova stoßen. Diese Werkzeuge ermöglichen es, native Apps mithilfe von HTML, CSS und JavaScript zu programmieren. Hiermit ist die erste App schnell gebaut und auf dem eigenen Gerät installiert. Doch macht sich in vielen Fällen die erste Enttäuschung breit. „Native App“ bedeutet nun einmal leider nicht automatisch auch „native Performance“. Doch wie erreicht man mit Webtechnologien eine native Performance? Hier kommt Titanium Mobile ins Spiel.

Es geht auch ohne WebViews

Wie unterscheidet sich also Titanium Mobile von anderen Mobile-App-Frameworks? Grundsätzlich schreibt man Apps mit Titanium Mobile in JavaScript. Sowohl die Applikationslogik als auch das User Interface werden programmatisch in JavaScript erzeugt. Wird die App auf dem Gerät ausgeführt, wird der JavaScript-Code vom Titanium SDK zur Laufzeit interpretiert und durch native Proxy-Objekte ausgeführt. Das bedeutet zum Beispiel, dass ein Button unter Android und iOS jeweils seine native Java bzw. Objective-C-Komponente nutzt und nicht lediglich durch eine Webview mithilfe von HTML und CSS dargestellt wird. Dadurch kann trotz einer nativen Ausführung des Codes der Großteil an Quellcode für Android als auch iOS gleichermaßen genutzt werden. Zur Interpretation des JavaScript-Codes wird für iOS JavaScriptCore genutzt, Android greift auf Google’s V8 JavaScript Engine zurück.

Das SDK bietet neben den gängigen UI-Komponenten Zugriff auf so gut wie alle nativen iOS- und Android-Schnittstellen. Hierzu zählen unter anderem:

  • Native Mapviews
  • Kamera-API
  • Sound-API
  • Kalender-API
  • Beschleunigungssensor
  • SQLite-Datenbanken
  • NFC-API

Das Titanium Mobile SDK steht aktuell in der Version 3.3.0 zum kostenlosen Download bereit und ist zudem als Open-Source-Projekt unter der Apache-2-Lizenz bei GitHub zu finden.

Zusätzlich zum eigentlichen SDK kommt Titanium mit einer auf Eclipse basierenden IDE namens „Titanium Studio“ inklusive Debugger daher. Da Appcelerator, die Firma hinter Titanium, im Jahr 2011 Aptana aufgekauft hat, basiert Titanium Studio auf der Webentwicklungs-IDE Aptana. Die Nutzung von Titanium Mobile ist vollkommen kostenlos. Appcelerator rundet die Titanium-Plattform mit einer eigenen Cloud-Lösung namens „Appcelerator Cloud Services“ ab, welche entsprechend gut in das SDK integriert ist.

Meine erste eigene App

Dreh- und Angelpunkt von Titanium Mobile ist das JavaScript-API, mit dem die Brücke zwischen JavaScript- und nativem Code geschlagen wird. Diese gilt es also zunächst einmal zu beherrschen und zu verstehen. Glücklicherweise gibt Appcelerator den Entwicklern eine gute Dokumentation, ein hilfreiches Wiki und ein Q&A-System an die Hand. Doch auch ohne sich nun stundenlang mit dem API vertraut zu machen, ist es schnell und einfach möglich, eine erste eigene App zu schreiben.

Alle verfügbaren API-Methoden werden in einem globalen Objekt zur Verfügung gestellt. Dieses Objekt ist sowohl unter dem Namen „Titanium“ als auch in der Kurzform „Ti“ verfügbar (Listing 1).

 // Erzeugt ein "Window"-Objekt, welches als Grundlage nahezu aller Applikationen benötigt wird
var win = Titanium.UI.createWindow({
    backgroundColor: 'white'
});
// Auch über die Kurzform "Ti" ist das API aufrufbar
var label = Ti.UI.createLabel({
    text: "Hallo Welt"
});
// Setter, der nach der eigentlichen Initialisierung genutzt werden kann
label.color = "red";
// Bindet ein Click-Event auf das Label
label.addEventListener("click",function(e)
  {
    alert("Hallo! ");
});
// Fügt das Label als Kindelement in die View-Hierarchie
win.add( label );
// Öffnet die Applikation
win.open();

Ziemlich cool, oder? So kann man bereits nach wenig Einarbeitungszeit die ersten Ergebnisse hervorbringen und seine App-Ideen als Prototypen bauen. Durch JavaScript wird dem Webentwickler eine bekannte Programmiersprache an die Hand gegen – aber Vorsicht! Die Möglichkeit, komplexe Mobile-Applikationen „mal eben“ in JavaScript zu schreiben, kann einen Entwickler schnell dazu verleiten, Spaghetticode zu erzeugen.

Im Fall von Titanium ist das aus zweierlei Gründen kontraproduktiv. Der offensichtlichste Grund ist die erschwerte Wiederverwendbarkeit des Codes und der hohe Aufwand, den man benötigt, um sich in die App wieder einzuarbeiten, wenn erst einmal ein Spaghetticodekonstrukt entstanden ist.

Viel entscheidender ist allerdings das Thema Speicherverwaltung. Vor allem Webentwickler, die unter JavaScript lediglich „jQuery“ verstehen, sollten ihre Kenntnisse vor der Verwendung von Titanium auf Vordermann bringen. Jede globale Variable liegt im globalen Scope und belegt somit permanent Speicher, der auf mobilen Endgeräten eher rar gesät ist.

Um auf globale Variablen zu verzichten, empfiehlt es sich, die App in einer sich selbst ausführenden anonymen Funktion zu schreiben. Des Weiteren implementiert Titanium Mobile die CommonJS-Spezifikation, wodurch es möglich ist, kleinere Module zu programmieren, die losgelöst vom globalen Namensraum ausgeführt werden. Sehen wir uns also noch einmal unsere „Hallo Welt“-App in der CommonJS-Variante an (Listing 2 und 3).

 // Selbstausführende anonyme Funktion, die alleine im globalen Namensraum liegt
(function() {
    // Lade das "HelloWorldWindow" CommonJS Modul via require
    // CommonJS-Module werden ohne die Dateiendung JS geladen
    var Window = require(‘HelloWorldWindow');
    // Erzeuge ein neues "Window"-Objekt und öffne es
    new Window().open();
})();
 function HelloWorldWindow() {

  var self = Ti.UI.createWindow({
    backgroundColor: 'white'
  });
    
  var label = Ti.UI.createLabel({
    text: "Hallo Welt",
    color: "red"
  });
  label.addEventListener("click",function(e)
  {
    alert("Hallo!");
  });
  self.add( label );
  
  return self;
}

// Definiere die HelloWorldWindow-Funktion als Modul-API 
module.exports = HelloWorldWindow;

Wenn man es ganz sauber haben möchte, kann man die Generierung des Labels auch noch in einem eigenen Modul abhandeln, das Prinzip ist dabei dasselbe. Mit dieser Methode ist es also möglich, wesentlich saubereren, modularen Code zu schreiben, den man sich auch nach einiger Zeit ohne Kopfschmerzen erneut anschauen kann.

Eine Codebase – mehrere Plattformen

Unsere Hello-World-App läuft mit dem aktuellen Code bereits auf iOS, Android und BlackBerry-10-Geräten, sofern die entsprechenden SDKs vorhanden und installiert sind. Was aber, wenn wir für die unterschiedlichen Plattformen ein unterschiedliches User Interface wollen? Titanium bietet hierfür eine einfache Eigenschaft des Titanium.Platform-Objekts an (Listing 4).

 if( Ti.Platform.osname === "android" )
{
  // Meine Android-spezifische Anpassung
  alert("Hallo Android");
} 
if( Ti.Platform.osname === "blackberry" ) {
  alert("Hallo BB10");
}
if( Ti.platform.osname === "iphone" )
{
  alert("Hallo iPhone und iPod");
}
if( Ti.Platform.osname === "ipad" )
{
  alert("Hallo iPad");
}

Es bleibt nun dem Entwickler überlassen, ob er ein CommonJS-Modul pro Plattform erstellt, oder ob er die Änderung in das bestehende CommonJS-Modul integriert.

MVC mit Titanium – Hallo Alloy

Wenn eine App aus vielen unterschiedlichen UI-Elementen besteht, die je nach Plattform anders aussehen und sich anders verhalten, kann der Code ziemlich schnell unübersichtlich werden. Das liegt daran, dass sich UI-Elemente schnell mit Applikationslogik vermengen. Wäre es also nicht schön, wenn es ein Framework für Titanium geben würde, wie man es aus dem Web- und PHP-Bereich kennt, das einem die Trennung von Applikationslogik und User Interface erleichtert?

Genau für diesen Zweck wurde das MVC-Framework Alloy geschaffen. Es wird von Appcelerator bereits seit zwei Jahren entwickelt und vorangetrieben und findet sich ebenfalls als Open-Source-Software bei GitHub. Alloy hat viele coole Features an Bord. Dazu zählen unter anderem: Backbone.js Models, Underscore JS, XML Views und Alloy TSS – vergleichbar mit CSS für die UI-Gestaltung, Widget-Unterstützung, Themes und vieles mehr. Schauen wir uns also erneut unsere Hello-World-Applikation an, wenn wir sie mithilfe von Alloy schreiben (Listing 5, 6 und 7).

  
    <label id="label">Say My Name</label>
  
 function sayMyName(e) {
  alert( "Heisenberg" );
}
// $.index referenziert das erste Objekt der index.xml-Datei
// In unserem Fall das "Window"-Objekt
$.index.open();
 "Window": {
  backgroundColor: "white"
},
"Label": {
  color: "red"
},
// Auch plattformabhängige Queries sind möglich ...
"Label[platform=android]": { 
  color: "black"
},
// ... ebenso wie Abfragen auf den Formfaktor
"Label[formfactor=tablet]": { 
  color: "blue"
},
// Auch die CSS-Punktnotation ist möglich
".customclass": { 
  font: {
    fontWeight: "bold"
  }
},
// Oder Abfragen auf IDs
"#myID": { 
  borderRadius: 5
}

Mit Alloy ist es also noch einfacher, seine erste App zu schreiben. Durch die strikte Trennung von Model, View und Controller bleibt die Übersicht erhalten. Vor allem die XML-Views sind eine enorme Verbesserung gegenüber der herkömmlichen JavaScript-Variante, da man direkt eine strukturierte Version der View vor Augen hat.

Mithilfe von Alloy ist es außerdem möglich, in XML-Views sowohl plattformabhängige als auch formfaktorabhängige (Handheld oder Tablet) Abfragen zu machen (Listing 8).

 
  
    <label id="label_android">Android - Say My Name</label>
    <label id="label_tablet_ios">iOS Tablet - Say My Name</label>
    <label id="label_handheld_ios">iOS Handheld - Say My Name</label>
    
      <button>Damn right</button>
    

Je nachdem, wie viele plattformabhängige Viewelemente man in seiner App nutzen möchte, kann aber auch diese Herangehensweise unübersichtlich werden. Doch Alloy hat auch hier eine Lösung parat. Denn Alloy ist ganz auf das Prinzip „Eine Codebase – mehrere Plattformen“ ausgelegt. Möchte man also beispielsweise für Android eine eigene View erzeugen, muss man lediglich im views-Ordner einen Unterordner Namens android anlegen und kann dort seine Android-spezifischen Views ablegen. Dasselbe gilt natürlich auch für ios.

Diese Vorgehensweise ist nicht nur für XML-Views möglich, sondern kann auch für Styles und Controller genutzt werden.

Und wie funktioniert Alloy?

Lasse ich meine Hallo-Welt-Alloy-App nun im Simulator oder auf einem Gerät laufen, beginnt Alloy mit seiner Arbeit. Die XML- und TSS-Dateien werden von Alloy ausgelesen und geparst, um daraus den oben dargestellten herkömmlichen Titanium-Code zu erzeugen. Hierfür setzt Alloy auf Node.js. So entsteht am Ende – wenn man sich den generierten Code einmal anschaut – ein zusammengesetzter, generierter JavaScript-Code.

Den Vorteil des Parsens der Alloy-Dateien kann man sich zu nutzen machen. Gehen wir noch einmal auf die Titanium.Platform.osname-Abfrage im oberen Beispielcode ein. In der herkömmlichen Titanium-Entwicklung wird die IF-Abfrage, wie man sie sieht, mit in den Quellcode der App geschrieben und zur Laufzeit jedes Mal durchlaufen und abgefragt. Bei einer Abfrage bedeutet das noch keinen großen Performanceverlust – je mehr Abfragen aber in der App landen, umso mehr unnötiger Code muss innerhalb der App ausgeführt und verglichen werden. Mit Alloy kommen hierfür bestimmte reservierte Variablen innerhalb der Controller zum Einsatz (Listing 9).

 if( OS_ANDROID ) 
{
  // Meine Android-spezifische Anpassung
  alert("Hallo Android");
} 
if( OS_BLACKBERRY )
{
  alert("Hallo BB10");
}
if( OS_IOS ) {
  alert("Hallo iOS");
}

Das besondere an der angepassten if-Abfrage sind die Spezialvariablen OS_ANDROID, OS_IOS und OS_BLACKBERRY. Diese Variablen kann man sich als Compiler-Direktiven vorstellen.

Beim Parsen der App prüft Alloy auf das Vorkommen dieser besonderen Variablen und entfernt den nicht zutreffenden Code. In diesem Fall würde also in der Android-App nur das alert stehen, nicht aber die if-Abfrage selbst. Diese wird bei der Generierung der JavaScript-Dateien von Alloy komplett entfernt. Dadurch bleiben also auch komplexe Apps, die in verschiedenen Applikationen unterschiedlichen Code ausführen, performant.

Neben der Abfrage auf bestimmte Plattformen kann auch auf die aktuelle Umgebung geprüft werden. Das ist besonders praktisch, wenn man beispielsweise in der Testversion seiner App auf eine andere API-Schnittstelle zugreifen möchte, als in der Liveversion. Hierfür stehen die folgenden Variablen zur Verfügung:

  • ENV_DEV – Für Apps, die im Simulator/Emulator laufen
  • ENV_TEST – Für Apps, die auf einem Gerät zum Testen laufen
  • ENV_PRODUCTION – Für Apps, die zur Veröffentlichung heraus gespeichert wurden

Mit Alloy ist es also noch einfacher, in die Welt der nativen App-Entwicklung einzusteigen, als es mit Titanium Mobile ohnehin schon möglich ist. Doch je nachdem, wie komplex die App wird, kann es vorkommen, dass man bei Titanium Mobile irgendwann auch an die Grenzen des Frameworks stößt.

Wenn’s mal etwas mehr sein darf

Möchte man bestimmte Features des mobilen Betriebssystems seiner Wahl nutzen, die nicht vom Titanium-Framework abgedeckt werden, muss man Titanium erweitern. Das kann auf zwei verschiedene Arten geschehen. Die, aus Sicht des Entwicklers, einfachste Möglichkeit ist die Nutzung von bestehenden Modulen oder Alloy Widgets von Drittanbietern. Hierfür gibt es verschiedene Anlaufstellen:

  1. Appcelerator Marketplace: Der Marktplatz von Appcelerator steht allen Titanium-Entwicklern zur Verfügung. Hier werden sowohl kommerzielle als auch kostenlose/Open-Source-Inhalte angeboten. Als Entwickler hat man außerdem die Möglichkeit, eigene Inhalte zu verbreiten. Von eigenen Verkäufen behält Appcelerator 30 Prozent – die restlichen 70 Prozent gehen an den Entwickler. Hierbei stehen verschiedene Bezahlmodelle zur Verfügung (Einmalig, pro User, pro Monat, pro Jahr).
  2. gitt.io: Hierbei handelt es sich um ein Projekt, das aus der Titanium-Community entstanden ist. Es geht um eine automatisch indexierte Suchmaschine für GitHub, die mit einem Command Line Tool daher kommt, was einem die Installation der Module abnimmt. Sehr praktisch und definitiv einen Blick Wert.
  3. titaniumcontrols.com: Das ist mein persönliches Projekt und entstand gedanklich als Titanium-Pendant zur bekannten Seite CocoaControls, die hauptsächlich iOS User Interface Libraries auflistet. So findet man bei TitaniumControls eine handverlesene Übersicht von Titanium-Modulen, die das User Interface der eigenen App erweitern.

Findet man bei diesen Anlaufstellen nicht das richtige für die eigene App, bleibt zu guter Letzt noch die Möglichkeit, ein eigenes Titanium-Modul zu entwickeln. Die Module werden hierbei in Objective-C bzw. Java geschrieben und müssen vorgegebenen Richtlinien entsprechen, um über den JavaScript-Code ausgeführt werden und Rückgaben an JavaScript geben zu können. Unterstützung und Inspiration bei der Entwicklung eigener Module findet man sowohl im offiziellen Appcelerator-Wiki, als auch in den vielen GitHub Repositories zu diesem Thema.

Der Heilige Gral der App-Entwicklung?

Titanium macht es möglich, sehr schnell in der nativen App-Entwicklung Erfolg zu haben und einen Einstieg zu finden. Bevor das nächste App-Projekt ansteht, sollte man auf jeden Fall einen Blick auf die Möglichkeiten des SDKs werfen, um abwägen zu können, ob sich der Einsatz des Frameworks lohnt, erst recht, wenn man plant, die App auf mehreren Plattformen zu veröffentlichen.

Aber auch Titanium hat seine Einschränkungen. Dadurch, dass der JavaScript-Code zur Laufzeit ausgeführt wird, macht sich das, je nach Aufgabenbereich, irgendwann bemerkbar. Plant man beispielsweise eine Mandelbrot-Menge in seiner App zu erzeugen, kann ich von dem Einsatz von Titanium nur abraten. Außerdem sollte man sich vor Beginn des neuen Projekts einen Überblick darüber verschaffen, ob alle benötigten Module/Drittanbieter-Plug-ins für Titanium zur Verfügung stehen, oder ob man hierbei auf eigene Modulentwicklung angewiesen ist.

Titanium ist nicht der Heilige Gral, sollte jedoch in keinem Werkzeugkoffer eines App-Entwicklers fehlen.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -