Du hast deinen AdBlocker an?

Es wäre ein Traum, wenn du ihn für t3n.de deaktivierst. Wir zeigen dir gerne, wie das geht. Und natürlich erklären wir dir auch, warum uns das so wichtig ist. Digitales High-five, deine t3n-Redaktion

t3n 46

Progressive Web-Apps mit Angular 2 entwickeln: Ist das Ende der App-Stores in Sicht?

    Progressive Web-Apps mit Angular 2 entwickeln: Ist das Ende der App-Stores in Sicht?

(Screenshot: Google)

Mitte 2015 prägte Google den Begriff der „Progressive Web App“ (PWA). Seitdem steigt das Interesse an den Web-Apps stetig. Ein Einstieg mit Praxis-Demo mit einem Überblick über die wichtigsten Werkzeuge.

Nein, eine PWA ist keine neue Technologie. Eine PWA ist vor allem eine App mit besonderen Kennzeichen. Google [1] beschreibt diese mit „progressive“, „responsive“, „connectivity independent“, „app-like“, „fresh“, „safe“, „discoverable“, „re-engageable“, „installable“ und „linkable“. Damit PWAs diese Eigenschaften haben, braucht es den Einsatz verschiedener Technologien – sowohl bewährte, als auch neue und noch nicht weit verbreitete. Diese sind zum Teil aber auch bereits in ganz normalen Web-Applikationen zu finden, etwa die Notification-API [2] oder die Fetch-API [3]. Anders als webbasierte Cross-Plattform-Applikationen, die Entwickler zum Beispiel mit Apache Cordova erstellen, benötigen PWAs keinen nativen Container. Anwender können sie direkt im Browser ihres Gerätes ausführen und speichern. Dabei haben die PWAs Zugriff auf native APIs, sodass Entwickler keine nativen Gegenparts programmieren müssen. Für PWAs kommen nur HTML5, CSS3 und JavaScript oder Sprachen zur Anwendung, die zu JavaScript transpilieren, etwa TypeScript.

Mit Single-Page-Application-Frameworks (SPA) – wie Angular 2 oder React – erstellte Apps geben Benutzern das Gefühl, eine native Applikation zu verwenden. Der Rahmen der Applikation baut sich dabei jedoch nur einmal auf. Anschließend tauschen sich nur die Daten innerhalb dieses Rahmens aus – eine echte Navigation wie bei einer klassischen Website entfällt.

Als Beispiel dient im Folgenden die für diesen Artikel erstellte Demo-Applikation „PWA Books“ [4] (Download). Sie besitzt die zuvor genannten Eigenschaften einer Progressive Web App und basiert auf Angular 2.

Die App-Shell

Basis der App „PWA-Books“ ist eine HTML-Datei mit zugehörigem CSS, die eine minimale Benutzeroberfläche bereitstellt. Google bezeichnet dieses Gerüst als App-Shell [5]. Die Gestaltung findet mit Hilfe des CSS-Framework „Materialize“ statt, die die App responsive macht. Entwickler können auch andere Frameworks verwenden. Doch die Kombination von Materialize und Angular ist eine gute Wahl, um ein möglichst natives App-Gefühl („app-like“) zu erreichen.

Service Worker

Ein weiteres Hilfsmittel für PWAs sind die eigenständigen Skripte „Service Worker“ [6], die im Hintergrund laufen, auch wenn die Applikation nicht geöffnet ist. So können sie beispielsweise Push-Nachrichten empfangen. Ist ein Service Worker installiert und aktiviert, übernimmt er die Kontrolle über die Ausführung der Applikation und schaltet sich gewissermaßen als Proxy zwischen Browser und Anwendung. Entwickler können Service Worker nur mittels sicherem HTTPS nutzen – allein „localhost“ ist hier eine Ausnahme, um die Entwicklung zu vereinfachen. So lässt sich die PWA-Eigenschaft „safe“ sicherstellen.

Derzeit unterstützen nur die Browser Google Chrome und Mozilla Firefox die Service Worker, was deren Nutzung – und somit auch die Verbreitung von PWAs – leider doch ziemlich einschränkt. Für den Browser Microsoft Edge [7] sind die Service Worker gerade in der Entwicklung. Apple hat sie für Safari [8] bislang lediglich angedacht.

Entwickler, die einen Service Worker nutzen möchten, müssen beim Service-Worker-Container des Browsers eine JavaScript-Datei registrieren, die diesem alle Inhalte für die Skripte bereitstellt.

JavaScript-Datei registrieren

if ('serviceWorker' in navigator) {
 navigator.serviceWorker.register('./serviceWorker.js')
 ... 
}

Listing 1

