Offline WebApps

Web Anwendungen offline zur Verfügung zu stellen, ohne dass man lokal einen Server bereit stellen muss, das geht, mit HTML5. Wie genau möchte ich in diesem Artikel zeigen.

Problemstellung

html5Web Anwendungen haben den Nachteil, dass zu deren Benutzung immer eine online Verbindung nötig ist. Das ist insbesondere dann nicht garantiert, wenn man unterwegs und auf die mobile Internetverbindung des Smartphones angewiesen ist. Das ist einer der Gründe, warum Apps für das Smartphone gerne als native Apps entwickelt werden, denn diese können lokal auf dem Gerät installiert und damit offline benutzt werden. Nachteil dabei ist, dass eine App immer spezifisch für das Betriebssystem (iOS, Android, Windows) entwickelt werden muss. Wie ich in meinem Blog Artikel „HTML, CSS, JS – die universelle UI-Technologie?“ beschrieben habe, gibt es zwar mit JavaScript und Phonegap einen Weg die App aus einer Codebasis zu generieren, schöner ist aber, genau eine Anwendung zu haben, die immer im Browser, online und offline, ohne lokale Installation benutzt werden kann.

HTML5 bietet genau dafür eine Lösung. Web Anwendungen können im Browser aufgerufen, online und offline benutzt und auch Daten lokal gespeichert werden. Lokal benötigt man lediglich einen HTML5 konformen Browser. Wichtig dabei ist zu wissen, dass damit eine serverseitige Erzeugung der UI nicht mehr möglich ist, Frameworks wie JSF können nicht eingesetzt werden, alles was offline benötigt wird, muss auch offline zur Verfügung gestellt werden. Das heißt die Entwicklung der WebApp erfolgt mit HTML, JavaScript und CSS.

Anwendung lokal bereit stellen

Theorie

Um die Anwendung lokal und damit offline nutzen zu können, muss sie einmal im Browser, online über die URL der Anwendung, aufgerufen werden. So weit gibt es noch keinen Unterschied zu jeder anderen Web-Anwendung. Was der Browser bei diesem Aufruf macht, ist alle Files (HTML, JavaScript, CSS, Bilder) lokal zu speichern. Damit ist die Anwendung quasi lokal installiert und kann auch offline im Browser über die URL aufgerufen werden. Das ist schon sehr faszinierend, man hat keine Internetverbindung, gibt eine URL im Browser ein und die Webseite erscheint.

Um dies zu ermöglichen, hat HTML5 eine spezielle Datei eingeführt, das Cache-Manifest. In dieser Datei werden alle Files eingetragen, die der Browser lokal speichern soll, also alle Files (HTML, JavaScript, CSS, Bilder), die man benötigt um die Anwendung offline nutzen zu können. Beim Aufruf der URL läd der Browser zunächst alle Files herunter, die in dieser Datei stehen, erst dann wird die HTML-Seite im Browser angezeigt und die Anwendung kann genutzt werden. Das kann zum Nachteil werden, wenn im Cache-Manifest viele große Dateien stehen und der Browser erst mal mehrere MB herunter laden muss. Während dieses Download Vorgangs wartet der Nutzer. Nach dem Download werden die Files lokal verwendet und nicht mehr vom Server geladen, selbst wenn man online ist. Die lokale Speicherung ist unabhängig vom Browser-Cache, d.h. selbst wenn der Benutzer seinen Browser-Cache löscht, stehen die Files immer noch offline zur Verfügung.
Soll eine Update zur Verfügung gestellt werden, z.B. eine neue Version einer JavaScript Datei, muss das Cache-Manifest geändert werden. Es reicht eine kleine Änderung, auch in einem Kommentarfeld. Der Browser registriert dies beim nächsten online Aufruf der URL und läd alle Files im Cache-Manifest neu runter. Hier schlägt dann wieder der Nachteil zu, wenn viele große Files im Cache-Manifest referenziert sind und ein langer Download-Vorgang läuft.

Praxis

Das Cache-Manifest hat üblicherweise die Endung *.appcache, kann aber jede beliebige Dateiendung haben. Wichtig ist aber, dass sie den MIME-Type „text/cache-manifest“ hat. Es muss also geprüft werden, ob dieser MIME-Type bereits im Webserver konfiguriert ist.

Als Beispiel soll eine kleine Website mit zwei HTML-Seiten, die untereinander verlinkt sind, einem Bild, einem CSS-File und einer JavaScript-Datei offline bereit gestellt werden. Die Sample kann unter http://www.discoveration.de/demo/offline angeschaut werden.

Das Cache-Manifest enthält alle Files, die offline benötigt werden

CACHE MANIFEST
# Revision 1.0.2
CACHE:
index.html
seite2.html
html5.jpg
test.css
onlinecheck.js
NETWORK:
*

Zeilen die mit einem # beginnen sind Kommentare. Im Beispiel steht im Kommentar die Versionsnummer der WebApp. Es reicht diese Nummer im Kommentar zu ändern damit der Browser alle Files im Cache-Manifest erneut herunter läd.

