Tutorial on How-To Develop a Google Chrome App | HTML5

HTML5 offers a lot of interesting APIs for programming web applications that reside offline. Interestingly so does Google Chrome through Chromium's own API. In this article I will demonstrate how to create an offline app in Google Chrome using the Offline APIs in HTML5. This is different than the Chrome APIs for creating Installable apps, which can either be a full blown app or a Google Extension.

To take an application offline, a couple of considerations are necessary. First you need to define which assets of your application must be available offline to allow your application to run normally. Second, you need to be able to store data from your app when you are offline but also be able to upload that data to your server, if need be, when the app is back online or least when a synchronization is needed with a server. Finally, you need to be able to update your app from the server with any new features or updates.

To demonstrate these capabilities, I will build a simple address book to store my data locally and to sync with a server.

For this project I am using the Aptana version of Eclipse, which includes templates for HTML5. This is a free download from the Aptana web site. Although, it is possible use the HTML5 Boilerplate templates from Paul Irish, I believe it would be easier to grasp the concepts better by builder the HTML5 app from scratch.

From Eclipse, create a web application project using the appropriate web template (this is a standard template). Click Next and choose the “Basic HTML template”. Click finish to setup the project, which will include the initial index.html file.

Offline Manifest

To add Offline capabilities, you need to define a manifest file to define what assets to download to enable the app to function as if it was on a server. To define a manifest, we will to change the DOCTYPE in the HTML header. In the template, the DOCTYPE is define as:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<!--You will need to change this to :-->

<!DOCTYPE HTML>
<html manifest="addressbook.manifest">

Next you will need to create a manifest file. This can be anything you like but best practices dictate that it should have the manifest extension and be located at the root of your web app folders. You can also store your manifest file online on your web server. This can be a relative path or an absolute path. For an absolute app, it has to be from the same origin as your app. The syntax would be something like:

http://yourserver.com/myapp.manifest

Configure MIME Type

Also the manifest file has to have the correct MIME type, which is: text/cache-manifest.
To handle this, you save the manifest file with the manifest extension and you add the following directive to the .htaccess file on your Apache based server:

AddType text/cache-manifest .manifest

For IIS 6 or 7, you need to define type from the inetMgr tool:

  • Define the MIME type to either be valid for the entire server or to be valid for you application directorie.
  • To add a MIME type to a directory: Right click on the directory in which you want to add the MIME type.
  • Select the HTTP headers tag.
  • Click the File types button at the lower right.
  • Click New type and supply the extension and the content type as listed above.
  • To add a mime type to an entire server; Right click on the server.
  • Click the File types button and follow the instructions above.
  • Click New type and supply the extension and the content type as listed above.



If your app originates on the Google AppEngine, you define your manifest as follows:

- url:/appdir/(.*\.manifest)
static_files: appdir/\1
mime_type: text/cache-manifest
upload: appdir/(.*\.manifest)

For this example, I am naming the file addressbook.manifest and in it I will define the assets (files) that will need to be stored locally. This is the contents of the file:

MANIFEST File Contents

CACHE MANIFEST
# you can add comments using this syntax.
# if your app will only be offline, like if you are building an app for an Android device or an IOS    # device instead of an native app, then you donât necessarily need to include the CACHE
# MANIFEST header. However if the app is web based with offline capabilities, like Google 
# GMail, then you need to include the header information

CACHE:
index.html
styling.css
logic.js

# list any other pages as required. Their paths are relative to the manifest file.
# Any files listed after the CACHE header will load from the AppCache and not
# from the server. Any new files or changes to the server side manifest file will
# trigger the download and update from the server.
 

NETWORK:

# List any files that arenât cached, like any cgi script or types of configuration files or other
# script.

FALLBACK:
# Use this section to identify any files the app should use as failover plan. Any pages or images
# file can be listed here and are loaded if any of the main pages or other files fail to load.

# This is an example and not part of the app
main_logo.png failover_logo.png

It is important to note that 5 mb of data can be stored offline, so it is important to keep these constraints in mind when designing an app.

Updating the Cache



As I mentioned, if the manifest file is altered, then the app will download the new files listed in the manifest, but it won’t necessarily update the other files. As part of the HTML5 offline specification, the API provides programmatic control of the caching. This includes events and status to manipulate the cache of an application.

To add programmatic logic to our app for the caching, define a JavaScript file, logic.js for our app. In the file create a function appInit() which will be called when the app is loaded:

Index.html

<!DOCTYPE HTML>
<html manifest="addressbook.manifest">
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>Simple Address Book</title>
        <script src='logic.js' language="javascript" type='text/javscript'/>
    </head>
    <body onload='appInit()'>
        <h1>Simple Offline Address Book App</h1>
    </body>
</html>

logic.js

Code from logic.js

/**
 * Cache Update
 */