Fehlt dieser Container, lässt sich der Service Worker nicht registrieren und die PWA muss ohne die erweiterten Funktionen auskommen. Das heißt, dass die Anwender dann die Applikation zwar mit ihren Grundfunktionen nutzen können, doch auf die zusätzlichen Features verzichten müssen. Diese stehen nur Nutzern mit entsprechenden Browsern zur Verfügung.

Die App-Shell der Demo „PWA Books“: Eine HTML-Datei mit CSS, die eine minimale Benutzeroberfläche bereitstellt. Hier einmal ohne und einmal mit Inhalt. (Screenshot: PWA Books)

Um die Service Worker mit Angular zu kombinieren, registrieren Programmierer diese beim Start der Anwendung. Bei PWA-Books steht für den Service-Worker-Service die Methode „register()“ bereit, die die PWA beim Start aufruft.

ServiceWorkerService mit register() starten

constructor(private _serviceWorker: ServiceWorkerService, ...) {
 _serviceWorker.register();
}

Listing 2

Der Start der Anwendung löst nun die Installation und Aktivierung der Service Worker aus – oder besser gesagt die der Datei „serviceWorker.js“, welche den nötigen Code für die Service Worker enthält. Die Events „install“ und „activate“ können Entwickler innerhalb der Service-Worker-Datei registrieren, um eigene Logiken zu implementieren.

Eigene Logiken implementieren

self.addEventListener('install', (event) => {});
self.addEventListener('activate', (event) => {});

Listing 3

„self“ beschreibt dabei den Scope [9] des Service Workers, auf dem dessen Funktionen zur Verfügung stehen. Der Service Worker ist die Grundlage, um weitere PWA-Eigenschaften wie „connectivity independent“ zu erfüllen. Doch dazu später mehr.

Installierbare Web-App

Damit sich eine App installieren lässt und somit eine weitere PWA-Eigenschaft erfüllt (installable), benötigen Entwickler noch Meta-Informationen. Hierfür können sie eine „manifest.json“-Datei mit Informationen wie Titel, Beschreibung oder Pfade zu Icons hinterlegen – also auf dem standardisierten Web-App-Manifest aufsetzen. Dieses lässt sich wie eine normale Ressource in die index.html einbinden. Mit Hilfe dieser Manifest-Datei können beispielsweise Google-Chrome-Nutzer die App auf ihrem Home-Bildschirm als eigenständige Applikation hinzufügen. In Firefox ist dies aktuell nur über die Entwickler-Tools möglich.

Um dieses Feature unter iOS oder Microsoft-Windows-Phone zu nutzen, müssen Developer die index.html weiter anpassen, da sie in diesen Fällen ihre Informationen nicht aus der manifest.json bezieht. Zudem unterstützen die Plattformen Service Worker noch nicht, sodass die Nutzer nur auf die Web-Instanz verlinken, aber die App nicht wirklich installieren können.

PWAs zeichnen sich etwa dadurch aus, dass sie sich auf dem Home-Screen installieren lassen und auch im Offline-Modus funktionieren. (Screenshot: PWA Books)

PWAs zeichnen sich etwa dadurch aus, dass sie sich auf dem Home-Screen installieren lassen und auch im Offline-Modus funktionieren.

Push-Nachrichten

PWAs bieten einen weiteren Vorteil: Push-Nachrichten. Damit erfüllen sie auch die Eigenschaft „re-engageable“. Das heißt, die App-Nutzer erhalten Updates, auch wenn diese nicht aktiv ist, und können mit einem Klick oder Touch auf die Benachrichtigung erneut in Interaktion mit der Anwendung treten – wie bei nativen Apps. Dafür nutzen Entwickler die Push-API [10], die derzeit jedoch nur Chrome (für Android) und Firefox unterstützen. Die Push-API müssen Entwickler bei der Installation des Service Workers beim PushManager registrieren.

Push-API registrieren

serviceWorkerRegistration.pushManager
 .subscribe()
 .then((endpoint) => { ... });

Listing 4

Dabei erhalten sie als Endpunkt eine URL vom Browser, die sie nutzen können, um Push-Nachrichten zu versenden. Da App-Betreiber natürlich nicht jede Nachricht manuell senden wollen, sollten Developer das Aufrufen der Endpunkte – es gibt verschiedene Endpunkte je Browser – im Server-Teil der Anwendung durchführen.

Um die Push-Nachrichten im Browser empfangen und anzeigen zu können, registrieren Entwickler einen Event-Listener im Service Worker, den jeder Push aufruft. Aber Achtung: Ohne einen Endpunkt, also einen Server-Teil, erhält der Nutzer auch keine Push-Nachrichten – selbst wenn der EventListener registriert ist.

EventListener registrieren

self.addEventListener('push', (event) => {});

