Neuigkeiten von trion.
Immer gut informiert.

Rapid Prototyping mit React Native

Wie macht man mobile Entwicklung heute?
Häufig ist die Antwort hierfür ein Cross-Platform Framework. Insbesondere für Rapid Prototyping sollte der initiale Entwicklungsaufwand möglichst begrenzt sein. Wenn gleichzeitig auch die langfristigen Wartungskosten reduziert werden können, lassen sich diese Prototypen im nächsten Schritt gleich in vollständige Anwendungen umbauen. Es ist möglich, beispielsweise für eine Messe oder als Proof of Concept mit sehr geringem Aufwand und beschränktem Plattformwissen mobile Anwendungen zu launchen, ohne dabei allzu viel Zeit zu verschwenden.

React Native [3] hat sich hierbei als eines der populärsten Frameworks für derartige Anwendungsfälle herausgetan [1] [2]. Die Gründe dafür sowie eine kurze Einführung in die Konzepte inklusive einer Basis-Anwendung, die als Grundgerüst für die eigenen React-Native-Aspirationen dient, sind in diesem Artikel zu lesen.

Warum React Native?

Bevor mach sich für React Native statt einer anderen Technologie entscheidet, sollte verstanden werden was React Native ausmacht und was Alternative wären.

React Native gehört zur Kategorie der nativen Anwendungen und der Unterkategorie Cross-Platform-Frameworks (siehe Abbildung 1).

Abbildung 1. Einordnung von React Native in die Hierarchie mobiler Anwendungen.

Native Anwendungen stehen im Kontrast zu Progressive Web Apps und laufen direkt auf dem Gerät anstatt im Web Browser. Dies hat einige Vorzüge. So können beispielsweise unter iOS aus dem Browser nach wie vor keine Push-Benachrichtigungen versandt werden. Auch Hintergrundprozesse sind von einer Progressive Web App aus dem Browser heraus sowohl unter Android als auch unter iOS nicht möglich. Auch die Speicherung von größeren Datenmengen (zurzeit 50MB bei iOS) zur Offlineverarbeitung ist in Progressive Web Apps nicht möglich. [4]

Die Welt der nativen Anwendungen teilt sich in vollnative Anwendungen und Cross-Platform-Frameworks. Bei einem Cross-Platform-Framework kann sowohl die Android- als auch die iOS Anwendung aus der gleichen Quellcodebasis erstellt werden. Diametral gegenüber gibt es die vollnativen Anwendungen, die etwa für Android mit Java oder C und bei iOS früher mit Objective-C und heute meist mit Swift direkt gegen die Platform-API des jeweiligen Systems programmiert werden.

Cross Platform Frameworks

Eine Cross-Platform-Anwendung soll dabei wie oben schon genannt Entwicklungsaufwand und langfristige Wartungskosten reduzieren, während eine vollnative Anwendung besser auf die Anforderungen des jeweiligen Betriebssystems zugeschnitten werden kann.

In der Praxis ist insbesondere die Menge der Androidtelefonen keine homogene Masse. Es gibt inzwischen eine riesige Fülle an herstellerspezifischen Funktionen und Eigenheiten in stark herstellerabhängig konfigurierten Androidversionen auf den Mobiltelefonen und Tablets der unterschiedlichen Hersteller. Dies führt dazu, dass das oben genannte konkrete Zuschneiden auf das Betriebssystem häufig nur auf dem kleinsten gemeinsamen Nenner funktioniert und keineswegs alles so standardisiert ist, wie initial erwartet.

Wenn man sich nun also dafür entschieden hat, eine spezifische App mit einem Cross-Platform-Framework zu entwickeln, gibt es neben React Native noch weitere Frameworks mit teils großer Beliebtheit, wie etwa Ionic, Flutter, NativeScript oder Xamarin. Hier ergibt sich gleich die erste Kategorisierung: Programmiersprache des Quellcodes.

Wahl der Programmiersprache

Während React Native-, Ionic- und NativeScript-Anwendungen mit JavaScript oder TypeScript entwickelt werden, wird bei Flutter die Sprache Dart und bei Xamarin C# auf .NET-Basis verwendet. Im Vergleich zu Dart und C# haben JavaScript und TypeScript mit Abstand die höchste Popularität [1] [2], weswegen es allgemein mehr Inhalte dazu zu finden gibt (siehe Abbildung 2).

