Flutter – Ein Überblick über Googles Mobile App SDK für Android und iOS

Hybride Frameworks, mit denen Code zwischen Android und iOS Geräten geteilt werden kann, verführen öfter mit ihrem Versprechen „Write once, run anywhere“. Dass dieses Versprechen nicht unbedingt eingelöst wird, zeigen mehrere Blogposts namhafter Firmen wie Airbnb und Udacity, die sich von React Native zugunsten der nativen Entwicklung abgewandt haben. Die Gründe sind vielfältig und spezifisch, und sie zeigen vor allem auf, dass hybride Entwicklung kein einfacher Weg zu weniger Entwicklungszeit und -kosten bedeutet. Die Entscheidung für hybride Entwicklung muss daher informiert und bedacht getroffen werden. In diesem Post wird Googles neuster SDK Flutter kurz beleuchtet.

Was ist Flutter?

Flutter ist laut Googles eigenen Aussagen ein Mobile App SDK für das Erstellen hochwertiger nativer Interfaces für Android und iOS in Rekordzeit. Flutter-Anwendungen werden in Dart geschrieben und können schließlich zu iOS und Android-Anwendungen verpackt werden. Dart ist ebenfalls eine Eigenentwicklung von Google, die speziell für auf die Entwicklung von Frontend-Anwendungen zugeschnitten ist und auch z.B. für die Programmierung von Angular verwendet werden kann.

Die höchst angepriesenen Features von Flutter sind Hot Reload, das sofortige Beobachten von Änderungen am Gerät beim Programmieren, eine extensive Widget-Library, die das Design von schönen und flüssigen User Interfaces erleichtern soll und Reactive Programming, also das asynchrone Ausführen von Operationen bei Nutzerinteraktionen. Die Schwerpunkte sind also klar: optimale User Interfaces und eine gute Entwicklererfahrung. Im Folgenden werde ich einige Aspekte von Flutter genauer beleuchten.

Dart

Zwischen der Verbreitung von Java und Dart gibt es offensichtlich extreme Unterschiede. Laut dem aktuellen Tiobe Index liegt Java mit 17% auf Platz 1, Dart hingegen mit 0,5% auf dem 23ten Platz. (Aber rangiert dabei immer noch weit über Kotlin.) Einen Java-Entwickler wird man leichter an die Hand bekommen als einen Dart-Entwickler, allerdings beherrscht nur ein kleiner Teil der Java-Entwickler auch das nötige Knowhow für die Entwicklung von nativen Apps. Durch Darts Frontend-Fokus dürfte der typische Dart-Entwickler hier einen Vorsprung haben.

Dart ist in der neusten Version stark typisiert, und verfügt über eine Syntax, die stark von JavaScript beeinflusst wurde. Dart unterstützt Objektorientierung sowie funktionale Programmierung und bringt von Haus aus eine sehr mächtige Standardbibliothek an Funktionen mit. Syntaktisch reicht sie noch nicht an die Kürze und Klarheit von beispielsweise Kotlin oder Swift heran, aber bietet gerade im Vergleich mit Java knappen und ausdrucksstarken Code.

Asynchronität ist ein Kernpunkt von Dart und ist direkt in die Standardbibliotheken integriert, während man bei der nativen Entwicklung häufig zu Hilfsbibliotheken wie RxJava oder LiveData greifen muss. Dart unterstützt Async / Await, Futures und asynchrone Streams, auf die man sich ähnlich wie auf Rx Observables subscriben kann, um bei jedem Output zu reagieren, bis der Stream geschlossen ist. Positiv überrascht hat mich die Unterstützung für Tests mit asynchronen Funktionen, für die eine Reihe praktischer Matcher zur Verfügung stehen.

Interessant für die Performance und auch die Größe von Apps ist das native Tree Shaking von Dart und Flutter, also dass nicht benötigte Funktionen vom Compiler entfernt werden. Das wirkt sich insbesondere positiv auf den Speicherabdruck einer App aus, weshalb Flutter von diesem Feature starken Gebrauch macht. Im Gegenzug dazu kann Runtime Reflection nicht verwendet werden, wodurch beispielsweise Dependency Injection und das Parsen von JSON Objekten unhandlicher gemacht werden.

User Interface

Widgets ist ein Wort, das man in Flutter ständig lesen wird, denn jedes UI Objekt ist ein Widget. Während man in Android das UI hauptsächlich über XML deklariert und die einzelnen Views und Layouts über ihre IDs anspricht, programmiert man das gesamte UI in Flutter direkt in Dart. Tatsächlich ist das mein größter Kritikpunkt an dem Framework, da es Layout und Funktionalität sehr eng verzahnt und die Übergabe von Designs an die Entwickler, wie sie zum Beispiel von Photoshop zu Android XML, erschwert.

