Lesezeit 8 Minuten

Progressive Web Apps (PWA) sind ein webbasiertes, plattformübergreifendes Anwendungsmodell: Dieser Typ Anwendung wird exakt einmal auf Basis moderner Webtechnologien entwickelt und kann danach nicht nur in den gängigen Webbrowsern ausgeführt, sondern auch auf diversen Mobil- und Desktopbetriebssystemen installiert werden. Vom Homebildschirm oder aus der Programmliste heraus gestartet, werden diese Anwendungen vollflächig, beziehungsweise in einem eigenen Fenster angezeigt und unterscheiden sich somit nicht von ihren nativen Gegenstücken. Insgesamt bietet sich das Anwendungsmodell für all diejenigen an, die sich keine mehrfache Entwicklung derselben App für unterschiedliche Plattformen leisten können oder wollen.

Abbildung 1 - Progressive Web Apps mit Angular - „Nur“ eine Web-App: Die Twitter-PWA läuft in ihrem eigenen Fenster, mit Dark-Mode und Dock-Icon samt Notification-Badge

„Nur“ eine Web-App: Die Twitter-PWA läuft in ihrem eigenen Fenster, mit Dark-Mode und Dock-Icon samt Notification-Badge

Hier auf dem Host-Europe-Blog haben wir Ihnen vor einigen Monaten die Entwicklung von Progressive Web Apps mit React vorgestellt. Aus Sicht der Progressive Web Apps ist es unerheblich, mit welchem Framework die jeweilige App entwickelt wird. Somit kommt auch Angular infrage, das beliebte Single-Page-App-Framework von Google. Gemeinsam mit Microsoft treibt Google das PWA-Modell stark voran. Daher verwundert es kaum, dass auch für Angular eine Unterstützung für Progressive Web Apps verfügbar ist. Der PWA-Support ist zwar nicht standardmäßig aktiviert, lässt sich aber im Handumdrehen einschalten – auch für bestehende Projekte. Dazu wird auf der Kommandozeile der folgende Angular-CLI-Befehl ausgeführt:

ng add @angular/pwa

Typischerweise definiert man Progressive Web Apps anhand von zehn Eigenschaften, an denen sich der folgende Blogpost orientiert. Die oben genannte PWA-Unterstützung für Angular setzt manche dieser Eigenschaften schon um, bei anderen müssen Entwickler aktiv werden. Manche Punkte sind harte Anforderungen, andere eher weiche Faktoren. Schauen wir rein!

Progressive

Das Wort „Progressive“ steckt bereits im Namen des Anwendungsmodells: Diese Eigenschaft besagt, dass Progressive Web Apps, ausgeführt in älteren Webbrowsern wie zum Beispiel dem Internet Explorer 11, nicht brechen sollen. Dieser Browser versteht weder die PWA-Schnittstellen noch andere moderne Web-APIs. Wenn die Anwendung grundsätzlich aber auch in älteren Browsern laufen kann, etwa wenn sie primär eine Forms-over-Data-Anwendung ist, sollte die Verwendung moderner Schnittstellen aber nicht dazu führen, dass die Anwendung in älteren Browsern bricht.

Um die Unterstützung älterer Browser sicherzustellen, gibt es das Prinzip des Progressive Enhancement. Hierbei wird zunächst geprüft, ob der Webbrowser eine bestimmte Schnittstelle unterstützt, bevor sie genutzt wird. In Webbrowsern ohne Unterstützung käme es andernfalls zu einem Fehler. Die Angular-PWA-Unterstützung kümmert sich bereits um das Progressive Enhancement in Bezug auf die PWA-Schnittstellen. Werden innerhalb der Anwendung andere Webschnittstellen verwendet, muss sich der Entwickler selbst darum kümmern.

