Progressive Web-Apps entwickeln – Version 2.0: Offline-Kurzanleitung

Dieses Codelab ist Teil des Kurses „Progressive Web-Apps entwickeln“, der vom Google Developers Training-Team entwickelt wurde. Sie können den größten Nutzen aus diesem Kurs ziehen, wenn Sie die Codelabs der Reihe nach durcharbeiten.

Weitere Informationen zum Kurs

Einführung

In diesem Lab verwenden Sie Lighthouse, um eine Website anhand der Standards für progressive Web-Apps (PWAs) zu prüfen. Außerdem fügen Sie mit der Service Worker API Offlinefunktionen hinzu.

Lerninhalte

  • Websites mit Lighthouse prüfen
  • Offlinefunktionen in eine Anwendung einfügen

Wichtige Informationen

  • Grundkenntnisse in HTML, CSS und JavaScript
  • Vertrautheit mit ES2015 Promises

Voraussetzungen

  • Computer mit Terminal-/Shell-Zugriff
  • Internetverbindung
  • Chrome-Browser (für die Verwendung von Lighthouse)
  • Ein Texteditor
  • Optional: Chrome auf einem Android-Gerät

Laden Sie das Repository „pwa-training-labs“ von GitHub herunter oder klonen Sie es und installieren Sie bei Bedarf die LTS-Version von Node.js.

Wechseln Sie in das Verzeichnis offline-quickstart-lab/app/ und starten Sie einen lokalen Entwicklungsserver:

cd offline-quickstart-lab/app
npm install
node server.js

Sie können den Server jederzeit mit Ctrl-c beenden.

Öffnen Sie Ihren Browser und rufen Sie localhost:8081/ auf. Sie sollten sehen, dass die Website eine einfache und statische Webseite ist.

Hinweis:Melden Sie alle Service Worker ab und löschen Sie alle Service Worker-Caches für localhost, damit sie das Lab nicht beeinträchtigen. In den Chrome-Entwicklertools können Sie dazu auf dem Tab Anwendung im Bereich Speicher löschen auf Websitedaten löschen klicken.

Öffnen Sie den Ordner offline-quickstart-lab/app/ in Ihrem bevorzugten Texteditor. Im Ordner app/ erstellen Sie das Lab.

Dieser Ordner enthält:

  • Der Ordner images/ enthält Beispielbilder.
  • styles/main.css ist das Haupt-Stylesheet.
  • index.html ist die Haupt-HTML-Seite für unsere Beispielwebsite.
  • package-lock.json und package.json verfolgen App-Abhängigkeiten (die einzigen Abhängigkeiten in diesem Fall sind für den lokalen Entwicklungsserver).
  • server.js ist ein lokaler Entwicklungsserver zum Testen.
  • service-worker.js ist die Service Worker-Datei (derzeit leer).

Bevor wir Änderungen an der Website vornehmen, führen wir eine Prüfung mit Lighthouse durch, um zu sehen, was verbessert werden kann.

Kehren Sie zur App (in Chrome) zurück und öffnen Sie den Tab Audits der Entwicklertools. Das Lighthouse-Symbol und die Konfigurationsoptionen sollten angezeigt werden. Wählen Sie unter Gerät die Option „Mobil“ aus, wählen Sie alle Prüfungen aus, wählen Sie eine der Drosselungsoptionen aus und wählen Sie Speicherplatz freigeben aus:

Klicken Sie auf Prüfungen ausführen. Die Überprüfungen dauern einen Moment.

Erklärung

Nach Abschluss des Audits sollte in den Entwicklertools ein Bericht mit den Ergebnissen angezeigt werden. Es sollten Ergebnisse angezeigt werden, etwa so (die Ergebnisse sind möglicherweise nicht genau gleich):

Hinweis:Lighthouse-Punktzahlen sind Schätzungen und können durch Ihre Umgebung beeinflusst werden, z. B. wenn Sie viele Browserfenster geöffnet haben. Ihre Ergebnisse stimmen möglicherweise nicht genau mit den hier gezeigten überein.

Der Abschnitt Progressive Web-App sollte in etwa so aussehen:

Der Bericht enthält Werte und Messwerte in fünf Kategorien:

  • Progressive Web-App
  • Leistung
  • Bedienungshilfen
  • Best Practices
  • SEO

Wie Sie sehen, schneidet unsere App in der Kategorie „Progressive Web-App (PWA)“ schlecht ab. Lass uns unseren Wert verbessern!

Sehen Sie sich den PWA-Abschnitt des Berichts an, um herauszufinden, was fehlt.

Service Worker registrieren

