blog-post-img-3973

Mobile Apps – Nativ vs. Hybrid oder: Wer billig kauft, kauft zwei mal

Christoph ist ein „App Guy“ und unser erster richtiger Gastautor. „Können wir da nicht eine App zu machen?“ ist eine Formulierung, die in den letzten Jahren in dem ein oder anderen Online Marketing Meeting gefallen sein dürfte und Leuten wie ihm Koppfschmerzen bereitet. Daher gibt Christoph uns ein paar interessante Einblicke in die App-Entwicklung und worauf es dabei alles ankommt:

Ein ungebrochen starker Trend in der App-Entwicklung sind sogenannte Hybride Apps oder Mobile Web Apps mittels Frameworks wie PhoneGap, Cordova & Co. Diese versprechen zu erheblich reduziertem Preis und reduziertem Aufwand das gleiche Ergebnis herkömmlicher App-Entwicklung. Zusätzlich sollen sie sofort auf allen mobilen Plattformen funktionieren. Günstiger, schneller fertig, alle Plattformen auf einmal! Das ist ja zu schön um wahr zu sein! Stimmt.

Schaut man sich die Ergebnisse an, kommt schnell die Ernüchterung: Die Apps sind träge, sehen oft nicht ansprechend aus. Einfache Aktionen lassen die App manchmal sekundenlang einfrieren. Animationen ruckeln stark. Bedienelemente reagieren nicht oder nur mit starker Verzögerung. Woran liegt das?

Begriffsklärung

Was ist aber denn eigentlich der Unterschied zwischen einer nativen und einer Hybrid-App? In der Software-Entwicklung spricht man von nativer Entwicklung, wenn am Ende des Entwicklungsprozesses ein Stück Binärcode steht, das direkt auf der CPU des Systems ausgeführt wird. Es ist also ein „Eingeborener“ des Systems, also nativ.

Eine Hybrid-App ist eine „leere“ App (ein Container), die nur einen sogenannten Web View anzeigt. Dies ist eine Komponente, die eigentlich dazu gedacht ist, HTML in einer App anzuzeigen, z.B. ein formatiertes Impressum. In einer Hybrid App wird dieser Web View nun bildschirmfüllend benutzt, um eine Benutzeroberfläche für die App in HTML nachzubauen. Die eigentliche Programmlogik wird über in die Seite integriertes JavaScript realisiert.

Schnell vs. Schnell Genug

Der Programmcode einer Hybrid-App wird also in JavaScript geschrieben und dann durch den WebView ausgeführt. Dies ist offensichtlich langsamer als Code, der quasi direkt binär „an die CPU geschickt“ werden kann, ohne das irgendwelche Zwischenschritte nötig sind.

Befürworter von Hybrid-Apps führen ein wichtiges und richtiges Argument ins Feld: Ein Programm muss nicht schnell sein, es muss schnell genug sein. D.h. heutige Hardware ist oft so schnell, dass es sich lohnt, in einer weniger schnellen Sprache zu entwickeln, wenn dadurch die Entwicklungskosten sinken und man z.B. in höherer Qualität (weniger Bugs, mehr Features) entwickeln kann. Wenn ich also durch eine Hybrid-App mehr Bang-For-The-Buck bekomme, aber die langsamere Performance als User gar nicht merke, sollte ich das machen. Die Frage ist also: Sind Hybrid-Apps schnell genug?

Sind Hybrid-Apps Schnell Genug ?

Nein. Selbst wenn unter gewissen Bedingungen (JIT-Compiler, siehe unten) diese um einen Faktor fünf an eine native iOS App heran kommen können, bedeutet dies immer noch, das man 80% der Performance seines Gerätes durch den Schornstein jagt. Was sind die Gründe dafür?

Garbage Collection

Ein Computerprogramm (also auch eine App) braucht Speicher, in dem Daten und das Programm selber abgelegt werden. In manchen Programmiersprachen ist es die Aufgabe des Programmierers zu entscheiden, wann der Speicher, den das Programm braucht, wieder für andere Programme freigegeben werden kann. In anderen Sprachen wird dies automatisch durch einen sogenannten „Garbage Collector“ erledigt. Das ist zwar sehr bequem, hat aber einen Nachteil: Wenn der Garbage Collector läuft, muss das Programm angehalten werden. Dies ist auf Desktop oder Server Systemen, auf denen i.d.R. reichlich Speicher vorhanden ist, kein Problem und führt kaum zu Performanceverlust. Auf mobilen Geräten sieht die Sache schon anders aus. JavaScript erledigt Speicherverwaltung ebenfalls mit einem Garbage Collector, so dass eben jene Performanceprobleme (Anhalten der App) unter JavaScript auftreten.

