HTML5 offline apps:
Real world insights

Stephan Hochdörfer // 2013-11-14

About me

  • Stephan Hochdörfer
  • Head of IT, bitExpert AG (Mannheim, Germany)
  • S.Hochdoerfer@bitExpert.de
  • @shochdoerfer

  • #PHP, #DevOps, #Automation

The age of smartphones

Offline First!




« We live in a disconnected & battery powered world, but our technology and best practices are a leftover from the always connected & steadily powered past. »
- offlinefirst.org

How to create "offline" apps?







« [...] we take the next step, announcing 2014
as the target for Recommendation. »
- Jeff Jaffe, CEO, W3C

HTML5 not ready?

HTML5 is ready!

What does "offline" mean?




« Offline storage is about capturing specific data generated by the user, or resources the user has expressed interest in. » - Eric Bidelman

Offline Containers




  • Hybrid Container
  • App Cache

Application: Hybrid Container

Application: App Cache




« The cache manifest in HTML5 is a software storage feature which provides the ability to access a web application even without a network connection. »
- Wikipedia

App Cache: Setup

<!DOCTYPE html>
<html lang="en">

App Cache: Setup

<!DOCTYPE html>
<html lang="en" manifest="cache.manifest">
CACHE MANIFEST
#2013-11-14

js/app.js
css/app.css
favicon.ico
http://someotherdomain.com/image.png

App Cache: Section Config

CACHE MANIFEST
# 2013-11-14

NETWORK:
data.php

CACHE:
/main/home
/main/app.js
/settings/home
/settings/app.js
http://myhost/logo.png
http://myhost/check.png
http://myhost/cross.png

App Cache: Section Config

CACHE MANIFEST
# 2013-11-14

FALLBACK:
/ /offline.html

NETWORK:
*

App Cache: Load the update!

// Check if a new cache version is available
window.addEventListener('load', function(e) {
  
  window.applicationCache.addEventListener('updateready', 
      function(e) {
    
      if(window.applicationCache.status == 
          window.applicationCache.UPDATEREADY) {
      
          window.applicationCache.swapCache();
      
          if (confirm('New version is available. Load it?')) {
	      window.location.reload();
          }
      }

  }, false);

}, false);

App Cache: Gotchas


  • Files are always(!) served
    from the cache
  • Manifest file needs to change
    to trigger an update
  • Non-cached resources will not
    load on a cached page
  • Do not allow the manifest file
    to be cached!

How to store data locally?



  • Web Storage
  • Web SQL Database
  • IndexedDB
  • File API

Web Storage





Very convenient form of offline storage:
simple key-value store

Web Storage: Example

var value = "my value";
// method call

localStorage.setItem("key", value);
value = localStorage.getItem("key");
// Array accessor

localStorage[key] = value;
value = localStorage[key];
// Property accessor

localStorage.key = value;
value = localStorage.key;

Web Storage: Example

var myObject = {
  key1: "value 1",
  key2: 500,
  key3: false
};
// store item

localStorage.setItem(
  "key", 
  JSON.stringify(myObject)
);
// retrieve item

myObject = JSON.parse(
    localStorage.getItem("key")
); 

Web Storage: Pros & Cons


  • Pro: Most compatible format.
    Yes, IE8 included!
  • Pro: No HTTP overhead
  • Con: The data is not structured
  • Con: Inadequate information
    about storage quota.

Web SQL Database





An offline SQL database based on SQLite,
a general-purpose SQL engine.

Web SQL: Example

var db = openDatabase('mydb', '1.0', 'DB',  5 * 1024 * 1024 );

db.transaction(function (tx) {
    tx.executeSql(
	'SELECT * FROM table',
	[],
	function(tx, results) {
	    var len = results.rows.length;
	    for(var i = 0; i < len; i++) {
		    // render item
	    }
	},
	function(tx, ex) {
	    alert("Error: " + ex.message);
	}
    );
});

Web SQL: Pros & Cons


  • Pro: Versioning support
  • Pro: A real database running
    in the browser!
  • Con: A real database running
    in the browser!
  • Con: No longer part of
    HTML5 specification!

IndexedDB




A nice compromise between Web Storage
and Web SQL Database giving you the
best of both worlds.

IndexedDB: Create store

var db = null;
var request = indexedDB.open("mydb");
request.onfailure = onError;
request.onsuccess = function(e) {
  db = request.result;
  var v = "1.0";
  if(v != db.version) {
    var verRequest = db.setVersion(v);
    verRequest.onfailure = onError;
    verRequest.onsuccess = function(e) {
      var store = db.createObjectStore("table",
	{
	  keyPath: "id",
	  autoIncrement: true
	});

      e.target.transaction.oncomplete =  function() {};
    };
  }
};

IndexedDB: Add item

try {
    var trans   = db.transaction(["mydb"], 
	IDBTransaction.READ_WRITE);

    var store   = trans.objectStore("table");
    var request = store.put({
      "MyKey1": 123,
      "MyKey2": "some random text"
    });
}
catch(ex) {
    // @TODO: Exception handling ;)
}

IndexedDB: Remove item

try {
    var trans   = db.transaction(["mydb"], 
	IDBTransaction.READ_WRITE);

    var store   = trans.objectStore("table");
    var id      = 1;
    var request = store.delete(id);
}
catch(ex) {
    // @TODO: Exception handling ;)
}

IndexedDB: Read items

try {
    var trans = db.transaction(["mydb"], IDBTransaction.READ);
    var store = trans.objectStore("table");

    var keyRange = IDBKeyRange.lowerBound(0);

    var cursorRequest = store.openCursor(keyRange);
    cursorRequest.onsuccess = function(e) {
      var result = e.target.result;
      if(!!result == false) {
	return;
      }

      // @TODO: process result.value

      result.continue();
    };
}
catch(ex) {
    // @TODO: Exception handling ;)
}

IndexedDB: Pros & Cons


  • Pro: Versioning support
  • Pro: Is the
    "new standard"
  • Con: You need to get used
    to the IndexedDB-way thinking
  • Con: Not many browsers do
    support it

Browser support?

Web Storage Web SQL DB IndexedDB File API
IE 8.0 10.0 10.0 -
Firefox 11.0 11.0 11.0 19.0
Chrome 18.0 18.0 18.0 18
Safari 5.1 5.1 - -
iOS 3.2 3.2 - -
Android 2.1 2.1 - -

Storage limitations?

Web Storage Web SQL DB IndexedDB File API
IE 10 MB 500 MB 500 MB
Firefox 10 MB 50 MB 50 MB
Chrome 5 MB
Safari 5 MB 5 MB 5 MB
iOS 5 MB 5 MB 5 MB
Android 5 MB ? ?

How to sync your data?





PouchDB, the JavaScript Database that syncs!

How to sync your data?

var db = new PouchDB('todo');

db.put({
 _id: 1,
 myKey1: 123,
 myKey2: 'Some random text'
});

db.replicate.to('http://myapp.com/mydb');







Thank you!