Abbildung 2. Google Trends für die Programmiersprachen JavaScript(blau), C#(rot), TypeScript(gelb) und Dart(grün).

Somit bleiben zum direkten Vergleich mit React Native noch Ionic und NativeScript. Von den dreien hat React-Native die höchste Popularität auf GitHub, Stackoverflow und Hackernews, gefolgt von Ionic. Schlusslicht ist NativeScript

React Native vs. Ionic vs. NativeScript

Ionic verwendet statt nativer UI-Elemente eine WebView und setzt Apache Cordova für den nativen Hardwarezugriff ein. Darunter leidet in der Praxis die Performance ein wenig. Komplexe UIs wie 3D-Modelle oder Spiele sind mit Ionic nur schwierig umsetzbar.

NativeScript gibt die gesamte API der entsprechenden nativen Plattform frei und erlaubt damit eine noch engmaschigere Integration mit dem Betriebssystem. Dafür ist die Community etwas kleiner was in weniger Beispielen und Problemlösungen auf Stackoverflow resultiert.

React Native sticht durch seine gute Performance dank Virtual DOM und der geringen Einstiegshürde für neue Entwickler hervor. Dabei hilft auch die Hot-Reloading Funktionalität, dank der die Iterationszeit massiv verkürzt werden kann. Wie auch bei React (nicht-native), können hier Änderungen am Quellcode direkt in der Anwendung reflektiert werden; Es ist keine erneute vollständige Kompilation und Installation erforderlich. Ein einfaches Speichern der angepassten Datei genügt. Des Weiteren ist React Native recht leichtgewichtig. Kontrapunkt davon ist, dass selbst für einfache Anwendungen unter Umständen bereits weitere Bibliotheken eingebunden werden müssen.

Hier die genannten und weitere Erkenntnisse einmal tabellarisch zusammengefasst:

Tabelle 1. Tabellarischer Vergleich der Frameworks
Framework Pro Con

React Native

performant

leicht zu lernen

rapide Entwicklung

ressourcenintensiver

Ionic

partieller nativer API-Zugriff über Plugins

langsam

ungeeignet für komplexe UI

NativeScript

gesamte native API verfügbar

einfache Integration mit Angular2 oder Vue

schnelles Reloading dank LiveSync

kleinere Community und weniger Content

Wie sieht das ganze nun in der Praxis aus?

Besonders gut sieht es aus für React-Entwickler. Diese werden vermutlich in den Codebeispielen einiges wiedererkennen. Die Codebeispiele sind übrigens auch online verfügbar [8] und mit Git verwaltet. So kann jeweils der zum aktuellen Kapitel passende Commit ausgecheckt werden.

Beginnen wir mit dem Setup der Entwicklungsumgebung.

Setup der Entwicklungsumgebung und erste Anwendung

  1. Für die lokale Entwicklung mit React Native und Typescript wird zunächst einmal NodeJS und NPM benötigt. NodeJS kann auf der offiziellen Seite [5] als Archiv heruntergeladen werden. Nach dem Herunterladen sollte der bin-Ordner zum PATH oder zu den Benutzerumgebungsvariablen (Windows) hinzugefügt werden.

  2. Für die Initialisierung einer neuen Projekt-App wird das create-react-native-app Package benötigt. Es kann via Node mit dem Befehl npm install -g create-react-native-app installiert werden.

  3. Nun kann ein neues Projekt mittels npx create-react-native-app <app-name> --template typescript initialisiert werden. Dadurch wird ein neues App-Projekt mit einfacher Konfiguration und einer Testseite sowie Typescriptunterstützung angelegt.

  4. Um die Integration mit einem Gerät oder Emulator zu erleichern, sollte außerdem das React Native Command Line Interface mittels npm install -g react-native-cli installiert werden.

  5. Als Emulator für ein Android-Smartphone verwenden wir für diesen Artikel die virtuellen Geräte vom AVD-Manager in Android Studio [6]. Wer unter Windows unterwegs ist und Hyper-V aktiviert hat, sollte dieses abschalten. Wie man einen Android-Emulator unter Windows mit Hyper-V zum Laufen bringt ist sicherlich ein interessantes Thema, sprengt aber den Rahmen dieses Artikels. Bei Intelsystemen wird statt Hyper-V standardmäßig HAXM verwendet. Nicht vergessen, die beiden Verzeichnisse <android-sdk>/emulator und <android-sdk>/tools auf den PATH hinzuzufügen und ADB [7] zu installieren und ebenfalls zum PATH hinzuzufügen.

  6. Um die frisch erzeugte Test-Anwendung zu bauen und auf dem Android-Emulator zu starten, wird im Projektverzeichnis (Das Verzeichnis mit der App.tsx) der Befehl npx react-native run-android ausgeführt.