Glücklicherweise geht es beim Progressive Enhancement nur um eine Verzweigung: Wird die API unterstützt, wird sie verwendet. Andernfalls kann die Funktion in der Benutzeroberfläche versteckt werden, oder es wird eine Fallback-Methode genutzt. So könnte es etwa bei der Web Share API funktionieren, die unter Chrome auf Android sowie Safari unter iOS und macOS den nativen Teilen-Dialog des Betriebssystems anzeigt. Auf anderen Systemen gibt es die API derzeit nicht. Steht die share()-Methode auf dem navigator-Objekt zur Verfügung, wird sie aufgerufen, andernfalls wird auf das weitaus besser unterstützte Mailto-Protokoll zurückgegriffen, welches das E-Mail-Programm öffnet:

if ('share' in navigator) {
navigator.share({ text: 'Hello' });
} else {
window.open('mailto:?body=Hello');
}

Progressive Enhancement am Beispiel der Web Share API

Responsive

Damit Progressive Web Apps mit Angular ihr Versprechen einlösen können, vom Smartphone bis zum 4K-Bildschirm sinnvoll zu funktionieren, muss sich das Layout der Anwendung an die verfügbaren Bildschirmabmessungen anpassen. Dieses Problem wurde im Web schon lange gelöst: durch responsive Webdesign. Es gibt viele Bibliotheken, die ein responsives Layout umsetzen, etwa Bootstrap oder Foundation. Im Angular-Umfeld bietet sich außerdem Angular Material an. Diese quelloffene Bibliothek wird von Google herausgegeben und implementiert das aus Android bekannte Material Design zur Verwendung in Angular. Neben dem responsiven Layout enthält diese Bibliothek auch viele Steuerelemente, wie Datepicker oder Grids. Um Angular Material zu installieren, wird folgender CLI-Befehl ausgeführt:

ng add @angular/material

App-like

Die Eigenschaft „app-like“ besagt, dass Progressive Web Apps mit Angular so aussehen und sich verhalten sollen wie native Apps auch. Das schließt unter anderem Navigationskonzepte mit ein: Sidebars, Tabbed Interfaces oder andere bekannte Mechanismen sollen bei Progressive Web Apps zum Einsatz kommen. Wenn eine PWA aussieht wie eine normale Website, ist das Ziel verfehlt. App-like bedeutet allerdings nicht, dass PWAs zwangsläufig die native Gestaltung des Betriebssystems adaptieren müssen: Apps wie Spotify oder Slack zeigen, dass die eigene Corporate-Identity sinnvoll über verschiedene Plattformen verteilt werden kann, ohne dass die Benutzererfahrung darunter leidet.

Abbildung 2 - App-like: Angular Material bringt auch einen Navigationsrahmen mit sich

App-like: Angular Material bringt auch einen Navigationsrahmen mit sich

 

Connectivity Independent

Progressive Web Apps wollen mit nativen Anwendungen auf Augenhöhe konkurrieren. Daher müssen sie auch dann ausgeführt werden können, wenn der Anwender gerade offline ist. Das passiert häufig: Unterwegs im Bahntunnel, im Flugzeug oder ohne Datenroaming im Ausland. Um Websites und Webanwendungen offlinefähig zu machen, wurden die Service Worker eingeführt. Dabei handelt es sich um JavaScript-Schnipsel, die durch eine Website registriert werden können.

Nach der Registrierung übernimmt der Service Worker die Kontrolle über die Website: Er erhält Zugriff auf die ausgehenden HTTP-Anfragen der Website und kann diese selbstständig beantworten. Der Service Worker hat Zugriff auf einen Cache, in dem er HTTP-Anfragen und die zugehörigen Antworten lokal zwischenspeichern kann. Dieser Cache darf nicht mit dem HTTP-Browsercache verwechselt werden, der in unveränderter Form weiter besteht. Um eine Angular-App offlinefähig zu machen, müssen ihre Quelldateien – das sind die HTML-, CSS- und JavaScript-Dateien und Assets wie Bilder oder Videos – in diesen Cache gelegt werden. Von dort aus kann der Service Worker die zwischengespeicherten Dateien selbst im Offlinezustand auslesen. Auch bei bestehender Internetverbindung hat das Vorteile: Denn in der Regel kann der Inhalt aus dem lokalen Cache deutlich schneller bezogen werden als über das Netz. Progressive Web Apps starten somit also besonders schnell.

