2019: Das Jahr der Cross-Plattform-Entwicklung
2019: Das Jahr der Cross-Plattform-Entwicklung
Die Gesamtzahl der weltweiten App-Downloads wird 2018 die Marke von 200 Milliarden überschreiten. Apps sind aus dem Alltag nicht mehr wegzudenken und die Werbung verspricht: „Es gibt für fast alles eine App.“ Wer mit überschaubarem Zeitaufwand eine Android und iOS App auf den Markt bringen möchte, wird früher oder später auf Cross-Plattform App-Entwicklung stoßen.
Die eigene App ist mittlerweile eine Notwendigkeit für so gut wie jedes Unternehmen, sei es ein Start-up oder ein Konzern, der ein ganzes App-Portfolio für unterschiedliche Produkt- und Kundensegmente bereithält. Heutzutage ist es üblich, Apps für die beiden führenden Betriebssysteme Android und iOS auszuliefern, um so möglichst viele Anwender zu erreichen. Ein Blick auf die verwendeten Technologien und Programmiersprachen der nativen Entwicklung treibt so manchem Entwickler jedoch Schweißperlen auf die Stirn. Android-Apps werden mit Java, Kotlin und Material Design entwickelt, iOS-Apps dagegen mit Swift, Objective-C und nach Apples Human Interface Guidelines. Entwickler, die beide Plattformen beherrschen, sind rar. Somit werden zwei Entwicklungsteams benötigt, eins für Android, eins für iOS. Das knappe App-Budget ist dadurch schneller aufgebraucht, die Synchronisation der Teams aufwendig. Die organisatorischen Hürden lassen sich eventuell durch agile Entwicklungsmethoden in den Griff bekommen, die technischen Hürden bestehen jedoch weiterhin. Die Cross-Plattform-App-Entwicklung greift genau diese Herausforderung auf. Statt mehrerer Entwicklungsteams ist nur noch eins nötig, der gesamte Entwicklungsprozess ist deutlich stromlinienförmiger. Sogar Entwickler, die nie für mobile Geräte entwickelt haben, können durch ihre Kenntnisse aus der Webentwicklung zu wertvollen Ressourcen bei der Entwicklung einer App werden.
Im Dschungel der Begrifflichkeiten verlieren selbst erfahrene Softwareentwickler schnell den Überblick: hybrid, nativ, Cross-Plattform, Web-App. Wo liegen die Unterschiede? Hybride Apps gibt es bereits seit gut einem Jahrzehnt. Sie stellen eine Kombination aus nativen Apps, die individuell für Plattformen wie iOS und Android entwickelt werden, und Web-Apps dar, die in der Regel nur angepasste mobile Webseiten sind. Hybride Apps sind HTML5-, CSS3- und JavaScript-basierte Anwendungen, die über einen nativen Container, wie zum Beispiel PhoneGap oder Apache Cordova, Zugriff auf die Hardwarefunktionen des Smartphones erhalten. Diese Art von Apps laufen in Browserkomponenten des Smartphones. Das Container-Framework sorgt dafür, dass Bedienelemente und Menüs des Browsers versteckt werden. Über Schnittstellenbibliotheken kommuniziert der Browser per JavaScript mit der Hardware des jeweiligen Smartphone-Betriebssystems. Dieser Ansatz hat jedoch entscheidende Nachteile. Hybride Apps fügen sich nicht wirklich in die jeweiligen spezifischen User Interfaces von Android und iOS ein, sie verwenden nicht die nativen UI-Elemente. Anwender merken schnell, dass sie es hier mit einer Art Mogelpackung zu tun haben. Hybride Apps fühlen sich nicht wie native Apps an, sie reagieren oft träge und ihnen fehlt die Reaktionsschnelle, die man von einer nativen App gewohnt ist.
Cross-Plattform-Apps kennen diese Probleme nicht. Sie verwenden das Beste aus beiden Welten, der nativen Welt und der hybriden Welt. Sie verwenden die jeweiligen betriebssystemspezifischen UI-Komponenten, erlauben dennoch die Entwicklung in populären Sprachen wie JavaScript oder TypeScript. Fangen wir mit dem Spitzenreiter an.
React Native entstand aus einem internen Hackathon bei Facebook im Jahr 2013. 2015 gab es die erste öffentliche Preview. Seitdem gewinnt React Native stark an Popularität und es rangiert bei GitHub unter den Top drei der beliebtesten Repositories. React Native funktioniert gänzlich anders als das oben erwähnte Apache Cordova. Wo bei Cordova nur HTML-Seiten in einer WebView gerendert werden, die im besten Fall den Anschein einer nativen App erwecken, benutzt React Native die jeweiligen nativen UI-Elemente. Der Einstieg in React Native fällt besonders Webentwicklern leicht, die schon mit React in der Webentwicklung gearbeitet haben. Gearbeitet wird in JavaScript oder neuerdings auch TypeScript. Swift, Objective-C, Java oder Kotlin muss man nicht beherrschen. React Native erlaubt es, die Komponenten in JSX zu formulieren, dadurch können XML-artige Elemente direkt im Code verwendet werden. Als Layout wird das aus dem Web bekannte Flexbox-Layout benutzt. Durch die Verwendung der nativen UI-Elemente lassen sich React-Native-Apps nicht von echten nativen Apps unterscheiden. React Native erreicht das folgendermaßen: Der JavaScript-Code kommuniziert asynchron über eine sogenannte Bridge (Abb. 1) mit den jeweiligen nativen Betriebssystem-Threads. Die asynchrone Kommunikation garantiert Performance auf der nativen Seite, sodass langlaufender JavaScript-Code das Rendern des UI nicht blockiert. Diese zusätzliche Schicht erhöht die Komplexität der gesamten Anwendung. Vor allem in den ersten Jahren gab es immer wieder Kompatibilitäts- und Performanceprobleme mit React Native, vor allem in Bezug auf Android, da React Native zuerst nur für iOS entwickelt wurde. Das Framework lässt sich mittlerweile als stabil bezeichnen, obwohl vor der Versionsnummer immer noch keine eins steht. Die meisten Kinderkrankheiten sind ausgemerzt und React Native ist praxiserprobt. Dies zeigt sich dadurch, dass namhafte Firmen wie Facebook, Walmart, Uber und Tesla React Native in ihren Apps einsetzen. Nachteilig ist, dass von Facebook aus nur ein überschaubarer Teil an Funktionalität mitgeliefert wird. Es fehlen offizielle Libraries für die Navigation oder Push Notifications, die sowohl auf Android als auch auf iOS funktionieren. Die große Community bietet entsprechende Lösungen an, zudem kann der riesige Fundus an npm-Paketen verwendet werden. Vor allem bei der Einbindung von nativen Modulen, welche die Hardware des Geräts ansprechen, lässt es sich manchmal nicht vermeiden, minimale Änderungen in Java- und Object-C-Dateien vornehmen zu müssen. Um dadurch nicht zu viele Entwickler abzuschrecken, wurde Expo vorgestellt.
Expo ist eine kostenlose und quelloffene Toolchain auf Basis von React Native und JavaScript, die weitere stabile Schnittstellen zu nativen Bibliotheken bietet. Mit dem Webdienst Expo Snack wird eine Programmierumgebung für den Webbrowser angeboten. Sie erlaubt es, gleichzeitig zu entwickeln und auf einem simulierten iOS- oder Android-Gerät zu testen. Das funktioniert gut, um schnell eine Fehlersituation nachzustellen, wer jedoch ernsthaft und längerfristig an einer App entwickelt, wird sich schnell die Smartphone-App Expo aus dem jeweiligen Store zusammen mit dem Kommandozeilenwerkzeug expo-cli laden. Mit diesen Werkzeugen lässt sich innerhalb von Sekunden das Grundgerüst einer App aufsetzen, das man direkt auf dem eigenen Gerät testen kann (Abb. 2). Die Webseite von Expo gibt hier eine gute erste Hilfestellung.
Die Entwicklungen bei Facebook in Bezug auf React Native wollte der Suchmaschinengigant Google wohl nicht auf sich sitzen lassen. Auch Google möchte auf dem Cross-Plattform-Markt mitmischen und bietet dafür Flutter an. Flutter ist Googles mobiles App-SDK für die Entwicklung nativer Apps auf iOS und Android. Google verwendet Flutter beispielsweise für die Google-Ads-App, weitere Anwendungen befinden sich in der Pipeline.
Flutter ist jünger als React Native und wurde 2017 vorgestellt. Derzeit noch in einer Release Preview verfügbar, soll 2019 das erste 1.0 Release veröffentlicht werden. Ähnlich wie React Native verwendet Fluttter keine WebViews zum Rendern. Im Gegensatz zu React Native werden nicht die betriebssystemeigenen nativen UI-Elemente benutzt. Flutter verwendet auf Android und iOS eine eigene Rendering-Engine, die sogenannte Widgets auf den Bildschirm zeichnet. Diese Widgets gibt es in verschiedenen Stilen, beispielsweise im aus Android bekannten Material Design, oder im Stil von iOS (Abb. 3). Der Vorteil dieses Ansatzes ist, dass Flutter immer die Kontrolle über das Design, die Performance und Qualität dieser Widgets behält. Bei React Native ist das nicht garantiert, da hier die betriebssystemeigenen UI-Elemente verwendet werden, auf die die Macher keinen Einfluss haben. Im Gegensatz zu React Native wird Flutter nicht mit JavaScript entwickelt, sondern mit der objektorientierten Programmiersprache Dart aus dem Hause Google. Das Markup wird nicht wie bei React Native deklarativ und in JSX, sondern imperativ als Code formuliert. Da Flutter das Rendering selbst vornimmt, verspricht man sich eine konstante Renderingperformance von 60 Frames per Second, ein deutlicher Vorteil gegenüber React Native, das vor allem im Android-Bereich immer wieder mit Performanceproblemen zu kämpfen hatte. Die Webseite von Flutter ist ein guter Startpunkt, hier gibt es Dokumentationen in von Google gewohnter, sehr hoher Qualität.
Entwickler, die bereits mit Angular oder Vue.js gearbeitet haben, werden sich über das nächste SDK (Software Development Kit) freuen. NativeScript ist ein Open-Source-Framework der Firma Progress, mit dem sich mit JavaScript oder TypeScript native iOS- und Android-Apps bauen lassen. NativeScript wurde 2015 veröffentlicht. Es nutzt die jeweiligen JavaScript Virtual Machines, und injiziert alle iOS und Android APIs direkt in die JavaScript Virtual Machine des Gerätes. Dadurch können die Schnittstellen von iOS und Android direkt in JavaScript angesprochen werden und so beispielsweise die plattformspezifischen UI-Elemente verwendet werden. Während die nativen Schnittstellen beispielsweise in React Native und Flutter vom Framework vor dem Entwickler verborgen werden, sind sie bei NativeScript ein integraler Bestandteil des Frameworks.
Das führt jedoch dazu, dass man sowohl iOS- als auch Android-Expertise im Entwicklungsbereich benötigt, um die jeweiligen Schnittstellen verwenden zu können. Seit 2016 unterstützt NativeScript die Entwicklung mit Angular, im Jahr 2018 wurde Vue.js-Support mit ins Boot geholt (Abb. 4). Hier ist der Einstieg für Entwickler besonders leicht, die schon mit einem dieser Frameworks im Webbereich gearbeitet haben. Auch NativeScript bietet eine Reihe von fertigen UI-Komponenten an, dort ebenfalls Widgets genannt, die auf dem jeweiligen Gerät als native Komponenten gerendert werden. NativeScript ist Single-Threaded, somit wird der JavaScript-Code im UI Thread bzw. Main Thread ausgeführt. Dies ist einerseits praktisch, da man asynchron auf die nativen UI-Elemente zugreifen kann. Rechenintensive Vorgänge können ein Stottern der UI hervorrufen und sollten besser über sogenannte Worker in NativeScript ausgelagert werden. Das UI wird in NativeScript typischerweise in XML-Templates und CSS angegeben, Komponenten können jedoch auch direkt im JavaScript-Code erzeugt werden. Es existieren eine Reihe von Layoutsystemen zur Anordnung der Komponenten, Webentwickler werden sich mit dem Flexbox-Layout direkt wie zu Hause fühlen. Plug-ins erweitern die Basisfunktionalität von NativeScript und erlauben beispielsweise den Zugriff auf das Dateisystem oder die Kamera das Smartphones. Die Community bietet einen ganzen Fundus an Plug-ins an, die unter https://market.nativescript.org/ verfügbar sind. Ähnlich wie React Native und Flutter gestaltet sich der Start einfach. Es existiert ein CLI-Werkzeug, um Projekte von der Kommandozeile aus zu erstellen und die App im Emulator oder auf dem Smartphone auszuführen. Auch hier dient die Webseite von NativeScript als Startpunkt für die Entwicklung.
Lange Zeit war native Entwicklung die erste und einzige Wahl für hochqualitative, performante und pixelgenaue Apps. Auf lange Sicht wird diese Art der Entwicklung jedoch immer seltener werden, da native Entwicklung aufwendig und teuer ist. Entwickler müssen Spezial-Know-how erwerben und können aufgrund der hohen Komplexität oft nur für eine Plattform entwickeln. Cross-Plattform-Frameworks bieten sich somit als sinnvolle Alternative an. React Native mausert sich vom Hackathon-Projekt zum Branchenprimus für Cross-Plattform-Entwicklung und erleichtert den Einstieg für Entwickler, die bereits im Web mit React entwickelt haben. Zudem lässt sich ein großer Codeanteil aus bestehenden React-Anwendungen mit minimalen Anpassungen wiederverwenden. Das vielfältige React- und JavaScript-Ökosystem und die große Community bieten zudem sehr viele Möglichkeiten zur Erweiterung und Anpassung von Apps und die Unterstützung durch den Giganten Facebook garantiert eine gewisse Zukunftssicherheit. Das von Google veröffentliche Flutter stellt eine interessante Alternative dar, vor allem durch die Unabhängigkeit der eigenen Widgets. Leider ist das Ökosystem noch überschaubar und man wird für die Entwicklung zwingend die Programmiersprache Dart lernen müssen. Auch die Größe der Community ist noch überschaubar, sodass es oft an Dart-Modulen für bestimmte Funktionalitäten mangelt. Flutters Vorteil gegenüber React Native ist, dass UI-Komponenten pixelgenau definiert sind und nicht von der Gestaltung von iOS und Android abhängen. NativeScript kann eine interessante Alternative sein, wenn bestehender Angular- oder Vue.js-Code vorhanden ist, der für die App verwendet werden soll. Hinter NativeScript steht jedoch kein globaler IT-Megakonzern und die Community ist im Vergleich zu React Native eher klein. Allen Cross-Plattform-Lösungen ist eins gemein: die Abhängigkeit zu den nativen Plattformen. Ändert Apple beispielsweise ein API zu einer UI-Komponente, muss es eine entsprechende Anpassung im Cross-Plattform-Framework geben. Das trifft vor allem auf React Native und zum Teil auch auf NativeScript zu. Da Flutter das Rendering komplett selbst übernimmt, ist es gegen diese Art von Änderungen des Hostsystems eher resistent. Dennoch rennen die Cross-Plattform-SDKs immer der Entwicklung der nativen Plattformen hinterher. Ein gemeinsames Entwicklungs-SDK, das von Google und Apple unterstützt wird, wäre wünschenswert. Jedoch ist das allein wegen der Unterschiedlichkeit der beiden Plattformen Zukunftsmusik und weder Google noch Apple werden ein wirkliches Interesse an einer solchen Lösung haben. Somit sollte abgewogen werden, welche Technologie bei der Entwicklung einer App infrage kommt (Tabelle 1).
React Native | Flutter | NativeScript | |
---|---|---|---|
Autor | Progress | ||
Code | JavaScript/TypeScript | Dart | JavaScript |
Offiziell unterstützte Plattformen | Android ab 4.1, iOS ab 9 | Android ab 4.1, iOS ab 8 | Android ab 4.2, iOS ab 8.1 |
UI-Komponenten | Verwendung der nativen Komponenten | Eigene Rendering Engine mit Widgets im Stil von Material Design und iOS | Verwendung der nativen Komponenten |
Anzahl GitHub-Sterne | > 70 000 | > 41 000 | >1500 |
Tabelle 1: Übersicht über die vorgestellten Cross-Plattform-Frameworks
Gibt es bereits eine bestehende native App, lässt sich insbesondere React Native einfach integrieren. Auch NativeScript und Flutter bieten die Integration in bestehende Apps an. Je nach Szenario kann Cross-Plattform die Entwicklung um den Faktor zwei beschleunigen. Soll eine App besonders hardwarenah sein oder ganz spezifische Schnittstellen ansprechen, führt jedoch kaum ein Weg an nativer Entwicklung vorbei. Viele Apps, vor allem im Businesskontext sind formulargetrieben und hier spielen Cross-Plattform-Frameworks ihre Stärke voll aus.