Das UI wird ausschließlich aus Containern, Zeilen und Spalten zusammengesetzt, was aus der Web-Entwicklung vertraut sein sollte. Allerdings ist fraglich, weshalb Google nicht direkt für Flutter ein Constraint basiertes Layout zur Verfügung stellt, da sich bereits auf nativem Android zeigte, wie unübersichtlich Schachtelungen werden können, um ein gewünschtes Layout zu erreichen. Und da das gesamte Layout in Code gegossen ist, erhöht dieser Ansatz weder Lesbarkeit noch Wartbarkeit.

Erträglich wird das Entwickeln tatsächlich dank des Hot Reloads, der wesentlich zuverlässiger als die Apply Changes Funktion von Android funktioniert. Die Änderungen sind innerhalb von Sekunden sichtbar. Dazu bietet Flutter viele Komfortfunktionen zum Erstellen von Listen oder dem Anreichern von Widgets mit, die den Code kompakter als die Java-Äquivalente machen und Boilerplate ersparen. Für eine endlose Liste genügt zum Beispiel folgende Deklaration:

ListView.builder(

  itemBuilder: (BuildContext context, int index) {

    return Text('entry $index');

  },

)

Die grundlegende Architektur hinter dem UI ist hingegen durchdachter und gibt im Gegensatz zur Android Entwicklung direkt einen reaktiven Weg mit, um auf Nutzerinteraktionen zu reagieren. Widgets sind in nicht-interaktive, zustandslose Widgets und interaktive, zustandsbehaftete Widgets unterteilt. Wird der Zustand gesetzt, wird das entsprechende Widget neu gezeichnet. Diesen Zustand kann man ohne größere Probleme an ein ViewModel koppeln und erhält leicht eine saubere MVVM-Struktur, die inzwischen auch in Android bevorzugt wird.

Behandlung von iOS und Android

Zu den wichtigsten Komponenten von hybriden SDKs gehört der Umgang mit plattformspezifischen Konventionen des UIs und das Abrufen von Kontextinformationen wie Batterielevel oder Internetverbindung.

Flutter verfügt über eine umfassende Bibliothek an Widgets, die in Material und Cupertino unterteilt sind und die Android und iOS Äquivalente darstellen. Der Großteil der Komponenten wie zum Beispiel der Listview ist plattformagnostisch und damit ohne Unterscheidung einsetzbar. Andere Komponenten wie zum Beispiel die Navigationsleisten sind plattformspezifisch, benötigen plattformspezifische Eltern-Elemente und verfügen über unterschiedliche Properties. Dieses Problem ist allerdings mit einfachen Methoden handhabbar.

Zur Kopplung an die Plattform und deren Kontextservices nutzt Flutter Nachrichtenkanäle, über die es sich mit dem Backend austauscht. Auf der Flutter-Seite muss man nur den Kanal benennen, und kann einfache Nachrichten an das Backend senden. Je nach Plattform müssen hierfür dann Adapter implementiert werden, die auf die Nachrichten lauschen und die Ergebnisse zurückliefern. Alternativ kann auch das UI einen dieser Kanäle abonnieren, um auf Ereignisse der Plattform zu reagieren.

Zukunft von Flutter

Flutter ist über die letzten Jahre immer weiter gereift. Aktuell ist die zweite Release Preview verfügbar, und Anfang Dezember findet die Flutter Live statt, in der die neusten Entwicklungen zu Flutter bekannt gegeben werden. Der SDK erfreut sich auf Stack Overflow zunehmender Beliebtheit und ist teilweise gleichauf oder höher als ReactNative. Flutter Apps werden auch auf dem von Google entwickelten Betriebssystem Fuchsia laufen können, während Java aktuell nicht unterstützt wird. Welchen Einfluss Fuchsia auf das Ökosystem mobiler Geräte haben wird, bleibt jedoch abzuwarten.

Flutter ist eine ernstzunehmende, aber noch sehr junge Alternative für die mobile Entwicklung. Dem SDK fehlen noch Reife und Tooling, die Android durch Java geschenkt bekam. Die Community befindet sich im Wachstum und Google arbeitet beständig daran auf Entwickler-Konferenzen für Flutter zu werben. Mein Fazit wäre, dass es für kleinere Projekte und Teams spätestens mit dem ersten stabilen Release eine Überlegung wert wäre, neue Projekt auf Flutter Basis zu beginnen