Anschließend sollte sich neben einigen Command-Line-Fenstern der Androidemulator öffnen, auf dem dann die soeben erstellte Anwendung installiert und gestartet wird, sobald alles fertig gebaut ist.

Abbildung 3. Android Emulator mit frisch installierter und gestarteter Anwendung.

Aber was wurde da jetzt genau ausgeführt?

Die erste React-App

Nach einem kurzen Blick in das vom Befehl in Schritt 4 neu erstellten Verzeichnisses sehen wir einige Dateien und Ordner:

ShowcaseApp/
├── android/: Quellcode und Buildconfig für die native Android-App.
├── ios/: Quellcode und Buildconfig für die native iOS-App als XCode-Projekt.
├── node_modules/: Abhängigkeiten für dieses Projekt.
├── App.tsx: Primäre View der Anwendung, referenziert aus der index.js.
├── app.json: Metainformationen wie Name der Anwendung und Version.
├── index.js: Haupteinstiegspunkt der React-Native App.
├── package.json: Definition der Abhängigkeiten für dieses Projekt.
└── tsconfig.json: Compiler- und Linterkonfigurationen für Typescript.

Ändern wir nun im ersten Schritt den angezeigten Text und die Hintergrundfarbe. Dazu müssen wir die primäre View bearbeiten, also die App.tsx. Diese sieht momentan wie folgt aus:

Inhalt der App.tsx
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>Open up App.tsx to start working on your app!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Sie teilt sich grob in drei Blöcke. Oben stehen die zu importierenden Abhängigkeiten. In unserem Fall sin des nur die Standardabhängigkeiten React, sowie StyleSheet, Text und View aus dem Package react-native.

Im zweiten Block mit der Funktion sehen wir, dass hier eine function namens App exportiert wird. Dieser Export bedeutet, dass diese Funktion von außerhalb dieser tsx-Datei sichtbar und aufrufbar ist. Sie gibt ein Element vom Typ View (oben importiert) zurück und assoziiert in HTML-Notation den im dritten Block definierten Style. Innerhalb dieses View-Elementes ist ein Text-Element geschachtelt, welches den in Abbildung 3 auf dem Emulator angezeigten Text enthält.

Im dritten Block folgt die CSS-artige Inlinestyledefinition. Es gibt also eine Art Style-Selektor container mit den angegebenen Eigenschaften. Diese wird wie beschrieben in Block zwei obendrüber an das View-Element angehängt. Üblicherweise werden die Styles in React Native immer in dieser Form definiert und nicht in CSS-Dateien ausgelagert. Mit der richtigen Progammbibliothek ließe sich das natürlich ändern.

Zusammenfassend haben wir also eine View mit einem Text darin, welche mit einem CSS-artigen Inlinestyle gestyled ist.

Testweise könnte man jetzt den Text wie folgt ändern:

<Text>Open up App.tsx to start working on your app!</Text> 🡆 <Text>Hallo Welt Test 123</Text>

und den Style:

backgroundColor: '#fff', 🡆 backgroundColor: '#d3fccf',

Nach dem Speichern der veränderten App.tsx sollte sich die App auf dem Emulator nach einem Moment automatisch wie folgt aktualisieren:

Abbildung 4. Aktualisierte App auf dem Android Emulator.

Sofern die automatische Aktualisierung einmal nicht funktioniert, kann auch manuell aktualisiert werden, indem im entsprechenden Konsolenfenster die Taste r gedrückt wird.