Abbildung 3 - Die Cache-Inhalte des Service Workers können in den Chrome Developer Tools im Bereich Application | Cache inspiziert werden

Die Cache-Inhalte des Service Workers können in den Chrome Developer Tools im Bereich Application | Cache inspiziert werden

Damit sich Entwickler nicht selbst um das Caching der Quelldateien kümmern müssen, stellt das Angular-Team eine Service-Worker-Implementierung bereit. Die Unterstützung des Projektes wurde durch die Ausführung des Konsolenbefehls vom Anfang bereits vorbereitet. Um jedoch Irritationen zu vermeiden, die sich während der Entwicklungszeit durch eine ältere, aus dem Cache ausgelieferte Anwendungsversion ergeben könnten, wird der Service Worker ausschließlich produktiven Builds der Anwendung beigefügt. Diese werden über den Befehl ng build –prod erstellt. Dieser produktive Build kann anschließend auf einen beliebigen Server hochgeladen werden.

Neben der Offlinefähigkeit der Anwendungsquelldateien beleuchtet die Eigenschaft Connectivity Independent aber auch noch einen zweiten Aspekt: Auch die strukturierten Anwederdaten, zum Beispiel Kunden- oder Artikeldatensätze, sollten offline verfügbar sein. Auch hierfür kennt das moderne Web Lösungen – konkret die lokale Browserdatenbank IndexedDB. Hier können selbst im Offlinemodus Datensätze abgelegt und beliebig modifiziert werden. Sobald die Internetverbindung wieder besteht, können die Datensätze aus der lokalen Clientdatenbank mit dem entfernten Server synchronisiert werden – also genau so, wie es native Apps auch tun würden. Allerdings bedeutet das, dass Entwickler nun die aufwendigen Themen Datensynchronisierung, Konfliktbehandlung und Datenbankmigrationen bedenken müssen. Bibliotheken wie PouchDB können allerdings dabei helfen, diese Operationen zu vereinfachen.

Fresh

Wenn die Quelldateien der Anwendung im lokalen Zwischenspeicher abgelegt werden, stellt sich die Frage, was passiert, wenn eine neue Fassung der Anwendung ausgerollt wird. Beim nächsten Aufrufen der PWA wird zunächst die im Cache hinterlegte Version geladen. Die Service-Worker-Implementierung von Angular prüft bei jedem Start der Anwendung (sofern eine Internetverbindung besteht), ob auf dem Server zwischenzeitlich eine neue Version bereitgestellt wurde. Ist das der Fall, wird die Version automatisch heruntergeladen und im lokalen Zwischenspeicher abgelegt. Beim nächsten Start der Anwendung wird dann die neue Fassung geladen.

Um den Anwender auf die Verfügbarkeit einer neuen App-Version hinzuweisen, steht in Angular der Service SwUpdate zur Verfügung. Dessen Observable available wird aufgerufen, wenn eine Aktualisierung zur Verfügung steht. Um die neue Version auszuführen, genügt es dann, die Anwendung einmal neuzuladen:

import { SwUpdate } from '@angular/service-worker';

export class AppModule {
constructor(swUpdate: SwUpdate) {
swUpdate.available.subscribe(() => {
if (confirm('Neue Version verfügbar. Neu laden?')) {
window.location.reload();
}
});
}
}

Beispielverwendung des SwUpdate-Services

Die von Angular bereitgestellte Service-Worker-Implementierung nimmt dem Entwickler sehr viel Arbeit ab, erlaubt aber nur begrenzte Konfigurationsmöglichkeiten. Wer mehr Kontrolle über den Service Worker braucht, kann das Skript auch selbst schreiben – etwa unter Zuhilfenahme der Bibliothek Workbox von Google.

Re-engageable