Einer der im Bericht aufgeführten Fehler ist, dass kein Service Worker registriert ist. Derzeit haben wir eine leere Service Worker-Datei unter app/service-worker.js.

Fügen Sie das folgende Skript unten in index.html ein, direkt vor dem schließenden </body>-Tag:

<script>
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('service-worker.js')
      .then(reg => {
        console.log('Service worker registered! 😎', reg);
      })
      .catch(err => {
        console.log('😥 Service worker registration failed: ', err);
      });
  });
}
</script>

Erklärung

Mit diesem Code wird die leere Service Worker-Datei service-worker.js registriert, sobald die Seite geladen wurde. Die aktuelle Service Worker-Datei ist jedoch leer und hat keine Auswirkungen. Im nächsten Schritt fügen wir den Servicecode hinzu.

Ressourcen vorab im Cache speichern

Ein weiterer im Bericht aufgeführter Fehler ist, dass die App im Offlinemodus nicht mit dem Statuscode 200 reagiert. Wir müssen unseren Service Worker aktualisieren, um das Problem zu beheben.

Fügen Sie der Service Worker-Datei (service-worker.js) den folgenden Code hinzu:

const cacheName = 'cache-v1';
const precacheResources = [
  '/',
  'index.html',
  'styles/main.css',
  'images/space1.jpg',
  'images/space2.jpg',
  'images/space3.jpg'
];

self.addEventListener('install', event => {
  console.log('Service worker install event!');
  event.waitUntil(
    caches.open(cacheName)
      .then(cache => {
        return cache.addAll(precacheResources);
      })
  );
});

self.addEventListener('activate', event => {
  console.log('Service worker activate event!');
});

self.addEventListener('fetch', event => {
  console.log('Fetch intercepted for:', event.request.url);
  event.respondWith(caches.match(event.request)
    .then(cachedResponse => {
        if (cachedResponse) {
          return cachedResponse;
        }
        return fetch(event.request);
      })
    );
});

Kehren Sie jetzt zum Browser zurück und aktualisieren Sie die Website. Prüfen Sie in der Console, ob der Service Worker:

  • registriert
  • Installiert
  • Aktiviert

Hinweis:Wenn Sie den Service Worker bereits registriert haben oder Probleme auftreten, alle Ereignisse auszulösen, heben Sie die Registrierung aller Service Worker auf und aktualisieren Sie die Seite. Wenn das nicht funktioniert, schließen Sie alle Instanzen der App und öffnen Sie sie wieder.

Beenden Sie als Nächstes den lokalen Entwicklungsserver in der Befehlszeile, indem Sie Ctrl + c ausführen. Aktualisieren Sie die Website noch einmal. Sie wird geladen, obwohl der Server offline ist.

Hinweis:Möglicherweise wird ein Konsolenfehler angezeigt, der darauf hinweist, dass der Service Worker nicht abgerufen werden konnte: An unknown error occurred when fetching the script. service-worker.js Failed to load resource: net::ERR_CONNECTION_REFUSED. Dieser Fehler wird angezeigt, weil der Browser das Service Worker-Script nicht abrufen konnte (da die Website offline ist). Das ist jedoch zu erwarten, da wir den Service Worker nicht verwenden können, um sich selbst zu cachen. Andernfalls würde der Browser des Nutzers für immer denselben Service Worker verwenden.

Erklärung

Sobald der Service Worker vom Registrierungsskript in index.html registriert wurde, tritt das install-Ereignis des Service Workers ein. Während dieses Ereignisses öffnet der install-Ereignis-Listener einen benannten Cache und speichert die mit der cache.addAll-Methode angegebenen Dateien im Cache. Das wird als „Pre-Caching“ bezeichnet, da es während des install-Ereignisses stattfindet, das in der Regel beim ersten Besuch eines Nutzers auf Ihrer Website ausgelöst wird.

Nachdem ein Service Worker installiert wurde und kein anderer Service Worker die Seite steuert, wird der neue Service Worker „aktiviert“ (der activate-Ereignis-Listener wird im Service Worker ausgelöst) und er beginnt, die Seite zu steuern.

Wenn Ressourcen von einer Seite angefordert werden, die von einem aktivierten Service Worker gesteuert wird, werden die Anfragen wie bei einem Netzwerkproxy über den Service Worker geleitet. Für jede Anfrage wird ein fetch-Ereignis ausgelöst. In unserem Service Worker sucht der fetch-Event-Listener in den Caches und antwortet mit der im Cache gespeicherten Ressource, falls sie verfügbar ist. Wenn die Ressource nicht im Cache gespeichert ist, wird sie normal angefordert.

Durch das Caching von Ressourcen kann die App offline verwendet werden, da keine Netzwerkanfragen erforderlich sind. Unsere App kann jetzt auch im Offlinemodus mit dem Statuscode 200 antworten.