Threading

Ein weiteres Problem ist Threading – die „Nebenläufigkeit“. Sobald eine App etwas anspruchsvoller werden soll, müssen Dinge gleichzeitig geschehen: Eine komplexe Anfrage an die eingebaute SQLite kann z.B. einige Sekunden dauern, währenddessen soll die App nicht einfrieren.

Hierfür gibt es sogenannte Threads (vom englischen „Faden“) – „Handlungsstränge“, die parallel abgearbeitet werden. Nun ist das Ausführungsmodell (die Regeln, wie das Skript interpretiert wird) von JavaScript per Definition Single-Threaded. Selbst wenn JavaScript blitzschnell wäre: es ist nicht möglich, nebenläufige Aktionen auszuführen. Wenn der JavaScript-Kuchen redet, sind die JavaScript-Krümel leise!

Jede Hybrid-App, die mehrere Dinge parallel tun soll, steht hier also vor einem enormen Problem.

Keine JavaScript-JIT-Beschleunigung

Es gibt ein Argument für JavaScript-Entwicklung, das immer gerne (zurecht) zitiert wird: der Fortschritt bei sogenannten JIT-Compilern. JIT steht für „Just In Time“. Hierbei handelt es sich um eine Technik, bei der wichtige Stücke des JavaScript Codes gerade rechtzeitig vor der Ausführung in echten Maschinencode übersetzt werden. Hierdurch ergeben sich in modernen Browsern (also alles außer IE < 9) enorme Geschwindigkeitsverbesserungen.

Das ist ein starker Punkt für Hybride Apps. Leider ist JIT-Kompilation unter iOS und Android nur für den Browser aktiv. Mit WebViews und damit Hybrid-Apps ist diese Beschleunigung abgeschaltet. Jede Hybrid App hangelt sich also stückchenweise von JavaScript Befehl zu Befehl, parst ihn, checkt, ob die Syntax OK, ist, und führt ihn dann aus.

Selbst mit JIT ist JavaScript immer noch ein gutes Stück von nativer Performance entfernt – und ohne? Button tappen, Kaffee holen, der App beim Arbeiten und Akku leeren zusehen.

JavaScript: dynamisch typisiert

JavaScript ist im Gegensatz zu Objective-C und Java eine sogenannte „dynamisch typisierte“ Programmiersprache. Was heißt das? Nun, das heißt das man in JavaScript sprichwörtlich Äpfel mit Birnen vergleichen kann – noch schlimmer: ich kann eine Birne haben, die in Wirklichkeit ein Apfel ist.

Ein Beispiel: Wenn ich in meinem Programm einen Wert habe, z.B. einen Rechnungsbetrag und den Nachnamen eines Kunden, dann haben diese Werte unterschiedliche Typen. Der Rechnungsbetrag ist eine Zahl, der Nachname des Kunden eine Zeichenkette. Sogenannte statisch typisierte Sprachen speichern diese Werte nun genau so, wie es für den Wert am besten ist. Dies ist bei einer dynamischen Sprache nur schwer möglich. D.h. selbst wenn ein JIT-Compiler für JavaScript verfügbar ist, kann er nicht so stark optimieren, weil ihm Wissen fehlt. Zudem müssen bei dynamisch typisierten Sprachen Werte in speziellen Containern hinterlegt werden (boxing) was wieder Speicher- und Performaceverlust und mehr Arbeit für den Garbage Collector bedeutet.

Probleme mit der Grafik-Hardwarebeschleunigung