Der Hintergrund ist jetzt grün und der Text wie angepasst. Wunderbar! Da Android-Apps auch häufig mit Java entwickelt werden, stellt sich hier die Frage, ob sich diese eher funktionale Schreibweise der Anwendungsdefinition auch objektorientierter mit Klassen wie in Java abbilden lässt. Das würde den Umstieg von Android-Entwicklern, die Java verwenden wohl signifikant erleichtern. Die Antwort auf die Frage lautet: Ja, es geht auch mit Klassen. Sogar relativ leicht.

Alternative: Klassen statt Funktionen

Oben hatten wir unsere Anwendung ja als einzelne Funktion definiert, die zurückgegeben wird. Alternativ können in React und React Native auch Klassen verwendet werden.

Ersetzen wir also unsere Funktion durch eine Klasse:

export default class App extends React.Component<any, any> {

  constructor(props: any){
    super(props);
  }

  public render() {
    return (
      <View style={styles.container}>
        <Text>Hallo Welt Test 123</Text>
      </View>
    );
  }
}

Imports und die Styledefinition bleiben wie gehabt. Statt einer Funktion wird nun jedoch eine Klasse App zurückgegeben, welche von React.Component erbt. Auf die beiden any-Typen in den spitzen Klammern wird im nächsten Schritt eingegangen.

Nach der Klassendefinition folgt in der dritten Zeile der Konstruktor. Der Konstruktor ist in diesem Fall eher unspektakulär, da der übergebenen Wert bloß an den Superkonstruktor durchgereicht wird. In diesem Fall wäre dieser Konstruktor sogar optional, da genau dieses Verhalten auch vom impliziten Standardkonstruktor so durchgeführt wird.

Schließlich folgt die render-Methode, welche den identischen Inhalt zur App-Methode aus dem vorherigen Codebeispiel enthält.

Nun stellt sich die Frage, welchen Mehrwert das Ganze mit der Klasse nun bringt, da das Resultat das gleiche ist wie mit der App-Funktion von oben. Es gibt nur mehr Overhead. Die Antwort lautet: Das richtige Tool für den richtigen Job. In diesem Beispiel war die Klasse komplett stateless, daher böte sich eine Implementierung ohne explizite class nur über die Funktion an. Anders sieht es im folgenden Beispiel aus.

Statemanagement in React-Native Apps

Hier fügen wir in die bestehende Anwendung ein Textfeld und eine Schaltfläche hinzu. Sobald die Schaltfläche gedrückt wird, soll der initiale "Hallo Welt"-Text durch den Text im Textfeld ersetzt werden. Dadurch wird die Anwendung zustandsbehaftet. Da die weiteren Beispiele im Artikel auf diese Basis aufbauen, soll in dieses Textfeld kein beliebiger Text, sondern ein Standort eingeben werden.

Beginnen wir wieder mit den Imports:

import React from 'react';
import { StyleSheet, Text, View, TextInput, Button } from 'react-native';

Dieses Mal werden also neben dem Text und dem View offenbar noch weitere Elemente aus dem react-native-package importiert. Spannend!

Wie versprochen soll das Beispiel nun einen internen state haben. Dafür wird zunächst einmal definiert, wie dieser denn aussehen soll. Dies geschieht anhand eines Interfaces:

interface AppState {
  locationText: string
  editedLocationText?: string
}

Das Interface spezifiziert wie ein dazugehöriges Objekt auszusehen hat, enthält selbst aber nur diese Metainformation und keine tatsächlichen Daten. in diesem Fall gibt es also ein Attribut vom Typ string namens locationText, welches den angezeigten Ort bereithält. Dazu gibt es noch ein optionales Attribut editedLocationText, welches den geänderten Text beinhalten soll. Objekte in TypeScipt sind zwar semistrukturell definiert, lassen sich per Cast aber üblicherweise ohne Plausibilitätscheck duck-typen. Fehlende Attribute, die im Cast-Ziel vorhanden sein müssen, sind dann beim Zugriff wie zu erwarten undefined.

Weiter mit der Klassendefinition:

export default class App extends React.Component<any, AppState> {

  constructor(args: any) {
    super(args);
    this.state = { locationText: "Hallo Welt!" };
  }
}

