iX 7/2017
S. 104
Praxis
Portable Apps
Aufmacherbild

Mobile Entwicklung mit NativeScript

Ein Teig, zwei Kekse

Wer dieselben Apps für Android und iOS anbieten will, muss speziellen Code für die jeweilige Plattform schreiben. Oder sich für ein neutrales Framework wie das freie NativeScript entscheiden, das auf Webtechniken setzt.

Native Apps haben einige entscheidende Vorteile gegenüber mobilen Webseiten. Die wichtigsten Teile wie häufig benötigte Medien und das Grundgerüst befinden sich bereits auf dem Endgerät, was die Ladezeit deutlich verkürzt. Außerdem lassen sich native Apps über die Stores der Hersteller vertreiben. Benutzer kennen die Bedienelemente einer nativen App schon von ihrem Mobilgerät. Auch der Zugriff auf die Hardware, etwa Sensoren, Kamera oder das Dateisystem, ist aus einer nativen App heraus einfach. Eine große Hürde bildet allerdings, dass Apps für iOS in Objective-C oder Swift und für Android in Java oder Kotlin entwickelt werden. Was wäre also naheliegender, als die Vorteile der Webentwicklung mit HTML, CSS und JavaScript mit denen der nativen Entwicklung zu verbinden, wie es das freie Framework NativeScript tut? Dieser Artikel verdeutlicht an einem Beispiel die Arbeit damit.

NativeScript setzt auf eine klare Trennung zwischen den Funktionen (JavaScript), dem Styling (CSS) und der Struktur (XML). Sein Kommandozeilenwerkzeug erzeugt aus diesen Komponenten eine native App für iOS oder Android. NativeScript verwendet das native UI des Systems und nutzt dafür keine HTML-, sondern eigene XML-Elemente. Die in JavaScript geschriebenen Funktionen der App übersetzt NativeScript nicht in Objective-C oder Java, sondern führt sie in einer Virtual Machine aus. Bei iOS ist das die JavaScriptCore VM, bei Android die V8-Engine.

Native Funktionen in iOS und Android

Neben der JavaScript-VM sind weitere Hilfsmittel nötig, um den Abstand zu Objective-C und Java zu überwinden. Für iOS stellt NativeScript beispielsweise JavaScript-Repräsentationen der Objective-C-Klassen zur Verfügung, die direkten Zugriff auf native Funktionen erlauben. Diese Klassen kapseln den Zugriff auf das System und spielen quasi Man in the Middle. Für Android erlaubt der Dynamic Class Generator Vererbung sowie das Implementieren von Interfaces und erzeugt die erforderlichen Java-Klassen. NativeScript-eigene Metadaten regeln den Zugriff auf die Android- und iOS-Schnittstellen. Für dieses Verfahren (und gegen etwa die Java-Reflection-API) sprechen Performance- und Speichergründe.

Als Entwicklungsplattform unterstützt NativeScript Windows, macOS und Linux. Um allerdings iOS-Apps zu erzeugen, braucht man Apples IDE Xcode, die es nur für macOS gibt. Folglich lassen sich Android-Apps auf allen genannten Systemen bauen, iOS-Anwendungen nur auf Apple-Rechnern. Als Ausweg bietet Telerik, der Hersteller von NativeScript, seinen kostenpflichtigen Cloud-Dienst Telerik Platform an, der Apps für beide Mobilsysteme produziert.

Die Entwicklungsumgebung einrichten

Zwingende Voraussetzung zum Entwickeln mit NativeScript ist eine lokale Installation von Node.js, auf dem das Kommandozeilenwerkzeug aufsetzt. Man installiert es mit npm install g native script global auf dem lokalen System und verwendet es mit dem Befehl tns auf der Kommandozeile.

Das Kommandozeilenprogramm ist lediglich ein Hilfsmittel, zum Bauen der Apps muss man zunächst die Entwicklungsumgebung für Android und iOS einrichten. Dazu gibt es für Windows und macOS online Kommandozeilenskripte (siehe „Alle Links“, [a]), die alles erledigen. Im Verlauf der Installation richten sie beispielsweise das JDK und das SDK für Android ein und konfigurieren den Emulator. Letzterer spielt eine entscheidende Rolle, denn anders als bei der herkömmlichen Webentwicklung lässt sich eine NativeScript-App nicht im Browser betrachten. Stattdessen baut man sie und und lädt sie in den Emulator. Im letzten Schritt der Installation führt tns doctor eine Systemdiagnose durch, um sicherzustellen, dass alle benötigten Komponenten korrekt installiert und aktuell sind.

Nach der Installation erzeugt man mit tns die Grundstruktur der App. Dieser als „Scaffolding“ bezeichnete Prozess etabliert sich in letzter Zeit mehr und mehr in der JavaScript-Welt. Das erledigt hier der Befehl tns create <Projekt>. Das Kommando erzeugt ein Verzeichnis mit dem Namen des Projekts und darin eine initiale Struktur. Sie besteht in der ersten Ebene aus den Verzeichnissen hooks, node_modules, platforms und app. Die ebenfalls erzeugte Datei package.json enthält die Konfiguration des Projekts inklusive der Liste der benötigten Pakete. In hooks liegen Skripte, die das NativeScript-Werkzeug in bestimmten Situationen ausführt. So lässt etwa tns prepare die Skripte in den Verzeichnissen before -prepare und after-prepare laufen. node _modules nimmt die in der App benutzten NPM-Pakete auf; einige davon installiert tns bereits automatisch.

Vorlagen für mobile Apps nutzen

Bevor eine App laufen kann, muss man sie für die Zielplattform bauen. Die dafür benötigten Dateien legt das Framework in platforms ab. Im Normalfall hat ein Entwickler mit dem Inhalt dieses Verzeichnisses nichts zu tun. Ganz anders sieht es mit app aus, denn hier entsteht der Quellcode der App. tns legt nicht nur die erwähnten Verzeichnisse an, sondern erzeugt bereits alles, was für eine rudimentäre funktionsfähige App erforderlich ist. Deren Struktur gibt ein App-Template vor, standardmäßig tns-template-hello -world. Es erzeugt eine einfache App mit einem Knopf, der nach dem 42. Anklicken das Programm beendet. Die Option --template legt das zu verwendende Template fest. Online stehen einige vorgefertigte Templates unter anderem für Angular und TypeScript bereit [b].

Ist die App erzeugt, kann man sie bauen und starten. tns run <Plattform> erstellt aus dem Quellcode ein Paket für die angegebene Plattform und startet den zuständigen Emulator. Der Platzhalter kann den Wert ios oder android annehmen. Da dieser Aufruf nicht terminiert, kann tns gewährleisten, dass die App bei jeder Änderung der Projektdateien automatisch neu gebaut und geladen wird.

Zum besseren Verständnis der Zusammenhänge folgt eine kleine Beispiel-App, die eine Liste von Aufgaben anzeigt. Ein Tap auf einen Listeneintrag verändert dessen Status. Außerdem soll der Benutzer neue Aufgaben eintragen können. Zunächst legt tns create taskList die Struktur des Projekts an. Während der Entwicklung sollte sich tns im run-Modus befinden. Der Emulator ist dann geöffnet und sämtliche Änderungen an der App erscheinen dort sofort.