Listing 5

Empfängt die PWA eine Nachricht, zeigt sie diese dem App-Nutzer auf dem Smartphone oder im Browser an. Den Titel, das Icon und den Text der Benachrichtigung können Entwickler selbst bestimmen.

Benachrichtigung einrichten

self.registration.showNotification('Notification', {
 body: 'You received a notification.',
 icon: 'resources/launcher-icon-144.png'
}));

Listing 6

Um eine Push-Nachricht auszulösen, schickt der Server der Applikation eine Nachricht an den Notification-Dienst, der die eigentliche Push-Nachricht abschickt. Theoretisch hat hierfür jeder Browser seinen eigenen Notification-Dienst. Praktisch unterstützen bisher nur Chrome und Firefox diese Funktion. Die Demo „PWA Books“ sendet Push-Nachrichten unter Google Chrome und nutzt hierfür die Messaging-Lösung „Firebase Cloud Messaging“ [11].

App im Offline-Modus

Ist die Internet-Verbindung schlecht oder nicht vorhanden, lassen sich PWAs auch im Offline-Modus nutzen. Service Worker überwachen dabei den Datenverkehr zwischen Applikation und Netzwerk. Somit können Entwickler ein Cache dazwischenschalten. Anfragen gehen dann nicht direkt an das Netzwerk weiter, sondern beziehen ihre Antworten aus dem Cache. Dazu registrieren Developer in der Service-Worker-Datei einen neuen Event-Listener, der auf das fetch-Event [12] reagiert.

Event-Listener registrieren

self.addEventListener('fetch', (event) => {});

Listing 7

Das fetch-Event führt alle Anfragen an das Netzwerk aus. Doch damit Anfragen an den Cache Antworten erhalten, muss dieser gefüllt sein. Dabei stellt sich zunächst die Frage, was für ein Cache sinnvoll ist. Die Service Worker stellen einen oder mehrere Caches zur Verfügung, die darauf ausgelegt sind, Netzwerkanfragen und -antworten zu speichern und diese auch wieder auszugeben. Damit der Cache weiß, welche Anfragen er speichern soll, definiert ein Entwickler dies bei der Installation eines Service Worker.

Dazu öffnet er einen Cache und fügt alle definierten Anfragen hinzu. Damit die Applikation offline startet, erhält „PWA Books“ alle Dateien, die diese benötigt – also HTML-, CSS- und auch alle JavaScript-Dateien von Angular, die eigene Applikation eingeschlossen. Ist der Cache gefüllt, müssen Entwickler im fetch-Event festlegen, wie die App mit Netzwerk-Anfragen umgehen soll. Eine gute Strategie ist der „Cache, falling back to network“-Ansatz [13], bei der die App versucht, jede Anfrage erst einmal direkt aus dem Cache zu beantworten. Erst wenn dort kein Eintrag dazu vorhanden ist, leitet sie die Anfrage ans Netzwerk weiter.

Doch was ist mit Anfragen an den Serverteil der Anwendung? Was ist mit den Daten der App? Da diese nicht im Cache sind, gehen diese Anfragen immer noch direkt an das Netzwerk. Um diese Abhängigkeit vom Netzwerk zu unterbinden, könnten Entwickler solche Abfragen ebenfalls in den Cache laden. Doch dies würde immer nur den aktuellen Stand aus dem Cache liefern. Es wäre nicht möglich, Daten zu verändern, da sich die Datenmenge – also die gespeicherten Anfragen und Antworten – nicht manipulieren lässt.

Der „Cache, falling back to network“-Ansatz: Die App versucht jede Anfrage erst einmal direkt aus dem Cache zu beantworten. Erst wenn dort kein Eintrag dazu vorhanden ist, leitet sie die Anfrage ans Netzwerk weiter. (Screenshot: First Then Network)

Der „Cache, falling back to network“-Ansatz: Die App versucht jede Anfrage erst einmal direkt aus dem Cache zu beantworten. Erst wenn dort kein Eintrag dazu vorhanden ist, leitet sie die Anfrage ans Netzwerk weiter.
Es gibt allerdings eine Alternative. Entwickler können die Daten komplett in der App speichern und sie nur periodisch oder manuell mit dem Server synchronisieren. Die Demo „PWA Books“ verfährt so. Sie hält exemplarisch alle Daten im LocalStorage und synchronisiert diese nur mit dem Server, wenn der Benutzer den Button „Sync“ betätigt. Dann geht die Liste der lokalen Daten an den Server. Dieser kombiniert sie mit den gespeicherten Daten und schickt die neue Liste zum Client zurück, der sie im LocalStorage ablegt. In der Praxis ist der LocalStorage hier jedoch nur bedingt zu empfehlen, da dieser ein Speicher-Limit hat und nur kleine Datenmengen halten kann.