Es fällt auf, dass im Kontrast zum oberen Beispiel die Klasse nicht länger die beiden Typen any-any in den spitzen Klammern, sondern any-AppState beinhaltet. Der vordere der beiden Parameter ist der Typ der sogenannten Properties. Dies sind quasi Eingabeparameter für die Klasse, die dann in den Konstruktor weitergereicht werden. Der zweite Parameter ist unsere State-Definition von oben. Im Konstruktor wird der State auch gleich mit dem location Text-Wert Hallo Welt! initialisiert, welcher im vorherigen Beispiel noch im Virtual-DOM fest einprogrammiert war.

Dank Typescript lässt sich hier für den State auch ausschließlich locationText (und natürlich optional editedLocation) setzen, und dafür auch nur string-Werte.

Als nächstes die überarbeitete render-Methode, welche innerhalb der Klasse, etwa unterhalb des Konstruktors vor die finale schließende Klammer eingefügt wird:

  public render() {
    return (
      <View style={styles.container}>
        <Text>{this.state.locationText}</Text>
        <TextInput placeholder="Ort eingeben" onChangeText={(text) => this.onLocationTextChange(text)} />
        <Button title="Übernehmen" onPress={() => this.saveLocation()} />
      </View>
    )
  }

Anstatt des hartkodierten Wertes erhält das Text-Element nun seinen Wert aus dem lokalen State locationText. Zusätzlich gibt es hier den erwähnten TextInput mit einem Platzhaltertext und einem onChange-Handler, der aktiv wird sobald sich der eingegebene Text ändert. Die aufzurufende Funktion this.onLocationTextChange muss natürlich noch erstellt werden. Sie bekommt in bekannter Lambda-Schreibweise ein string-Argument übergeben, welches den aktualisierten Text enthält.

Schließlich folgt noch die Schaltfläche mit der Aufschrift "Übernehmen", welche beim Klicken die Methode this.saveLocation() aufrufen soll.

Fehlen noch die beiden Methoden zum Ändern und Speichern des aktualisierten Textes:

private saveLocation() {
  console.log(`Aktualisiere Ort: ${this.state.editedLocationText}`);
  this.setState({ locationText: this.state.editedLocationText ? this.state.editedLocationText : "", editedLocationText: "" });
}

private onLocationTextChange(text: string) {
  this.setState({ editedLocationText: text });
}

Diese beiden Methoden müssen sich auch innerhalb der Klasse befinden. Die Methode saveLocation gibt zunächst den aktuell geänderten Wert auf der Konsole mittels String-Template aus. Anschließend wird der State der Anwendungs-Klasse aktualisiert, indem der locationText auf den Wert der editierten Location gesetzt wird. Letztere wird anschließend geleert.

Als Resultat der State-Aktualisierung wird umgehend ein partieller Render der Oberfläche ausgelöst, wodurch das Textelement den neuen Text anzeigt und das Eingabefeld geleert wird.

Die zweite Methode erhält den vom Event-Handler abgefangenen neuen Wert für den Text des Eingabefeldes und legt diesen im State-Feld editedLocationText ab.

Wie bei der oberen Methode wird auch hier ein Render aufgrund der Zustandsaktualisierung ausgelöst. Allerdings wird dabei nur das virtuelle DOM von React aktualisiert und nicht die tatsächliche Oberfläche der Android-App neugezeichnet, da es ja nur eine Änderung am internen State gab, der nicht in einer geänderten Oberfläche resultiert.

Die aktualisierte Version der App sieht wie folgt aus:

Abbildung 5. App mit internem Zustand und dynamisch aktualisierender Oberfläche.

Natürlich ließe sich der State auch mit dem funktionalen Ansatz des vorherigen Kapitels realisieren.

Um den Mehrwert einer nativen App gegenüber einer Progressive Web App auch zu realisieren, sollen nun einige native-only Funktionen, wie die Geo-Location und eine Push-Notification verwendet werden.

Geo Location

Da Geo Location seit React Native .60 nicht mehr bei den initialen Plattformbibliotheken dabei ist, muss hierfür ein extra Modul [9] installiert werden: npm install @react-native-community/geolocation --save. Es macht Sinn, dafür kurz den Emulator und den automatischen Reloadprozess zu beenden, da es sonst zu Dateilocks kommen kann und die Modulinstallation nicht erfolgreich abgeschlossen werden kann.