function appInit(){
	var appCache = window.applicationCache;
	var db = null;
	//Request an cache update
	appCache.update();

	switch (appCache.status) {
	  case appCache.UNCACHED: // 0
	    return 'UNCACHED';
	    break;
	  case appCache.IDLE: // 1
	    return 'IDLE';
	    break;
	  case appCache.CHECKING: // 2
	    return 'CHECKING';
	    break;
	  case appCache.DOWNLOADING: // 3
	    return 'DOWNLOADING';
	    break;
	  case appCache.UPDATEREADY:  // 4
	    return 'UPDATEREADY';
	    break;
	  case appCache.OBSOLETE: // 5
	    return 'OBSOLETE';
	    break;
	  default:
	    return 'UKNOWN CACHE STATUS';
	    break;
	};
	
	//If the update was successful, swap the cache for the new one. 
	if (appCache.status == window.applicationCache.UPDATEREADY) {
		  appCache.swapCache(); 
		  if (confirm('A new version of the Address Book is available. Load it?')) {
		        window.location.reload();
		        launchDb();
		      }
		    } else {
		      // Manifest didn't changed.
		    }
		}
	
}

First we define an appCache variable and set it to window.applicationCache. Next we attempt to update the cache by calling the update method. Then we define the different events that are available. If the update was successful and the event status is UPDATEREADY meaning the dowload of the new files was successful, then we can call the swapCache method to actually update the cache.

Offline Storage


Now that we have our offline app ready for, well, for being offline, we are going to need a place to store our data for our Address Book.

For our example, I will use the Web SQL database. To use, first we will need to create a database if it does not exist and open it. Then create a table, again if it does not exist and finally provide CRUD operations.

var db = null;
function launchDb(){
	db = openDatabase('addrbook', '1.0', 'offline address book database', 5 * 1024 * 1024, createInitTable(db){
	db.transaction(function(tx)
{
	tx.executeSql('CREATE TABLE IF NOT EXIST addresses (id, name, email)');

}
);

});

}

//I will add this code to the appInit function from above and should look like this:


function appInit(){
var db = null;
â¦

	//If the update was successful, swap the cache for the new one. 
	if (appCache.status == window.applicationCache.UPDATEREADY) {
		  appCache.swapCache(); 
		 // init or open the database 
  launchDb();
		}
}

There are most definitely better ways to code this, but for the purposes of our example, it will suffice. Once the cache update is complete, the database and table will attempt to be created and/or opened as well as the table.

We will also need some code next for our CRUD operations; primarily an INSERT and a SELECT query.

function getEntries(db){

db.transaction(
       function(tx) {
           tx.executeSql(
               'SELECT * FROM addresses WHERE date = ? ORDER BY name;',
                  function (tx, result) {
                   for (var i=0; i < result.rows.length; i++) {
                       var row = result.rows.item(i);
           var list = document.getElementById(âdataAddressâ)
                      	list += âname : â + row.name + â,  email:â row.email;
                        }
               },
               errorHandler
           );
       }
   );
}

function insertEntries(db, nameStr, emailStr){
db.transaction(
       function(tx) {
           tx.executeSql('INSERT INTO LOGS 
                        (name, email) VALUES (?, ?'), [nameStr, emailStr];
                        }
               },
               errorHandler
           );
       }
   );

}

Now that we have our back-end and CRUD operations in place, all that is left is to build the UI. For this part, I will use an improved HTML5 features, namely: Form 2.0 and new features that is part of the Web Form API: placeholder text and autofocus

The placeholder attribute adds a prompt or tooltip to the field, while the autofocus places the cursor in a designated field.

So back to our index.html page, insert after the h1 element a form element with two fields: name and email.

<form action=POST>
	<input name=ânameâ placeholder=âEnter a contact nameâ autofocus/>
	<input name=âemailâ placeholder=âEnter a valid e-mail addressâ/>

</form>

So there you have it. This article only brushes on the features of HTML5 for storage and offline capabilities as well as some of the new form features.

More by this Author


Comments 6 comments

Jagan 4 years ago

WOW... Such a awesome tutorial !

Thanks =)


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

I am glad you found it useful. Thanks for the feedback


Edward 4 years ago

Hey Klanguedoc,

Looks pretty descriptive for newbies like myself to learn on how to chrome appsusing HTML5.HTML5 also finds its big way in responsive web designing ,it would be of great use for readers if u explain on tat since ur presentation is great..

I loved reading ur article and wish more related posts from you..


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Hi Edward,

Thanks for the great feedback. I would certainly like to write more about HTML5 and and how to use to develop web apps.


Eddwin Paz 3 years ago

Hi, you have any idea how i can prevent closing a Extension? example i want to make a Small Phone Agenda but when i to no another page or click somewhere else it closes and when i click back the form its blank again.

Any ideas? i wanted to try a tab extension but don't know where to go.

Thanks!


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

Usually an extension remains open as long as the Chrome browser is open. Do you mean to want it the stay on top. Have you tried z-index. The answer is not really in Chrome, but in CSS

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    Click to Rate This Article
    working