Progressive Web Apps – PWA

Manifest – Ladeliste

Eine Progressive App ist eine Webseite, die ähnliche Funktionen wie eine native Anwendung aufweist, die ohne Internet-Verbindung genutzt und auf dem Homescreen der mobilen Geräte installiert werden kann. Progressive Web Apps haben ihre Vorteile gegenüber nativen Apps: Sie sind einfacher zu erstellen.

23-02-02 SITEMAP

Voraussetzungen

Progressive Web Apps zeigen sich ohne die Navigationsleiste des Browsers (das bringt zusätzlichen Platz für die App), bieten ein einfaches Add to Homescreen für die Installation und legen einen Cache aller benötigten Ressourcen an und funktionieren auch dann, wenn der Benutzer offline ist. HTML, CSS und Javascript reichen. Sie müssen nicht über die App-Stores der Hersteller verteilt werden.

Um eine Webseite in eine PWA umzuwandeln,

  • darf die App noch nicht installiert sein,
  • die Seite muss über HTTPS bedient werden,
  • der Nutzer muss mindestens 30 Sekunden auf der Seite verbracht haben.

Dazu kommen technische Anforderungen:

  • Die Seite braucht ein Webapp-Manifest.
  • Die Webseite muss ein spezielles Script – den Service Worker – mit einem fetch-Event registrieren.

Aufbau / Dateien der PWA

index.html
manifest.json
/js/main.js
service-worker.js
android-chrome-192x192.png
android-chrome-512x512.png
apple-touch-icon.png

PWA Manifest

Das Manifest ist eine Ladeliste für Ressourcen, die vom Browser für den Aufbau der Anwendung gebraucht werden:

  • Kurzname und Name der Anwendung
  • Icons und Farbschema
  • Start-URL

Bei einer PWA ist das Manifest eine schlichte Javascript-Objekt-Notation oder eine JSON-Datei. Aus dem HTML-Manifest site.webmanifest wird eine JSON-Datei manifest.json. Die Manifest-Datei kann jeden beliebigen Namen haben, aber sie muss im Root-Verzeichnis der Anwendung liegen.

Im head-Element des HTML-Dokuments verweist ein link-Element auf das JSON-File.

index.html
<link rel="manifest" href="manifest.json">

So z.B. kann manifest.json aussehen

manifest.json
{
    "name": "DOKOBO",
    "short_name": "DOKOBO",
    "icons": [
        {
            "src": "/android-chrome-192x192.png",
            "sizes": "192x192",
            "type": "image/png",
            "purpose": "any maskable"
        },
        {
            "src": "/android-chrome-512x512.png",
            "sizes": "512x512",
            "type": "image/png"
        }
    ],
    "theme_color": "#e7ebc1",
    "background_color": "#e7ebc1",
    "display": "standalone",
	"start_url": "/index.html"
}

display:standalone verbirgt das Chrome des Browsers: die Navigationsleiste und Tabs. Das schafft zusätzlichen Platz für die Elemente der PWA. Würden wir davon ausgehen, dass der Benutzer den normalen Anblick einer Webseite bevorzugt, hätten wir dort display: browser eingesetzt.

Ein dritter Wert für display ist minimal-ui, das ein Reload und einen Zurück-Button einspielt.

Eine zusätzliche Eigenschaft orientation:portrait oder landscape würde die App in den jeweiligen Modus bringen.

Mehr zum Manifest: The Web App Manifest

Wenn die Kriterien für eine Progressive Web App zutreffen, zeigt der Browser eine kleine und eher unauffällige Statuszeile.

Add to Homescreen

Der Benutzer kann die Infozeile mit einem Klick aus dem Weg räumen. Der Browser kramt sie dann nach etwa drei Monaten erneut hervor.

Das Manifest wird von Chrome, Edge, Firefox, dem Samsung-Browser und Opera unterstützt, von Safari allerdings nur teilweise: Safari informiert den Benutzer nicht über die automatische Infozeile, dass die App installierbar ist.

main.js: serviceWorker supported?