Das neue Modul wird dann beim Starten via npx react-native run-android automatisch vom React Native CLI gelinked.

Um den Standort in der App selbst auszulesen, anstatt sich auf den Benutzer zu verlassen, wird die saveLocation-Methode wie folgt abgeändert:

private saveLocation() {
  console.log(`Aktualisiere Ort: ${this.state.editedLocationText}`);
  Geolocation.getCurrentPosition(pos => {
    let loc = this.state.editedLocationText ? this.state.editedLocationText:""
    this.setState({ locationText: `${loc}: ${pos.coords.latitude}/${pos.coords.longitude}`, editedLocationText: "" });
  },
    error => console.log(error),
    { enableHighAccuracy: false, timeout: 50000 });
}

Außerdem muss der Import von der oben hinzugefügten Abhängigkeit eingefügt werden:

import Geolocation from '@react-native-community/geolocation';

Wie im oberen Snippet ersichtlich, wird via Geolocation.getCurrentPosition(callback, error, config) der aktuelle Standort ausgelesen. Zurück kommt ein Objekt der Form

{   "coords":{
      "accuracy":603,
      "altitude":0,
      "heading":0,
      "latitude":37.4219865,
      "longitude":-122.0840175,
      "speed":0

},
   "mocked":false,
   "timestamp":1587238724751
}

Hieraus wird im Success-Callback die Latitude und Longitude ausgelesen und an den neuen anzuzeigenden locationText angehängt. Dieser wird dann gleich per State-Update weitergegeben.

Im Fehlerfall wird eine Meldung auf der Konsole ausgegeben.

Beim ersten Starten bzw. Reloaden der Anwendung taucht nun nach dem Klick auf den "Übernehmen"-Button die Berechtigungsabfrage in Abbildung 6 auf.

Abbildung 6. Berechtigungsabfrage Standort.
Abbildung 7. Ausgabe von Latitude und Longitude.

Nachdem die Berechtigungsanfrage akzeptiert wurde, wird sofern alles funktioniert hat nun der im Emulator eingestellte Standort ausgegeben (siehe Abbildung 7).

Eine Berechtigungsanforderung über einen Eintrag in der android/app/src/main/AndroidManifest.xml-Datei, welche sicherlich den meisten Androidentwicklern bekannt ist, ist hier nicht erforderlich. Der Grund dafür ist, dass das von uns ganz oben verwendete React-Native Template bereits alle Berechtigungen anfordert. Die Idee ist hierbei, diese nach Abschluss der der Entwicklungsarbeit entsprechend den Anforderungen zu stutzen. Für die iOS-App sieht dies ähnlich aus. Hier muss unter Umständen die Info.plist-Datei angepasst werden.

Neben der Geolocation gibt es noch weitere spannende native-only Funktionen. Zum Beispiel das Versenden von Push-Notifications. Das schauen wir uns als nächstes an.

Push-Notifications

Da die Konfiguration von Remote Push-Notifications über Firebase oder Apple Push Notification services den Rahmen dieses Artikels etwas sprengen würde, beschränken wir uns hier auf lokale Push-Benachrichtigungen. Da diese Funktionalität von React-Native nicht direkt mitgeliefert ist, wird erneut eine Programmbibliothek [10] installiert (npm install --save react-native-push-notification) sowie die dazugehörigen Typescript-Typen (npm install --save @types/react-native-push-notification).

Anschließend wird die saveLocation-Methode ein letztes Mal erweitert:

private saveLocation() {
  console.log(`Aktualisiere Ort: ${this.state.editedLocationText}`);
  Geolocation.getCurrentPosition(pos => {
    let editedLocText = this.state.editedLocationText ? this.state.editedLocationText : ""
    let loc = `${editedLocText}: ${pos.coords.latitude}/${pos.coords.longitude}`
    this.setState({ locationText: loc, editedLocationText: "" });
    PushNotification.localNotification({ message: loc });
  },
    error => console.log(error),
    { enableHighAccuracy: false, timeout: 50000 });
}

Natürlich muss PushNotification auch importiert werden:

import PushNotification from 'react-native-push-notification';