Alle iOS und neuere Android Devices (> 3.0) führen Grafikoperationen (Linien zeichnen, Formen mit Farbe füllen, Alpha-Blending etc.) hardwarebeschleunigt aus. D.h. der im Gerät eingebaute Grafikchip übernimmt das Zeichnen, der Code gibt nur kurz den Befehl dazu. Die Pixel werden von der Hardware gesetzt. Leider klappt das unter Android nicht mit WebViews (https://code.google.com/p/android/issues/detail?id=25722, https://code.google.com/p/android/issues/detail?id=17352).

Man hat also die Wahl zwischen Flackern (hässlich) oder keiner Hardwarebeschleunigung (langsam).

Auch unter iOS ist das Thema Hardwarebeschleunigung in WebViews kein leichtes: http://indiegamr.com/ios6-html-hardware-acceleration-changes-and-how-to-fix-them/ Während ich bei nativer Programmierung einfach Hardwarebeschleunigung für meine Komponente an- oder ausschalten kann, muss ich bei der Web Entwicklung sehr gut auf die Auswahl meiner CSS Attribute achten. Schnell schleicht sich ein falsches CSS-Attribut ein, und ich habe auf einmal ein DOM Element, dass nicht beschleunigt gezeichnet wird – oops.

Keine natives User Interface

Alle Hybrid-Frameworks müssen sämtliche Bedienelemente (Buttons, Spinner, Listen etc. pp.) mit HTML nachbauen. Man hat also keinen Button, sonder ein <div /> (o. ä.), das per CSS-Styling das Aussehen eines „echten“ Buttons bekommt. Nun haben wir uns aber schon für den Fall eines simplen Buttons die erste Verzögerung in der Reaktion der Benutzeroberfläch eingehandelt: Ein nativer Button des Frameworks weiß, dass er nur geklickt (oder besser getappt) werden kann. Verlässt der Finger den Button wieder kann dieser sofort ein „Event feuern“, also Aktionen im Programm auslösen. Das HTML-Div weiß nicht, dass es ein Button ist. Es wartet einen Moment, ob nicht ein zweiter Tap kommt, so dass es statt einem „Klick“-Event ein „Double-Klick“-Event feuert. Laut Google sind das ungefähr 300 ms! Also bevor die WebApp bei etwas so einfachem wie einem Klick überhaupt anfängt etwas zu tun, ist die native App schon lange fertig

The problem with this approach is that mobile browsers will wait approximately 300 ms from the time that you tap the button to fire the click event. The reason for this is that the browser is waiting to see if you are actually performing a double tap. (https://developers.google.com/mobile/articles/fast_buttons)

One Look to Rule Them All, And In The Darkness Bind Them

Eines der wichtigsten Argumente für Hybride Apps ist, dass man nur einmal Programmieraufwand hat, um eine App auf allen Plattformen (iOS, Android, Windows Phone, Blackberry) zu veröffentlichen. Der Vorteil sei, dass die App überall gleich aussieht.

Dies ist allerdings genau ein Argument gegen Hybride Apps. Eine Android-App, die wie eine iOS App aussieht, ist keine Android App. Die Plattformen haben unterschiedliche Bedienkonzepte, unterschiedliche UI-Elemente, ein anderes Look’n’Feel … Die Hybrid-Frameworks arbeiten alle nach dem gleichen Prinzip: die iOS-Bedienelemente werden durch HTML/JS – Widgets nachgebaut. Die aus diesen Widgets zusammengebaute Webseite wird dann auf dem Gerät „abgespielt“, egal ob es sich um ein Apple oder Samsung Gerät handelt.

Auf dem Desktop wäre ein Windows-User sehr über ein Programm im Mac OS X Stil verwundert, dass sein Menü nicht unter dem oberen Fensterrahmen anzeigt, sondern im Start-Menü. Was aber auf dem Desktop ein offensichtlicher Bug wäre, wird mobil als Feature verkauft?

Mer losse d’r DOM in Kölle

Ein weiteres K.O. – Kriterium ist das DOM – das Document-Object-Model. Dies ist die Baum-Datenstruktur, die jeder Webseite – und somit auch jeder Ansicht in einer Hybrid-App – zugrunde liegt. Sie wird durch die geschachtelten HTML-Elemente gebildet, aus denen eine Webseite aufgebaut ist.

Dieses DOM ist sehr umfangreich und wird – für die Zwecke einer App – zu ineffizient im Speicher gehalten. Jede Aktion in einer Hybrid-App-Benutzeroberfläche bedeutet eine Modifikation dieser teilweise sehr tief geschachtelten Baum-Struktur.

Nun – „If your only tool is a hammer all your problems look like nails.“ Wie wir sehen, ist es durchaus möglich GUIs aus dem DOM zu bauen. Allerdings geht dies wieder auf Kosten der Performance – man hat nicht die Möglichkeiten, der nativen Layoutsysteme, die von Apple & Google darauf getrimmt wurden, schnell und flüssig zu funktionieren.

Moment: Java hat aber auch viele der Eigenschaften von JavaScript!

Das stimmt. Java hat einen Garbage Collector, unter bestimmten Bedingungen boxt Java sogar Werte! Das ist u.a. ein Grund, warum ältere Android Versionen im Vergleich zu ihren iOS Pendants langsamer und träger wirken: die Apps werden immer wieder kurz unterbrochen, um den Garbage Collector anzuwerfen und Speicher freizuschaufeln.

Warum dann nicht zumindest unter Android JavaScript nehmen? Nun, die anderen Nachteile habe ich immer noch: Probleme mit der Grafikbeschleunigung, das DOM, keine nativen UI-Komponenten, kein Zugriff auf die Hardware.

Für äußerst performance-kritischen Code muss ich unter Java in der Tat einigen Aufwand in Kauf nehmen, damit der Garbage Collector „ruhig bleibt“. Auch wenn es schwer ist, ist es in Java zumindest möglich. In JavaScript wird schon z.B. für das Ergebnis einer Addition ein neues Number Objekt erzeugt, das vom Garbage Collector aufgeräumt werden muss. Man hat also gar keine Chance kritische Bereiche des Codes anzupassen.

Nicht zuletzt muss man bedenken, das Google einen enormen Aufwand darin steckt, den Java Compiler und Garbage Collector so effizient wie möglich zu gestalten (was in Android 4 auch deutlich Wirkung zeigt). JavaScript in WebViews hat hier für Google keine Priorität.

Andere Quellen

Eine enorm umfangreiche, dafür technisch wesentlich anspruchsvollere Übersicht über das Thema gibt es in diesem diesem Artikel: http://sealedabstract.com/rants/why-mobile-web-apps-are-slow/. Dort wird insbesondere das Geschwindigkeitsproblem mit vielen Quellen detailliert dargelegt.

P.S.

Nachtrag: Als Geschäftsführer einer Firma für native mobile Apps mag ich etwas voreingenommen sein. Allerdings habe ich ebenfalls über ein Jahrzehnt Web-Entwicklung hinter mir. Daher war ich über die Möglichkeit, Apps mit HTML 5 und JavaScript zu erstellen zunächst sehr erfreut. Wäre es eine tatsächliche Alternative für qualitativ hochwertige Apps, würden wir in unserer Firma längst Hybrid-Entwicklung anbieten. Insbesondere, da ich sehr gerne funktional JavaScript programmiere. Leider ist diese Technologie, zumindest in den nächsten drei bis fünf Jahren keine Alternative zur nativen Entwicklung, zumindest wenn eine reaktive, anspruchsvolle und professionelle App gewünscht ist.

(Titelbild: © bloomua – Fotolia.com)

Christoph Henkelmann 1 post

Seit 1999 programmiert Christoph Henkelmann Software für Server, Desktops
und mobile Geräte. Er studierte Informatik und Musikwissenschaft in Bonn
und begann seine Karriere als Entwickler im Bereich E-Commerce. Im Jahr 2012
gründete er zusammen mit Marko Tosic die Firma TheAppGuys.

4 Kommentare

  • […] bedanken wir uns bei den AppGuys, Marko und Christoph, der einen großartigen Gastartikel für uns geschrieben hat. Wenn ihr mal eine App braucht, das sind eure […]

  • Jeanny Carter (3 Jahren ago) Reply

    Lieber Christoph Henkelmann,

    vielen Dank fuer diesen aufschlussreichen Beitrag. Bisher haben auch wir uns Gedanken um die Entwicklung einer hybriden App gemacht. Er hat uns bei unserer Entscheidung sehr geholfen.

  • Andy (3 Jahren ago) Reply

    Hallo,
    erst einmal vielen Dank für diesen interessanten Beitrag. Ich suche schon seit einiger Zeit nach Pro und Contras in Bezug auf hybride und native Applikationen, nur leider findet man wenig grundlegendes sondern eher oberflächliches „Geschwafel“ bei dem eine These aufgestellt, diese aber nicht belegt oder begründet wird.
    In diesem Artikel sieht das tatsächlich anders aus. Jede Aussage wird durch Beispiele, andere Artikel und Aussagen Dritter untermauert. Egal ob Pro oder Contra.
    Ich möchte mich nochmals für diesen Einblick bedanken.

    Andy

  • Sebastian Vollmer (1 Jahr ago) Reply

    Hallo Herr Henkelmann,
    Leider bin ich erst heute, fast 3 Jahre nach Veröffentlichung, auf diesen Artikel gestossen.
    Da auch ich ein Verfechter von nativen Apps bin und immer wieder gegen die oberflächlichen Standardargumente der Hybrid-Verkäufer (Nativ=doppelter Aufwand etc) argumentieren muss, hat mir Ihr Artikel sehr geholfen.
    Die Frage ist, ob Sie das heute drei Jahre später immer noch so sehen.
    Gruss, Sebastian Vollmer

Leave a Reply

Rules of the Blog
Do not post violating content, tags like bold, italic and underline are allowed that means HTML can be used while commenting. Lorem ipsum dolor sit amet conceur half the time you know i know what.

Loading Facebook Comments ...

No Trackbacks.