Der Service Worker ist ein Script, dass nicht über ein Script-Element der Seite angesprochen wird, sondern durch ein Script registriert wird und im Hintergrund unabhängig von der Webseite läuft (der Service Worker hat keinen Zugriff auf das DOM). Würde der Service-Worker in einem Verzeichnis js oder einem anderen Unterverzeichnis gespeichert, würde das Script nur die Dateien sehen, die jeweiligen Ordner liegen.

Service Workers können Nachrichten senden und sich im Hintergrund synchronisieren. Dazu gehört z.B. die Behandlung von Netzwerk-Requests, Push- und Fetch-Events sowie ein Add to Home Screen. So wird die PWA mit Funktionen versorgt, die sonst nativen Apps vorbehalten sind.

index.html
<script src="main.js"></script>

Zuerst in main.js prüfen, ob der Browser den ServiceWorker unterstützt.

main.js
if ("serviceWorker" in navigator) {
	navigator.serviceWorker.register ("service-worker.js").then (function (result) {
		console.log ("Service Worker registriert, Scope: " + result.scope);
	}, function (error) {
		console.log ("Service Worker Registration fehlgeschlagen " + error);
	});
} else {
	console.log ("Service Worker nicht unterstützt");
}

Der Service Worker soll den Cache mit all den Ressourcen füllen, die für die Darstellung und die Funktionen der App gebraucht werden, wenn die Anwendung offline ist. In erster Linie sind das der Name der Anwendung und ein Array mit Referenz auf alle Dateien.

service-worker.js
// Name mit Versionsnummer
let cacheName = 'VIAv1';

// Dateien für den Cache
let cachedFiles = [
	"/",
	"/index.html",
	"/manifest.json",
	"/android-chrome-192x192.png"
	"/android-chrome-512x512.png"
	"/apple-touch-icon.png"
	"/js/main.js",
	"/js/appscript.js",
	"/css/style.css",
	"/img/image.jpg",
	…
];

Der Service Worker braucht einen Event Listener für das install-Event.

service-worker.js
// self ist der aktuelle Service Worker
self.addEventListener ("install", function (evt) {
	console.log ("Service Worker Install Event ");
	evt.waitUntil (
		// öffnen mit dem result der open-Message
		caches.open (cacheName).then (function (cache) {
			console.log ("Dateien für den Cache");
			return cache.addAll (cachedFiles);
		}).then (function () {
			return self.skipWaiting ();
		}).catch ( function (err) {
			console.log ("Cache Failed", err);
		});
	);
});

Das Install-Event feuert, wenn der Service Worker installiert ist und gibt das Cache-API frei, mit dem alle Ressourcen gespeichert werden, die dem Benutzer auch offline zur Verfügung stehen sollen.

BeforeInstallPrompt Event

Zusätzlich zur Infozeile feuern die Browser (nicht Safari) ein BeforeInstallPrompt Event. An dieser Stelle kann die Anwendung den Benutzer über eine eigene und deutlichere Infozeile informieren, dass er die App als Web App installieren kann.

Der Browser feuert das BeforeInstallPrompt Event, wenn die Anforderungen an die Progressive Web App erfüllt sind.

Die Kriterien für Chrome und andere Browser können auf der Web Fundamental Developer-Seite eingesehen werden.

Testen im Simulator

Mit Android Studio und Apple Xcode kann die Anwendung auf den Simulatoren der verschiedenen mobilen Geräte getestet werden.

ios-simulator
iPhone-Simulator in xCode
android-studio-test
Pixels-Simulator (Android Studio)

Bei einer einfachen HTML-Datei ohne Scripte und Bilder könnten wir jetzt bereits die Seite im Simulator in Chrome sehen und das Icon mit den drei Punkten oben rechts zum Homescreen hinzufügen – aber noch wäre die Seite halt eine einfache HTML-Seite. Immerhin auch offline.

Das Icon hat noch ein kleines Chrome-Symbol unten rechts. Wird die Mini-App gestartet, zeigt Chrome keine Adresszeile mehr. Die App ist jetzt standalone.