Hinweis:Das Aktivierungsereignis wird in diesem Beispiel nur für die Anmeldung verwendet. Das Ereignis wurde eingefügt, um bei der Fehlerbehebung von Problemen mit dem Service Worker-Lebenszyklus zu helfen.

Optional: Sie können die im Cache gespeicherten Ressourcen auch auf dem Tab Anwendung der Entwicklertools ansehen, indem Sie den Bereich Cache Storage maximieren:

Starten Sie den Entwicklungsserver mit node server.js neu und aktualisieren Sie die Website. Öffnen Sie dann in den Entwicklertools noch einmal den Tab Audits und führen Sie die Lighthouse-Prüfung noch einmal aus, indem Sie New Audit (das Pluszeichen oben links) auswählen. Nach Abschluss des Audits sollte unser PWA-Score deutlich besser sein, aber er könnte noch verbessert werden. Im nächsten Abschnitt werden wir unseren Score weiter verbessern.

Hinweis:Dieser Abschnitt ist optional, da das Testen des Installationsbanners für Web-Apps den Rahmen dieses Labs sprengt. Sie können es selbst mit Remote-Debugging ausprobieren.

Unser PWA-Faktor ist immer noch nicht gut. Einige der verbleibenden Fehler im Bericht sind, dass der Nutzer nicht aufgefordert wird, unsere Web-App zu installieren, und dass wir keinen Splash-Screen oder keine Markenfarben in der Adressleiste konfiguriert haben. Wir können diese Probleme beheben und Zum Startbildschirm hinzufügen schrittweise implementieren, indem wir einige zusätzliche Kriterien erfüllen. Am wichtigsten ist, dass wir eine Manifestdatei erstellen.

Manifestdatei erstellen

Erstellen Sie im Ordner app/ eine Datei mit dem Namen manifest.json und fügen Sie den folgenden Code ein:

{
  "name": "Space Missions",
  "short_name": "Space Missions",
  "lang": "en-US",
  "start_url": "/index.html",
  "display": "standalone",
  "theme_color": "#FF9800",
  "background_color": "#FF9800",
  "icons": [
    {
      "src": "images/touch/icon-128x128.png",
      "sizes": "128x128"
    },
    {
      "src": "images/touch/icon-192x192.png",
      "sizes": "192x192"
    },
    {
      "src": "images/touch/icon-256x256.png",
      "sizes": "256x256"
    },
    {
      "src": "images/touch/icon-384x384.png",
      "sizes": "384x384"
    },
    {
      "src": "images/touch/icon-512x512.png",
      "sizes": "512x512"
    }
  ]
}

Die im Manifest referenzierten Bilder sind bereits in der App enthalten.

Fügen Sie dann den folgenden HTML-Code unten im <head>-Tag in index.html ein:

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

<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="application-name" content="Space Missions">
<meta name="apple-mobile-web-app-title" content="Space Missions">
<meta name="theme-color" content="#FF9800">
<meta name="msapplication-navbutton-color" content="#FF9800">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="/index.html">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<link rel="icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="apple-touch-icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="icon" sizes="192x192" href="icon-192x192.png">
<link rel="apple-touch-icon" sizes="192x192" href="/images/touch/icon-192x192.png">
<link rel="icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="apple-touch-icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="apple-touch-icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="icon" sizes="512x512" href="/images/touch/icon-512x512.png">
<link rel="apple-touch-icon" sizes="512x512" href="/images/touch/icon-512x512.png">

Kehren Sie zur Website zurück. Wählen Sie in den Entwicklertools auf dem Tab Anwendung den Bereich Speicher löschen aus und klicken Sie auf Websitedaten löschen. Aktualisieren Sie dann die Seite. Wählen Sie nun den Abschnitt Manifest aus. Sie sollten die Symbole und Konfigurationsoptionen sehen, die in der Datei manifest.json konfiguriert sind. Wenn Sie Ihre Änderungen nicht sehen, öffnen Sie die Website in einem Inkognitofenster und prüfen Sie noch einmal.

Erklärung

Die Datei manifest.json enthält Informationen dazu, wie der Browser einige der progressiven Aspekte Ihrer App gestalten und formatieren soll, z. B. die Browser-Chrome, das Startbildschirmsymbol und den Splash-Screen. Sie kann auch verwendet werden, um Ihre Web-App so zu konfigurieren, dass sie im standalone-Modus geöffnet wird, wie eine native App (d. h. außerhalb des Browsers).