Service Worker können nicht nur die HTTP-Kommunikation beeinflussen, sondern auch außerhalb der Lebenszeit der eigentlichen Website ausgeführt werden. Dies erlaubt Anwendungsszenarien wie die Synchronisierung von Daten im Hintergrund oder das Senden von Pushbenachrichtigungen, ohne dass die eigentliche Webanwendung geöffnet sein muss. Beide Szenarien werden unter iOS derzeit aber nicht unterstützt. Angular erlaubt dem Entwickler, sich mithilfe des Services SwPush für die Pushkommunikation zu registrieren.

import { SwPush } from '@angular/service-worker';

export class AppComponent {
constructor(private readonly swPush: SwPush) {}

public onEnablePush() {
this.swPush.requestSubscription({
serverPublicKey: VAPID_PUBLIC_KEY
}).then(sub => this.sendToServer(sub));
}
}

 

Beispielverwendung des SwPush-Services

Um Pushbenachrichtigungen senden zu können, kommt das kostenfrei verwendbare Web-Push-Verfahren zum Einsatz, dessen Erläuterung den Rahmen dieses Blogposts sprengen würde. Eine umfassende Anleitung für den Betrieb mit Angular finden Sie hier.

Safe

Service Worker sind sehr mächtig: Sie erhalten Zugriff auf die HTTP-Kommunikation der Website, können stellvertretend für Webserver antworten und außerhalb der Lebenszeit der Website aktiv sein. Daher muss sichergestellt werden, dass das Service-Worker-Skript wirklich von der erwarteten Quelle stammt. Dazu muss die Website über eine gesicherte Verbindung, also über HTTPS übertragen werden. Dies ist auch für viele weitere moderne Webschnittstellen der Fall.

Aktuelle Webbrowser markieren Websites, die über HTTP übertragen werden, außerdem als „nicht sicher“. Für die Absicherung der Verbindung sind allerdings SSL- bzw. TLS-Zertifikate erforderlich, die bei Hostinganbietern wie Host Europe erhältlich sind. Darüber hinaus besteht die Möglichkeit, über die Initiative Let’s Encrypt kostenfreie, sich automatisch erneuernde Zertifikate zu beziehen. Für viele Anwendungs- und Serverplattformen stehen Bibliotheken bereit, die sich um den Bezug und die regelmäßige Aktualisierung des Zertifikates über Let’s Encrypt kümmern.

Discoverable

Weiterhin sollen PWAs „discoverable“ sein, also erkennbar und unterscheidbar von ganz normalen Websites. Somit können Suchmaschinenanbieter etwa eine eigene Kategorie für Web-Apps anbieten. Das Unterscheidungskriterium zwischen einer beliebigen Website und einer Webanwendung ist das Vorhandensein des sogenannten Web App Manifest – neben dem Service Worker die zweite PWA-Kerntechnologie. Diese Datei im JSON-Format enthält Metadaten zur Webanwendung, etwa ihren Titel, Symbole, Kategorien oder die Alterskennzeichnung. Typischerweise trägt die Datei den Namen manifest.json oder manifest.webmanifest. Auf sie verwiesen wird in der Hauptdatei der Webanwendung (typischerweise index.html) über das Link-Tag mit der Relation manifest. Durch die Ausführung des Angular-CLI-Befehls wurde dieses Tag automatisch hinzugefügt – samt einer vorgefüllten Manifestdatei und Beispielsymbolen, die das Angular-Logo zeigen.

<link rel=“manifest“ href=“manifest.webmanifest“>

Verweis auf das Web App Manifest

Installable

Neben der Offlinefähigkeit besteht der zentrale Sinn von Progressive Web Apps darin, dass sie sich auf dem Gerät des Anwenders installieren lassen. Je nach Webbrowser und Betriebssystem funktioniert das aus der Adresszeile heraus oder über das Browsermenü. Wichtig zu wissen ist allerdings, dass „Installation“ lediglich bedeutet, dass eine Verknüpfung zur Webanwendung auf dem Homebildschirm oder in der Programmliste abgelegt wird. Die Service-Worker-Features wie Offlinefähigkeit oder Pushbenachrichtigungen funktionieren auch rein im Browser, ganz ohne Installation. Für die Darstellung der Anwendung wird das zuvor genannte Web App Manifest herangezogen.

