NativeScript & Angular 2: Native Apps in JavaScript
In unserem ersten Artikel haben wir Ihnen die Neuerungen ab Angular 2 nähergebracht und einen Überblick über neue, weggefallene und überarbeitete Konzepte geben. Hierbei sind wir kurz auf die Möglichkeit eingegangen, mit einem alternativen Renderer auch andere Plattformen als den Browser zu bedienen. NativeScript verwendet solch einen alternativen Renderer, um aus einer Angular 2-Anwendung eine native App für mobile Plattformen zu erzeugen.
Im folgenden möchten wir Ihnen erläutern, was NativeScript ist, wie es sich von anderen Möglichkeiten der App-Entwicklung abgrenzt und wie man es mit Angular 2 einsetzen kann. Die Codebeispiele sind alle in TypeScript gehalten, die Funktionalität steht natürlich auch in JavaScript zur Verfügung.
Was ist NativeScript?
NativeScript ist ein Open Source-Framework von Progress Telerik, mit dem native Apps für Android und iOS in JavaScript geschrieben werden können. Die erste offizielle Version gibt es seit Mai 2015. Ende Januar 2017 ist nun die Version 2.5 mit vielen Neuerungen erschienen. NativeScript ist für Android ab Version 4.2 und iOS ab Version 8 verfügbar, seit Version 2.0 wird auch Angular 2 im vollem Umfang unterstützt. NativeScript steht unter der Apache-Lizenz Version 2 zur Verfügung.
Wie aus der Webentwicklung gewohnt, wird eine App dabei in JavaScript oder Typescript geschrieben. Die UI wird aus einem XML Template aufgebaut und gestylt, genauso wie im Browser mit CSS. Diese Ansätze gab es schon früher bei hybriden Apps, die mit PhoneGap/ Cordova entwickelt wurden. Jedoch gibt es hier einen bedeutenden Unterschied: Bei hybriden Apps wird die App auf dem Smartphone im mitgelieferten Browser (z. B. der Chrome WebView ab Android 4) ausgeführt. Die App wird im Browser gerendert und folgt den Regeln einer Webanwendung.
Bei NativeScript hingegen wird kein Browser/ WebView verwendet, um die App auf dem mobilen Gerät darzustellen. NativeScript führt zwar den JavaScript-Code aus, erzeugt jedoch zur Laufzeit Widgets der nativen Plattform.
Durch diesen nativen Ansatz ergeben sich die folgenden Vorteile:
Native Darstellung
Es gibt eine Schnittmenge von UI-Komponenten, die auf den Zielplattformen dargestellt werden können. Diese Komponenten werden nativ gerendert und sehen für den Benutzer aus, wie von anderen nativen Apps gewohnt. In der Regel ist die native Darstellung deutlich performanter als das Rendering im Browser und benötigt zudem weniger Ressourcen.
Benutzerführung
Anders als in einem WebView kann durch eine native App eine plattformspezifische Benutzerführung gewährleistet werden, bei Android befindet sich der Zurück-Button z. B. unten in einer extra Leiste, bei iOS Apps oben in einer Leiste. In einem Browser lässt sich dies oft nicht vereinen.
Plattform-Zugriff ohne Kapselung
Da die App nativ auf den Endgeräten läuft, kann direkt auf die Plattform zugegriffen werden. Aus JavaScript-Code können so direkt native Komponenten instanziiert oder manipuliert werden. Falls ein Feature nur in Android, aber nicht in iOS verfügbar ist, kann es trotzdem direkt aus JavaScript/TypeScript genutzt werden
import * as application from "application"; if (application.ios) {// do iOS specific stuff} if (application.android) {// do Android specific stuff}
Für Zugriffe auf das Filesystem oder die Kamera gibt es direkt Plugins von NativeScript, diese abstrahieren die plattformspezifischen Details für den Entwickler. Plugins können auch von Entwicklern oder der Community selbst geschrieben und geteilt werden. Hierfür betreibt NativeScript einen eigenen Marketplace [2].
Durch den direkten Zugriff auf das darunterliegende System gibt es von NativeScript einen Zero Day-Support für neue Android-/ iOS-Versionen. Neue Features können direkt am ersten Tag aus JavaScript genutzt werden.
Im Grunde besteht eine App aus drei Teilen: der Logik, dem Template und dem Styling. Im Folgenden werden wir auf jeden dieser Teile eingehen.
Logik: JavaScript / TypeScript
Wie oben beschrieben werden Apps in JavaScript, respektive TypeScript, geschrieben. Um diesen auszuführen, startet NativeScript zur Laufzeit eine JavaScript-Umgebung, welche den mitgelieferten Code ausführt. Eine App könnte rein in JavaScript geschrieben werden. Aus JavaScript können UI-Komponenten instanziiert und so eine komplette Oberfläche aufgebaut werden. Dies ist vergleichbar mit dem Aufbau einer Oberfläche mit Java Swing.
import {Button} from "ui/button"; var button = new Button(); button.text = "Lieber Leser";
Wie in Webanwendungen üblich, wird aber meist nur die Logik in JavaScript geschrieben und das UI in ein Template ausgelagert. Beide werden dann per Data-Binding synchronisiert. Da die App in JavaScript geschrieben ist und NativeScript auf Node aufbaut, können alle Node-Plugins, die nicht auf Browser-Funktionen zurückgreifen, genutzt werden. Diese können wie gewohnt per npm installiert werden.
Angular
Wird eine App mit Angular geschrieben, wird auch die Verwendung von TypeScript empfohlen. Mit der NativeScript CLI kann mittels tns create MeineApp --ng eine initiale Angular-App aufgesetzt werden. Diese enthält schon das erforderliche Bootstrapping für eine NativeScript-App.
Damit die Angular-Bibliotheken wie Router, die Forms oder das Http-Module in NativeScript wie gewohnt funktionieren, gibt es auch hier eigene Implementierungen für die mobilen Plattformen. Diese können wie von Angular gewohnt verwendet werden und finden sich in den node_modules/nativescript_angular/[3].
import { NativeScriptRouterModule } from "nativescript-angular/router"; import { NativeScriptHttpModule } from "nativescript-angular/http"; import { NativeScriptFormsModule } from "nativescript-angular/forms";
Ist die App erst einmal aufgesetzt, können Angular-Module, -Components und -Services geschrieben und verwendet werden. Templates und Styles können dann, wie von Angular gewohnt, direkt in der Komponenten geschrieben oder referenziert werden.
UI-Template: XML
Wie im Browser ist es in NativeScript möglich, die Oberfläche der App in XML zu schreiben. Da die IDEs häufiger besser mit HTML-Dateien umgehen können, haben diese die Endung *.html. Wie in anderen Frameworks besteht eine UI aus verschiedenen Layouts und darin enthaltenen UI-Komponenten (Labels, Buttons, ...). Auch in NativeScript sind UIs so aufgebaut.
Ein einfaches Beispiel:
<ActionBar title="Template" class="action-bar"></ActionBar> <StackLayout class="page"> <Label text="Hallo Welt" class="h1 m-x-auto"></Label> <Button text="Button" class="btn-primary m-x-30"></Button> </StackLayout>
Hier wird ein einfaches StackLayout verwendet, das alle Elemente untereinander darstellt, um ein Label und einen Button anzuzeigen. Auf die "class"-Attribute werden wir später beim Styling eingehen.
NativeScript bietet aktuell die folgenden sechs Layouts [4]:
- AbsoluteLayout: Alle Elemente in einem AbsoluteLayout können explizit mit x- und y-Koordinaten gesetzt werden.
- DockLayout: Erlaubt das Platzieren von Elementen links, rechts, oben oder unten im Layout. Dies könnte zum Beispiel für eine Statusleiste am oberen oder unteren Rand der App verwendet werden.
- GridLayout: Erlaubt das Platzieren von Elementen in Zeilen und Spalten, das Layout wird mit einer Zeilen- und Spaltenanzahl initialisiert. Die Elemente bekommen dann per Attribute die jeweilige Zeile und Spalte zugewiesen.
- StackLayout: Im StackLayout werden alle Elemente vertikal oder horizontal aufgelistet.
- WrapLayout: Das WrapLayout ähnelt dem StackLayout, jedoch bricht es die Elemente um, sobald diese nicht mehr in eine Zeile oder Spalte passen. Dazu kann eine Breite und Höhe angegeben werden.
- FlexBoxLayout: Dieses Layout wurde mit NativeScript 2.4 aufgenommen, es erlaubt ein Layout mit FlexBox [5], wie es aus dem Browser bekannt ist. Die Umsetzung ist etwas komplexer, jedoch lassen sich hiermit einfacher UIs für unterschiedliche Bildschirmgrößen bauen.
Neben den Layouts bietet NativeScript 19 Komponenten, die eine Schnittmenge der UI-Komponenten zwischen Android und iOS darstellen. Dazu gehören: Button, Label, TextField, Slider, ListView, Dialogs, … eine komplette Auflistung mit Screenshots kann unter [6] eingesehen werden. Plattformspezifische Attribute der Elemente können über den JavaScript-Code aufgerufen werden, falls dies nötig ist.
Achtung: Es sind keine selbstschließenden Tags im Template erlaubt, <Button /> funktioniert also nicht.
Angular
In Angular lassen sich die Templates auch in NativeScript direkt in der Component einfügen oder eine Template-Datei referenzieren. Das Databinding erfolgt wie bei Angular durch runde und eckige Klammern, dabei ist zu beachten, dass bei NativeScript-Elementen die Werte über Attribute gesetzt werden. In Angular & HTML ist so ein <button (click)=”buttonClick()” /> gültig, in NativeScript wird daraus ein <button (tap)=”buttonClick()”></button>. Dies ist zu beachten, falls Layouts 1:1 aus dem HTML übernommen werden. Ein einfaches Databinding mit einem Button würde wie folgt aussehen:
import { Component } from "@angular/core"; @Component({ selector: "btn-component", template: ` <Button [text]="buttonLabel" (tap)="buttonIsTapped()"> </Button> `, }) export class ButtonComponent { private buttonLabel = "Test"; buttonIsTapped() { console.log("Button is clicked"); } }
Auch Direktiven wie ngIf oder ngFor können im Template ohne Probleme verwendet werden.
Eine kleine Ausnahme stellt die Direktive RouterOutlet (<router-outlet></router-outlet>) aus Angular da. Da es in einer App keinen Zurückknopf wie im Browser gibt, gibt es in NativeScript eine eigene Direktive, diese nennt sich PageRouterOutlet (<page-router-outlet></page-router-outlet>). Die PageRouterOutlet-Direktive bildet die Zurück-Funktionalitäten der mobilen Plattformen ab und sorgt dafür, dass auch hier eine korrekte Navigation gewährleistet wird.
Styling: CSS
Wie jede Webanwendung lassen sich auch NativeScript-Apps mit CSS stylen [7], dazu gibt es folgende Möglichkeiten:
- Ein Stylesheet gültig für die ganze Anwendung: app.css
- ein Stylesheet gültig für die jeweilige Plattform: app.android.css | app.ios.css
- ein Stylesheet pro Template (Angular spezifisch)
- Inline-Styling
Die CSS-Selektoren sind dieselben wie im Browser, jedoch gibt es nur ein eingeschränktes Set an Attributen [8] die unterstützt werden. Zu beachten ist, dass es keine Einheiten wie px, em, … gibt.
// Template <Button class="square-button"></Button> // Styling .square-button { font-size: 48; background-color: #FFEFD4; border-radius: 0; border-color: black; border-width: 1; }
Mit NativeScript 2.4 wurde ein allgemein gültiges Theme für NativeScript geschaffen, dieses beinhaltet, ähnlich wie Bootstrap [9], Styling und ein Farbschema für alle Elemente. Das Theme ist standardmäßig installiert und in Sass geschrieben. Es erlaubt also die Anpassung und Erweiterung durch den Entwickler. Mit dem NativeScript Theme Builder [10] kann ein eigenes Farbschema erstellt werden, dabei können für alle UI-Komponenten eigene Anpassungen vorgenommen werden. Die Änderungen werden sofort dargestellt.
Stylesheets lassen sich mit dem passenden Plugin für NativeScript in Sass und Less schreiben.
Angular
Trotz dem Theme, das standardmäßig zur Verfügung steht, können in einer Component über styleUrl:[] eigene Styles geladen und im Template verwendet werden. Die View Encapsulation funktioniert auch in NativeScript, so werden die Styles einer Komponente, wie von Angular gewohnt, auch nur für das Template der Komponente angewendet.
Tooling
NativeScript bietet wie Angular ein CLI um Projekte von der Kommandozeile aus zu erstellen und die App in einem Emulator oder auf einem echten Gerät auszuführen und zu testen. Des Weiteren können fertige Releases damit gebaut und als App für Android oder iOS gepackt werden.
Für das CLI wird Node und der Paketmanager npm benötigt, installiert wird es dann mit dem Befehl npm install -g nativescript. Weitere Informationen für das Aufsetzen der Umgebung finden sie unter [11]. Das Paket stellt das Kommandozeilen Tool tns zur Verfügung.
Für Entwickler stehen dann unter Anderem folgende nützlichen Befehle zur Verfügung:
- tns create {AppName} [--ng]: Hiermit wird eine NativeScript-App initial angelegt, der optionale Parameter --ng sorgt für das Generieren einer App auf Basis von Angular und TypeScript.
- tns run {android | ios}: Mit diesem Befehl kann die App zur Entwicklungszeit auf Android oder iOS (nur unter Mac OS X) gestartet werden. Falls kein Gerät angeschlossen ist, wird ein vorhandener Emulator gestartet. Der Befehl ruft seit NativeScript 2.5 automatisch die Hot Reload- und Live Sync-Funktionalität auf (früher über tns livesync {android|ios} --watch). D. h. Style-Änderungen werden meist ohne Reload der App, Layout-Änderungen direkt mit einem automatischen Rebuild und Reload der App angezeigt.
- tns debug {android | ios --chrome}[12]: Dieser Befehl bewirkt das gleiche wie tns run, jedoch wird zusätzlich ein Debug-Port geöffnet. Falls der Befehl nicht durch das Visual Studio Code-Plugin ausgeführt wurde, wird am Ende des Builds in der Kommandozeile eine URL für Chrome angezeigt. Mit dieser URL kann die App mit den Chrome DevTools gedebuggt werden. Als Alternative bietet sich das Visual Studio Code-Plugin von NativeScript an, dieses besitzt die gleichen Debugging Features.
- tns test {init | android | ios} [13]: In NativeScript können mit verschiedenen Testing Frameworks Unit-Tests geschrieben werden, diese werden mit diesem Befehl ausgeführt.
Eine vollständige Liste der möglichen Befehle erhält man, in dem man tns ohne Parameter im Terminal ausführt.
Wie oben schon erwähnt, gibt es ein Plugin [14] für Visual Studio Code, mit diesem wird Debugging und Starten der Anwendung stark vereinfacht.
Angular
Für die CLI spielt es keine Rolle, ob die App mit TypeScript und Angular oder in JavaScript geschrieben ist. Nach dem Anlegen eines Projekts mit der CLI sind die nötigen Abhängigkeiten schon installiert und eingerichtet. Für den Bau einer finalen Anwendung empfiehlt sich das Node Plugin nativescript-dev-webpack [15], dieses nimmt weitere Optimierungen, z. B. eine AOT-Kompilierung, vor.
Ausblick und Fazit
NativeScript hat sich ab Version 2 zu einem starken Konkurrenten für Ionic oder React Native gemausert. Durch die Verwendung von Angular können Services und teilweise Komponenten aus Webanwendungen übernommen und in einer nativen App mit einer nativen Benutzerführung genutzt werden.
Der Artikel hat eine Übersicht über NativeScript und Angular gegeben, für einen weiteren Einstieg in das Thema ist die Dokumentation [16] und das Tutorial [17] für NativeScript sehr zu empfehlen. Darüber hinaus kann NativeScript auch in bestehende Apps integriert werden und bietet eine Unterstützung für verschiedene Displaygrößen. Des Weiteren wird von Telerik eine eigene, teils kostenpflichtige, UI-Erweiterung für NativeScript angeboten, um auch ein Seitenmenü, Listen und Graphen auf beiden unterstützten Plattformen anzuzeigen. Für Mitte April wurde schon NativeScript Version 3 angekündigt, die noch einmal eine deutliche Steigerung der Leistung mitbringen soll.
- Components Button
- NativeScript
- Implementierungen für die mobilen Plattformen
- FlexBox
- NativeScript-Komponenten
- NativeScript-Apps mit CSS stylen
- Set an Attributen
- Bootstrap
- NativeScript Theme Builder
- Aufsetzen der Umgebung
- Debugging
- Testing
- Visual Studio Code-Plugin
- Node Plugin nativescript-dev-webpack & bundling-with-webpack
- Dokumentation
- Tutorial