Am Ende geht dann nichts daran vorbei, die App auf einem Webserver zu installieren: Die App muss von HTTPS serviert werden. 10.0.2.2:8443 und localhost reicht nicht weit.

iOS: Kein Banner » Zum Homebildschirm hinzufügen «

Safari unterstützt den Cache des Service Workers, aber weder Push-Nachrichten noch eine Synchronisierung im Hintergrund und zeigt auch weiterhin kein Banner für eine intuitive Installation. Erst im Juni 2022 hat Apple angekündigt, dass Push-Nachrichten und ein besserer PWA-Support 2023 aufgenommen werden.

Obwohl Add to Homescreen / Zum Home-Bildschirm ursprünglich von Apple kam, hat sich Apple lange zurückgehalten. Das Web App Install Banner muss vom Script initialisiert werden.

Im Grunde genommen ist die Installation einer PWA auf dem Iphone einfach, aber irgendwie gut versteckt. Da bleibt uns nicht, als ein Banner zu installieren, das dem Benutzer den Weg weist.

iOS braucht zwei zusätzliche Meta-Tags und ein Link-Tag.

manifest.json
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<link rel="apple-touch-startup-image" href="/apple-touch-icon.png">

Ein Add to Homescreen oder Zum Homebildschirm hinzufügen kann mit einem HTML-Element in index.html angelegt und im Script der Seite (main.js) aktiviert werden, um dem Benutzer einen Weg zur Installation aufzuzeigen.

ios-pwa-zum-homebildschirm

Abfragen, ob eine App standalone läuft: iOS und Chrome Unterschiede.

isInWebAppiOS = (window.navigator.standalone == true);
isInWebAppChrome = (window.matchMedia('(display-mode: standalone)').matches);

Quelle Stackoverflow

main.js
window.onload = function () {
	if (pwaSupport) {
		let platform = navigator.platform;
		if (platform === 'iPhone' || platform === 'iPad') {
			// Die App ist noch nicht installiert
			if (!navigator.standalone) {
				let lastShown = parseInt (localStorage.getItem ('lastShown'));
				let now = new Date().getTime ();
				// lastShown NaN – App wurde noch nie geladen und Anweisung seit 7 Tagen nicht gezeigt
				if (isNaN (lastShown) || (lastShown + 1000 * 60 * 60 * 24 * 7) <= now) {
					document.getElementById("instructions").style.display = "block";
					localStorage.setItem ("lastShown", now);
				}
			}
		}
	}
}

function hideInstructions () {
	document.getElementById("instructions").style.display = "none";
}

Progressive Web App testen mit Chrome-Developer-Tools

In den Entwickler-Werkzeugen von Chrome kann die PWA mit Einstellungen wie Offline und Update on reload getest werden. Praktisch.

Die Lighthouse-Erweiterung ist ein weiteres Hilfsmittel für Progressive Web Apps. Wenn die Seite mit Lighthouse untersucht wird, zeigt Lighthouse den Fortschritt der App. chrome-developer-tools-service-worker

Externe Links / Verweise in PWAs

Links to cross-origin destinations are unsafe – mit target blank und rel="noopener"

Was PWAs können – auch unter iOS

Erst drei Jahre nachdem Chrome die Unterstützung für den ServiceWorker freigegeben hat, hat Apple des Status des ServiceWorker von Under Considuration zu Under Development signalisiert und den Service Worker dann ab iOS 11 unterstützt.

Viele Funktionen, die PWAs abgesprochen werden – insbesondere unter iOS – gibt es für Webseiten seit vielen Jahren, so z.B. Geolocation. Die biometrische Anmeldung per Gesichtserkennung und Fingerprint wird von den meisten Browsern per WebAuthn (Web Authentication) unterstützt (in Safari seit Version 13, iOS ab Version 14). Mehr dazu: Passkeys for web authentication (Passkey Series – Part 1).

Was vielen Entwicklern weiterhin unter iOS fehlt, sind die Push-Nachrichten.