{
"name": "Meine PWA-Demo",
"short_name": "PWA-Demo",
"display": "standalone",
"start_url": "/",
"icons": [
{
"src": "assets/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "assets/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

 

Beispielhaftes Web App Manifest

Die Eigenschaft name definiert etwa den Namen der Anwendung. short_name kann angegeben werden, wenn der Name sehr lang ist und z.B. auf dem Homebildschirm eines Mobilgerätes abgekürzt werden soll. display gibt den Anzeigemodus an, das hier verwendete standalone bedeutet eine vollflächige Ausführung auf Mobilgeräten bzw. im eigenständigen Fenster auf Desktopsystemen. start_url definiert die URL, die beim Aufrufen des Homebildschirm- oder Programmlisteneintrags abgefragt werden soll. Hier ließe sich etwa der Anwendung per Query-Parameter mitteilen, dass gerade die installierte Variante geöffnet wurde. Schließlich können im Array icons Symbole in verschiedenen Abmessungen hinterlegt werden. Beim Installieren der Anwendung werden all diese Informationen ausgelesen und auf die Verknüpfung angewandt.

Abbildung 4 - Darstellung der Progressive Web App unter Android

Darstellung der Progressive Web App unter Android

Linkable

Progressive Web Apps mit Angular sollen „verlinkbar“ sein. Es soll möglich sein, die Anwendung oder sogar einen bestimmten Anwendungszustand durch das Kopieren der URL mit einer anderen Person zu teilen. Im Web gibt es zumindest die einfache Ausbaustufe komplett geschenkt: Dazu muss einfach die URL zur Webanwendung geteilt werden. Wünschenswert ist aber auch, dass die URL bis auf einen konkreten Zielzustand verweist. Hierfür gibt es innerhalb von Single-Page-Applikationen das Routing, das die URL mit einer bestimmten Sicht der Anwendung verknüpft. Bei Angular gehört der Router zum Lieferumfang. Hierüber können Routen auf Zielzustände innerhalb der Anwendung gemappt werden.

export const ROUTES: Route[] = [
{ path: '', pathMatch: 'full', redirectTo: 'home' },
{ path: 'home', component: HomeComponent },
{ path: 'settings', component: SettingsComponent }
];

Routendefinition in Angular

Progressive Web Apps mit Angular – Fazit

Die PWA-Unterstützung von Angular erlaubt es Entwicklern, mühelos in die Welt der PWA-Entwicklung einzusteigen: Bei Progressive Web Apps mit Angular kümmert sich der Angular-Service-Worker um die Offlinefähigkeit der Anwendungsquelldateien und hält sie aktuell. Dank des mitgelieferten Web App Manifest kann die Angular-App direkt in ihrem eigenen Fenster ausgeführt werden. Manche Punkte, etwa das Responsive Design oder die Offlinefähigkeit der strukturierten Anwenderdaten verbleiben aber beim Entwickler. Am Ende lockt eine Anwendung, die mit nur einer Codebase auf allen relevanten Betriebssystemen und den Webbrowsern sinnvoll betrieben werden kann.

Christian Liebel

Christian Liebel ist Consultant bei der Thinktecture AG in Karlsruhe, wo er moderne Businessanwendungen auf Basis von Angular und .NET Core umsetzt. Für seine Communityaktivitäten wurde er als Google Developer Expert (GDE) und Microsoft Most Valuable Professional (MVP) ausgezeichnet. Als Mitglied der Web Applications Working Group des W3C hält er den Blick auf kommende Webschnittstellen.
Christian Liebel

Letzte Artikel von Christian Liebel (Alle anzeigen)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Die von Ihnen hier erhobenen Daten werden von der Host Europe GmbH zur Veröffentlichung Ihres Beitrags in diesem Blog verarbeitet. Weitere Informationen entnehmen Sie bitte folgendem Link: www.hosteurope.de/AGB/Datenschutzerklaerung/