Die Methode PushNotification.localNotification(…​) in Zeile 7 wird nun mit dem gleichen Wert wie die State-Aktualisierung aufgerufen. In unserem Fall ist dies auch der einzige Parameter. Die Methode akzeptiert jedoch noch über 20 weitere, optionale Parameter zum Konfigurieren unterschiedlichster Eigenschaften der Push-Notification. Die gesamte Dokumentation kann der README-Datei im GitHub Repository [10] entnommen werden.

So sieht unsere Push-Notification aus:

Abbildung 8. Push Notification.

Damit haben wir nun eine kleine Multi-Platform-App gebaut, welche neben einigen Basiselementen auch den Standort auslesen und Push-Benachrichtigungen verschicken kann. Dies Funktionalitäten blieben einer Progressive Web App dagegen verwehrt.

Fazit

Was nahezu sofort auffällt ist die große Nähe von React Native zu React. Das Wertversprechen welches allein durch den Namen suggeriert wird, wird hier voll und ganz eingehalten. Dadurch geht der Umstieg von React auf React Native für eine Person, die bereits einige React-Kenntnisse gesammelt hat, sehr leicht vonstatten.

Wer React noch nie verwendet hat, hat natürlich den Vorteil, dass nach der Lektüre von React Native die Rückrichtung nach React ebenfalls leichtfällt.

Außerdem fiel auf, dass React Native selbst doch sehr leichtgewichtig ist. Selbst für eigentlich für eine native App sehr offensichtliche Funktionen wie Push Notifications und auch Geolocation mussten weitere Abhängigkeiten nachgezogen werden. Die beiden Abhängigkeiten, die in diesem Artikel verwendet wurden, scheinen jedoch recht reif entwickelt zu sein und können beide eine große Menge an Contributers auf GitHub sowie eine große Menge an Verwendern via NPM vorweisen.

Einzig schmerzend fällt auf, dass eine direkte Trennung von Oberfläche und Programmierlogik sowie Domänenobjekten (etwa via dem MVC-Pattern) nicht so direkt umsetzbar scheint. Eine Vermischung von Oberflächencode und Businesslogik trägt insbesondere im Enterprise-Umfeld nicht gerade zu einer Reduktion der Gesamtkomplexität der Anwendung bei. Wie das anderswo gelöst wurde haben wir in einem Artikel zu NativeScript erläutert [11].

Das Setup der Android-Entwicklungsumgebung ist nach wie vor erstaunlich aufwendig. Sobald diese jedoch funktioniert, lässt sich React Native tatsächlich mit minimalem Aufwand integrieren. Auch während der Entwicklung ist insbesondere das Quick Reload Feature dank Virtual DOM (das übrigens auch bei React im Browser zum Einsatz kommt) sehr positiv aufgefallen. So wurden Änderungen an der UI oder dem Code nahezu instantan umgesetzt, ohne dabei etwa bereits eingetragene Werte zurückzusetzen oder gar die ganze Anwendung neuzustarten. Dies ermöglicht eine sehr agile Entwicklung mit kurzen Build-Compile-Deploy-Zyklen und rapidem Feedback.

Außerdem ist React Native dank umfangreicher offizieller Dokumentation [3] und vieler Stack-Overflow Posts und Tutorials überall im Netz recht leicht zu erlernen.

Wer bis hierher gelesen hat sollte auf jeden Fall das GitHub-Projekt auschecken und das ganze selbst ausprobieren; Nur so kann man sich wirklich ein eigenes Bild von React Native machen. Wenn es noch Fragen konkret zum Artikel oder zu React Native oder mobiler Entwicklung allgemein gibt, stehen wir natürlich gerne zur Verfügung.

Referenzen




Zu den Themen React, NativeScript, Vue und Angular bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:

Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.

Über Steffen Jacobs

Steffen Jacobs (M.Sc) hat Wirtschaftsinformatik an der Universität Mannheim studiert und ist als Consultant und Software-Entwickler tätig. In seiner Freizeit engagiert er sich im OpenSource Umfeld.

Feedback oder Fragen zu einem Artikel - per Twitter @triondevelop oder E-Mail freuen wir uns auf eine Kontaktaufnahme!

Zur Desktop Version des Artikels