Lesezeit: 9 Minuten
Apps entwickeln: Cross Platform mit React Native und Expo
Eines der beliebtesten Cross-Platform-Frameworks ist React Native. Wir bei MaibornWolff setzen es in einigen Kundenprojekten erfolgreich ein. Aber was macht React Native attraktiv und wie sieht die Developer Experience aus? Genau das betrachte ich im Folgenden näher. Native App oder Cross-Platform-Technologien Wer Apps für Mobilgeräte entwickeln möchte, muss ganz zu Anfang eine wichtige Entscheidung treffen:…
Eines der beliebtesten Cross-Platform-Frameworks ist React Native. Wir bei MaibornWolff setzen es in einigen Kundenprojekten erfolgreich ein. Aber was macht React Native attraktiv und wie sieht die Developer Experience aus? Genau das betrachte ich im Folgenden näher.
Native App oder Cross-Platform-Technologien
Wer Apps für Mobilgeräte entwickeln möchte, muss ganz zu Anfang eine wichtige Entscheidung treffen: Soll es eine native App werden oder können Cross-Platform-Technologien eingesetzt werden?
Was steckt hinter dieser Frage? Da die beiden großen mobilen Betriebssysteme Android und iOS jeweils einen hohen Marktanteil besitzen, möchte man in der Regel beide Plattformen bedienen. Baut man native Apps, nutzt man die von Apple und Google vorgesehenen Technologien, die spezifisch auf die jeweilige Plattform zugeschnitten sind. Dadurch wird garantiert, dass die Apps performant laufen, dass der Zugriff auf die Hardware (Kamera, GPS, etc.) einwandfrei funktioniert und dass die User Experience nahtlos zum Gesamtsystem passt. Leider unterscheiden sich Android und iOS technologisch grundlegend, weshalb mit diesem Ansatz zwei getrennte Versionen derselben App gebaut werden müssen.
Häufig benötigen Apps nur einen Bruchteil der Betriebssystem-nativen Features. Darüber hinaus möchte man, wenn möglich, den Mehraufwand einer doppelten App-Entwicklung sparen. Hier kommen Cross-Platform-Technologien wie React Native, Ionic oder Flutter ins Spiel. Die Grundidee all dieser Technologien ist dieselbe: Mit nur einer Code-Basis wird eine App für mehrere Plattformen erstellt, die über einheitliche Schnittstellen ebenfalls Zugriff auf die jeweiligen Geräte-nativen Features hat.
Den reduzierten Entwicklungsaufwand erkauft man sich unter anderem mit einigen technologischen Einschränkungen und einer etwas schlechteren Performance; durch immer schnellere Smartphones ist letzteres für Endnutzer aber häufig nicht mehr spürbar.
Learn once, write anywhere
React Native wurde 2015 von Facebook als Open Source veröffentlicht und basiert, wie der Name schon sagt, auf dem sehr populären Web-Framework React. Entwickler*innen, die bereits dieses Framework kennen, finden sich auch in React Native äußerst schnell zurecht. In Anspielung auf den berühmten Slogan „Write once, run anywhere“, der sich auf die Cross-Platform-Fähigkeit von Java bezog, lautet der Werbe-Slogan von React Native daher „Learn once, write anywhere“.
Diese große Stärke von React Native ermöglicht es Entwickler*innen nicht nur, ihr Wissen aus der Web-Entwicklung wiederzuverwenden und mobile Apps mit JavaScript oder TypeScript anstatt Java, Kotlin oder Swift zu bauen. Es können auch viele etablierte Technologien und Konzepte aus der Web-Entwicklung wiederverwendet werden, darunter State-Management-Architekturen (etwa mit Redux oder MobX) oder ein Linter-Setup (zum Beispiel mit ESLint) zur statischen Codeanalyse.
Nativ oder nicht nativ
Wieso trägt React Native das Wort „Native“ im Namen und wo liegt der Unterschied zu rein Web-basierten Apps wie zum Beispiel Progressive Web Apps?
React Native produziert keine Web-App, die nur in einer „nativen Hülle“ ausgeführt wird. Stattdessen sind die erzeugten User Interfaces (UIs) tatsächlich nativ, nutzen also Standard-UI-Komponenten des jeweiligen Betriebssystems. React Native stellt hierfür eine Abstraktionsschicht bereit: Die grundlegenden UI-Bausteine heißen beispielsweise <View>
, <Text>
oder <Image>
und werden in die passenden nativen Komponenten der jeweiligen Plattformen übersetzt. Dies wird ermöglicht durch die deklarative Art, mit der in React UIs definiert und aus Komponenten zusammengebaut werden. Flexibilität garantiert auch die Möglichkeit, einen React Native Wrapper für eigene native Komponenten zu erstellen.
Anders verhält es sich mit dem JavaScript-Code um die Komponenten herum: Dieser wird nicht in eine „native Sprache“ übersetzt, sondern von React Native direkt in einer JavaScript-Engine ausgeführt, die in einem Hintergrundprozess läuft. Die Kommunikation mit der nativen Plattform läuft über eine sogenannte Bridge. Diese stellt einen asynchronen, gebündelten und serialisierten Nachrichtenaustausch zwischen dem Haupt- und dem JavaScript-Thread sicher.
Expo: Ein Framework für React Native
Obwohl React Native bereits eine gute Abstraktionsschicht bietet und damit die Komplexität der Entwicklung deutlich reduziert, bleiben einige Schwierigkeiten der nativen Entwicklung erhalten. Dazu zählen insbesondere das Starten der App für die lokale Entwicklung sowie das Bauen einer Release-fähigen App-Datei. Hierfür ist ein natives Setup erforderlich. Für iOS bedeutet das, dass ein Mac mit einer Xcode-Installation vorhanden sein muss.
Um auch diese Schwierigkeiten zu lösen und damit noch schneller produktiv nutzbare Ergebnisse zu erhalten, kann Expo eingesetzt werden. Expo ist ein Framework sowie eine Sammlung von Services um React Native herum. Mit Expo kann eine React-Native-App komplett ohne natives Setup ausgeführt und veröffentlicht werden: Für die lokale Entwicklung läuft die App in einer Wrapper-App namens Expo Go, die alle zur Laufzeit notwendigen nativen Schnittstellen bereitstellt.
Für ein App-Release verfolgt Expo einen zweistufigen Prozess:
publish
: Zunächst werden die JavaScript-Dateien und weitere Assets verarbeitet und auf Expo-Servern abgelegt. Diese Version der App kann ebenfalls direkt mit Expo Go aufgerufen und gestartet werden. Damit ist es sehr einfach möglich, „Nicht-Entwickler*innen“ den Test der App zu ermöglichen, ohne auf Tools wie Apple TestFlight zurückgreifen zu müssen. Es genügt, die Expo Go App auf dem eigenen Smartphone zu installieren und die zu testende App über einen QR-Code zu öffnen. Darüber hinaus werden „published“ App-Versionen auch für Over-the-Air-Updates genutzt, das heißt für nicht-kritische App-Updates, die automatisch beim Nutzer nachgeladen werden, ohne dass dafür die gesamte App aktualisiert werden muss.build
: Möchte man eine App regulär im Google Play Store oder Apple App Store veröffentlichen, ist trotzdem eine gebaute Standalone-Version erforderlich. Diese wird auf Expo-Servern durch eine mit einem nativen Setup konfigurierte Pipeline gebaut. Dadurch wird erreicht, dass sich Entwickler*innen um diesen komplexeren Teil des Build-Setups nicht selbst kümmern müssen. Wie viele Angebote von Expo ist auch dieser Service kostenlos, man muss sich lediglich mit längeren Wartezeiten bei den Builds begnügen.
Managed Workflow
Neben den bereits genannten Vorteilen bringt Expo eine Reihe weiterer Erleichterungen für Entwickler*innen mit sich. Dazu zählt eine Vielzahl von einfach zu nutzenden Open-Source-Bibliotheken, die es unter anderem ermöglichen, mit allen möglichen Hardware-Schnittstellen eines Geräts zu kommunizieren. Außerdem bietet Expo ein besonders einfaches Setup für Push Notifications: Ein Service von Expo fungiert dabei als Vermittler zwischen dem Absender (etwa ein eigener Backend-Service) und den Push-Notification-Lösungen von Google und Apple. App-seitig hilft die Bibliothek expo-notifications
beim Empfang der Nachrichten.
All die genannten Features gehören zur „Standardausrüstung“ im sogenannten Managed Workflow von Expo. Man erkauft sich diese Vorteile allerdings durch den Verlust der Möglichkeit, beliebige React-Native-Bibliotheken mit nativem Bestandteil einbetten zu können. Außerdem kann der Bau einer Standalone-App nur bedingt beeinflusst werden und es entstehen mitunter sehr große App-Dateien. Für das Abstrahieren sämtlicher nativer Bestandteile muss Expo viele davon pauschal mit in die App kompilieren, um sie theoretisch nutzbar zu machen. Wird eine native Bibliothek von Expo nicht unterstützt, kann sie im Managed Workflow nicht genutzt werden.
Das Beste aus beiden Welten?
Glücklicherweise muss man sich nicht zwischen dem „goldenen Käfig“ des Managed Workflow und der „rauen Welt“ von React Native ohne Expo entscheiden. Expo bietet auch einen Bare Workflow, der sowohl die volle Flexibilität eines reinen React-Native-Setups bietet als auch die Nutzung von Expo-Features ermöglicht. Seit Dezember 2020 ist es mit den Expo Application Services (EAS) sogar möglich, Bare-Workflow-Apps auf Expo-Servern bauen zu lassen, genauso wie im Managed Workflow. Hierfür ist jedoch ein bezahlter Account notwendig.
Hat man damit begonnen, eine App im Managed Workflow zu bauen, kann später noch in den Bare Workflow gewechselt werden, wenn man feststellt, dass mehr Flexibilität bei der Entwicklung erforderlich ist. Für den Wechsel ist ein „Eject“ erforderlich, der das App-Projekt mehr oder weniger automatisiert umkonfiguriert. Die Praxis zeigt leider, dass hier häufig händische Nacharbeit notwendig ist. Besonders bei größeren bestehenden App-Projekten mit vielen eingebauten Bibliotheken kann es zu Problemen kommen. Beim App-Build und bei Over-the-air-Updates stellte sich auch die verfügbare Dokumentation als suboptimal heraus. Da der EAS-Build ein wenig anders funktioniert als der klassische Expo-CLI-Build, muss beispielsweise auch beim Umgang mit Umgebungsvariablen anders gearbeitet werden. Der Zeitbedarf für notwendige Kleinarbeit an verschiedenen Stellen sowie das Regression Testing kann sich bei einem „Eject“ also schnell summieren.
Fazit
Mit React Native können mobile Apps schnell und einfach entwickelt werden, ohne sich allzu viele Gedanken über die darunterliegenden Plattformen machen zu müssen. Mit Expo erreicht man sogar noch mehr Unabhängigkeit und kann in kürzester Zeit produktiv nutzbare Apps „auf die Straße“ bringen. Mit dem Managed und dem Bare Workflow bietet Expo verschiedene Abstufungen von Abstraktionsschichten über den Standard-Entwicklungsprozess mit React Native. Ein Wechsel vom Managed zum Bare Workflow, also hin zu mehr Flexibilität, ist mit einem Eject möglich. Dieser ist allerdings unangenehm und potenziell sehr zeitaufwändig, weshalb die Vor- und Nachteile vorsichtig abgewägt werden müssen.