Die Unterstützung für einige Browser ist zum Zeitpunkt der Erstellung dieses Artikels noch in der Entwicklung. Mit den <meta>-Tags wird eine Teilmenge dieser Funktionen für bestimmte Browser konfiguriert, die noch nicht vollständig unterstützt werden.

Wir mussten die Website-Daten löschen, um die alte im Cache gespeicherte Version von index.html zu entfernen, da diese Version keinen Manifestlink enthielt. Führen Sie eine weitere Lighthouse-Prüfung durch und sehen Sie, wie sich die PWA-Punktzahl verbessert hat.

Installationsaufforderung aktivieren

Im nächsten Schritt wird Nutzern die Installationsaufforderung angezeigt. In Chrome 67 wurden Nutzer automatisch aufgefordert, die App zu installieren. Ab Chrome 68 sollte die Installationsaufforderung jedoch programmatisch als Reaktion auf eine Nutzeraktion aktiviert werden.

Fügen Sie oben auf index.html (direkt nach dem <main>-Tag) mit dem folgenden Code eine Schaltfläche und ein Banner zum Installieren der App hinzu:

<section id="installBanner" class="banner">
    <button id="installBtn">Install app</button>
</section>

Fügen Sie dann die folgenden Formatierungen in styles/main.css hinzu, um das Banner zu gestalten:

.banner {
  align-content: center;
  display: none;
  justify-content: center;
  width: 100%;
}

Speichern Sie die Datei. Fügen Sie schließlich das folgende Skript-Tag in index.html ein:

  <script>
    let deferredPrompt;
    window.addEventListener('beforeinstallprompt', event => {

      // Prevent Chrome 67 and earlier from automatically showing the prompt
      event.preventDefault();

      // Stash the event so it can be triggered later.
      deferredPrompt = event;

      // Attach the install prompt to a user gesture
      document.querySelector('#installBtn').addEventListener('click', event => {

        // Show the prompt
        deferredPrompt.prompt();

        // Wait for the user to respond to the prompt
        deferredPrompt.userChoice
          .then((choiceResult) => {
            if (choiceResult.outcome === 'accepted') {
              console.log('User accepted the A2HS prompt');
            } else {
              console.log('User dismissed the A2HS prompt');
            }
            deferredPrompt = null;
          });
      });

      // Update UI notify the user they can add to home screen
      document.querySelector('#installBanner').style.display = 'flex';
    });
  </script>

Speichern Sie die Datei. Öffnen Sie die App in Chrome auf einem Android-Gerät mit Remote-Debugging. Wenn die Seite geladen wird, sollte die Schaltfläche „App installieren“ angezeigt werden. Auf einem Computer ist sie nicht zu sehen. Testen Sie daher auf einem Mobilgerät. Klicken Sie auf die Schaltfläche. Das Pop-up-Fenster „Zum Startbildschirm hinzufügen“ sollte angezeigt werden. Folgen Sie der Anleitung, um die App auf Ihrem Gerät zu installieren. Nach der Installation sollten Sie die Web-App im Standalone-Modus (außerhalb des Browsers) öffnen können, indem Sie auf das neu erstellte Symbol auf dem Startbildschirm tippen.

Erklärung

Mit dem HTML- und CSS-Code werden ein ausgeblendetes Banner und eine ausgeblendete Schaltfläche hinzugefügt, mit denen Nutzer den Installationsaufforderung aktivieren können.

Sobald das beforeinstallprompt-Ereignis ausgelöst wird, verhindern wir das Standardverhalten (bei dem Nutzer in Chrome 67 und früher automatisch zur Installation aufgefordert werden) und erfassen das beforeinstallevent in der globalen Variablen deferredPrompt. Die Schaltfläche „App installieren“ wird dann so konfiguriert, dass der Prompt mit der beforeinstallevent-Methode von prompt() angezeigt wird. Sobald der Nutzer eine Auswahl getroffen hat (Installation oder nicht), wird das userChoice-Promise mit der Auswahl des Nutzers (outcome) aufgelöst. Schließlich wird die Schaltfläche „Installieren“ angezeigt, sobald alles bereit ist.

Sie haben gelernt, wie Sie Websites mit Lighthouse prüfen und die Grundlagen der Offline-Funktionalität implementieren. Wenn Sie die optionalen Abschnitte durchgearbeitet haben, wissen Sie auch, wie Sie Web-Apps auf dem Startbildschirm installieren.

Weitere Ressourcen

Lighthouse ist Open Source. Sie können es forken, eigene Tests hinzufügen und Fehler melden. Lighthouse ist auch als Befehlszeilentool für die Integration in Build-Prozesse verfügbar.

Eine Liste aller Codelabs im PWA-Schulungskurs finden Sie im Willkommens-Codelab für den Kurs.