Das Cache-Manifest teilt sich in folgende Bereiche auf:

  • CACHE:
    Alle Einträge, die unter CACHE: stehen, werden lokal gespeichert.
  • NETWORK:
    Unter NETWORK: stehen alle Files, die auf jeden Fall aus dem Netzwerk bezogen werden müssen. Bei diesen Files wird der Cache umgangen.
  • FALLBACK:
    Zusätzlich gibt es noch den optionalen Eintrag FALLBACK:. Darunter stehen Seiten, die aufgerufen werden, für den Fall, dass auf eine Ressource nicht zugegriffen werden kann

Das Cache-Manifest muss im HTML-Tag der Webanwendung referenziert werden:

<html lang="de" manifest="test.appcache">

Damit steht die Webseite nach dem ersten online Aufruf offline zur Verfügung. Einfach mal ausprobieren. Die Sample aufrufen, Browser schließen, Internetverbindung trennen und dann die URL der Sample im Browser wieder aufrufen. Und siehe da, alles wird angezeigt und selbst die Links funktionieren.

Daten lokal speichern

Statische Seiten und JavaScript offline zu nutzen ist nur die halbe Miete. Meist müssen auch Daten offline gespeichert werden. Hierfür stellt HTML5 eine lokale Datenbank zur Verfügung. Diese gibt es in zwei Ausprägungen, eine Indexed DB und den Local Storage. Die Indexed DB ist eine SQL Datenbank, im Local Storage können nur Key-Value Paare als Strings gespeichert werden. Im folgenden möchte ich nur auf den Local Storage eingehen.
Der Local Storage bietet eine einfache JavaScript API um Daten zu lesen, speichern und löschen. Pro Domain wird ein Local Storage angelegt, d.h. man kann nicht auf den Locale Storage einer anderen Domain zugreifen. Gespeichert werden die Daten mit einem Key, über den man die Daten wieder lesen und löschen kann. Für die Eindeutigkeit des Keys innerhalb der eigene Domain muss man selbst sorgen, ist der Key schon vergeben, werden die bereits gespeicherten Daten überschrieben. Die Daten bleiben persistent auf dem Rechner bis sie explizit gelöscht werden, auch wenn der Browser geschlossen, oder der Rechner ausgeschalten wird.
Die API des Locale Storage stellt folgende Funktionen bereit:

  • localStorage.setItem('key', 'value');

    Speichert einen Wert unter dem angegebenen Schlüssel

  • localStorage.getItem('key');

    Gibt den Wert vom angegebenen Schlüssel zurück. Existiert dieser nicht wir „undefined“ zurückgegeben. Eine Alternative für den Zugriff auf die Daten wäre localStorage.key.

  • localStorage.removeItem('key');

    Entfernt den kompletten Datensatz des Keys aus dem Localstorage. Wiederherstellen ist nicht möglich.

  • localStorage.clear();

    Löscht alle Daten aus dem lokalen Speicher welcher von der Domain angelegt wurde.

JSON und Locale Storage

Auch JSON Objekte könne einfach im Locale Storage gespeichert werden, sie müssen lediglich in einen String umgewandelt werden

function readFromDB(key) {
   var resultString = localStorage.getItem(key);
   return JSON.parse(resultString);
};

function saveInDB(key, data) {
   var resultString = JSON.stringify(data);
   localStorage.setItem(key, resultString);
};

Beispiel und Tipps

Einen interessanten Ansatz, wie man selbst kontrollieren kann, welche Files aktualisiert werden, ohne sie ins Cache-Manifest einzutragen ist in folgendem Artikel zu finden:
http://labs.ft.com/2012/08/basic-offline-html5-web-app/

Einen Sychronisations-Mechanismus um lokale Daten mit einem Server zu synchronisiere bringt HTML5 nicht mit. Dieses Problem muss man nach wie vor selbst lösen. Es bietet sich dabei an, die lokalen Daten 1:1 in einer Serverdatenbank abzubilden und den eigentlichen Sync-Mechanismus, also den Abgleich von Datenänderungen, komplett auf dem Server zu realisieren.

Ich habe einen RSS Reader geschrieben, der konfigurierte RSS Feeds lokal speichert. Die Web App muss einmal online im Browser aufgerufen werden und steht dann auch offline zur Verfügung. Die Feeds werden, wenn man online ist, über einen AJAX Request gelesen und als JSON Objekt lokal gespeichert. Offline kann man die Feeds dann in aller Ruhe lesen.

Der RSS Reader kann unter folgender URL aufgerufen werden
http://apps.marco-michel.net/rssreader

One Reply to “Offline WebApps”

  1. Hi Marco,

    vielen Dank für den Artikel. War sehr aufschlussreich. Mit Features wie diesem werden Browser immer mehr zu vollwertigen Anwendungsplattformen. Bin gespannt was die nächste HTML-Generation dann alles kann.

    Sven

Schreibe einen Kommentar

Anmelden um einen Kommentar abzugeben.

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

*