Zu beachten ist, dass der Service-Worker-Cache keine Caching-Probleme löst, sondern lediglich die Möglichkeit für Caching bietet. Jeder PWA-Entwickler sollte sich daher direkt zu Beginn der App-Entwicklung Gedanken zum Thema „Caching und Offline-Verfügbarkeit“ machen: Welche Strategie passt beispielsweise, um mit Synchronisationskonflikten umzugehen?

Auf http://pwa.rocks gibt es bereits etliche Beispiele für Progressive Web Apps. (Screenshot: pwa.rocks)

Auf http://pwa.rocks gibt es bereits etliche Beispiele für Progressive Web Apps.
Da PWAs die Eigenschaften „installable“ und „connectivity independent“ haben und demnach also auch offline verfügbar sein sollen, ist es zu empfehlen, nach dem „Offline First“-Prinzip vorzugehen. Dies bedeutet, dass sie sich zuerst Gedanken um das Thema Offline macht und dann alle Anwendungsfälle daran orientiert.

In der Demo erfolgt die Auslieferung der App selbst und auch die Kontrolle der Daten in der App über den Service Worker und komplett offline. Im Offline-Modus beantwortet der Service Worker die Anfrage nach Applikations-Dateien aus dem Cache und die App die nach Daten aus dem LocalStorage. Natürlich gibt es immer wieder Anfragen, die trotzdem nicht funktionieren, etwa die Synchronisation oder der Empfang von Push-Nachrichten. Doch Entwickler können diese so auf ein Minimum reduzieren.

Fazit und Ausblick

Die Demo „PWA Books“ zeigt, mit wie wenig Aufwand Entwickler aus einer kleinen Web-App eine PWA erstellen können, die sich installieren und offline nutzen lässt sowie Push-Nachrichten liefert. PWAs fühlen sich an wie native Apps. Doch leider unterstützen noch nicht so viele Browser die Progressive Web Apps, dass man sie flächendeckend einsetzen könnte.

Die Tatsache, dass Entwickler mit PWAs nicht mehr auf die App-Stores für die Installation ihrer Apps angewiesen sind, legt die Vermutung nahe, dass sich Hersteller mobiler Browser wohl noch etwas gegen die Implementierung der für PWAs notwendigen Technologie sträuben – schließlich müssten sie auf Einnahmen verzichten. Bis dahin können Entwickler ihre Apps eben nur nach und nach sinnvoll durch Funktionen erweitern, die dann eben nur den Nutzern bestimmter Browser zur Verfügung stehen – etwa unter Chrome für Android.

Doch auch die Framework-Entwickler arbeiten daran, die Umsetzung von Progressive Web Apps zu vereinfachen. Google entwickelt derzeit zum Beispiel ein Mobile-Kit für Angular, das ein Template für PWAs zur Verfügung stellen soll. Auch für die Arbeit mit Service Worker hat Google bereits Tools [14] veröffentlicht. Die derzeit vermutlich beste Option, eine Web-Anwendung auf mobile Geräte zu bringen, dürfte Apache Cordova sowie Electron für Desktop-Geräte sein. Die Zukunft wird zeigen, ob Hersteller mobiler Browser mit der Entwicklung mitgehen – oder warten, bis sie ein Konzept gefunden haben, um ihre Einnahmen aus den App-Stores auf PWAs zu übertragen.

Steffen Jahr
Steffen Jahr

begeistert sich für Apps im Web und auf mobilen Endgeräten. Durch seine Arbeit als Softwareentwickler bei der Thinktecture AG kann er diese Begeisterung ausleben und entwickelt dort Cross-Plattform-Lösungen mit HTML5 und JavaScript. Ihr könnt Steffen auf Twitter (@steffenjahr) oder auf seinem Blog https://steffenjahr.de erreichen.

Links und Literatur

  1. PWA-Eigenschaften
  2. Notification API
  3. Fetch-API
  4. PWA Books
  5. App Shell
  6. Service Worker
  7. Service Worker für Edge
  8. Service Worker für Safari
  9. Scope des Service Worker
  10. Push-API
  11. Firebase Cloud Messaging
  12. fetch-Event
  13. Cache, falling back to network
  14. Service Worker Library

Finde einen Job, den du liebst

Bitte melde dich an!

Du musst angemeldet sein, um einen Kommentar schreiben zu können.

Jetzt anmelden

Hinweis

Du hast gerade auf einen Provisions-Link geklickt und wirst in Sekunden weitergeleitet.

Bei Bestellung auf der Zielseite erhalten wir eine kleine Provision – dir entstehen keine Mehrkosten.


Weiter zum Angebot