08 Jun 2010: Added links to Part 4 of this series in About this series, Summary, and Resources sections.
29 Jun 2010: Added links to Part 5 of this series in About this series, Summary, and Resources sections.
HTML 5 is a very hyped technology, but with good reason. It promises to be a technological tipping point to bring desktop application capabilities to the browser. As promising as it is for traditional browsers, it has even more potential for mobile browsers. Even better, the most popular mobile browsers have already adopted and implemented many significant parts of the HTML 5 specification. In this five-part series, you will take a closer look at several of those new technologies that are part of HTML 5 and can have a huge impact on mobile Web application development. In each part, you will develop a working mobile Web application showcasing an HTML 5 feature that you can use on modern mobile Web browsers like the ones found on the iPhone and Android-based devices.
In this article, you will develop Web applications using the latest Web technologies. Most of the code here is just HTML, JavaScript, and CSS—the core technologies of any Web developer. The most important thing you will need are browsers to test things on. Most of the code in this article will run on the latest desktop browsers with some noted exceptions. Of course you must test on mobile browsers too, and you will want the latest iPhone and Android SDKs for those. In this article, iPhone SDK 3.1.3 and Android SDK 2.1 were used. See Resources for links.
Why make your application work offline?
Offline Web applications are attractive to both users and developers for a number of reasons. Many developers would love to be able to write a single Web application that works on all of the most popular smartphones instead of writing native applications for each platform. Just because that would be convenient to developers does not mean that it would be desired by users. For that to happen, mobile Web applications have to be able to provide many (or most) of the same features that native mobile applications can provide. Working offline is definitely one of those features. Some applications will rely heavily on data and services from the Internet—whether or not they are a mobile Web or native application. For these applications, it is understood that functionality might be reduced if the user does not have a good connection to the Internet. However, the application cannot fail completely just because the user's connection is not good. With a traditional Web application that is exactly what would happen.
Offline capabilities bring mobile Web applications closer to parity with native applications. They have some other benefits too. Web browsers have always cached static resources. They rely on metadata from the HTTP response headers sent by your Web servers to retrieve the HTML, JavaScript, CSS, and images needed to render the page. If everything needed to render the page is cached, then the page loads very quickly. However, if something is not cached, then it can slow down everything dramatically. This happens more often than you might like. Maybe one CSS file had a different Cache-Control header than all of the other files, or maybe the browser kicked out of cache because it was running out of allocated space.
With offline applications, you are assured that everything is cached. Browsers will
always load everything from cache, though you also get control over what should not be
served from cache. It is a common Ajax hack to add an extra timestamp parameter to
Ajax GET requests (or even worse to use POST when GET is appropriate) to
avoid browsers caching a response. You won't need this hack for offline-enabled Web applications.
Offline applications sound great, so it must be complex to create one, right? Actually, it is quite simple. You need to do three things:
- Create an online manifest file
- Tell the browser about the manifest file
- Set the MIME type on the server
One key file is involved: the cache manifest for your application. This file tells the browser exactly what to cache (and, optionally, what not to cache.) This becomes the source of truth for your application. Listing 1 shows an example of a simple cache manifest.
Listing 1. Simple cache manifest
CACHE MANIFEST # Version 0.1 offline.html /iui/iui.js /iui/iui.css /iui/loading.gif /iui/backButton.png /iui/blueButton.png /iui/cancel.png /iui/grayButton.png /iui/listArrow.png /iui/listArrowSel.png /iui/listGroup.png /iui/pinstripes.png /iui/redButton.png /iui/selection.png /iui/thumb.png /iui/toggle.png /iui/toggleOn.png /iui/toolbar.png /iui/whiteButton.png /images/gymnastics.jpg /images/soccer.png /images/gym.jpg /images/soccer.jpg |
This file lists all of the files that your application needs to function properly. This includes HTML files as well as JavaScript, CSS, and images. It could include videos, PDFs, XML files, and so on. Notice that all of the URLs in this example are relative. Any relative URLs must be relative to the cache manifest file. In this case, the cache manifest file is in the root directory of your Web application. Compare the directory structure in Listing 2 to the relative URLs in Listing 1.
Listing 2. Text version of the directory structure for the Web application
Name
V images
gymnastics.jpg
soccer.png
V iui
backButton.png
blueButton.png
cancel.png
grayButton.png
iui.css-logo-touch-icon.png
iui.css
iui.js
iuix.css
iuix.js
listArrow.png
listArrowSel.png
listGroup.png
loading.gif
pinstripes.png
redButton.png
selection.png
thumb.png
toggle.png
toggleOn.png
toolbar.png
toolButton.png
whiteButton.png
manifest.mf
offline.html
> WEB-INF
|
You might have noticed that this application is using the iUI framework. This is a popular JavaScript+CSS kit for giving mobile Web applications the look and feel of native iPhone applications. As you can see from Listing 1 and Listing 2, the framework uses several images to go along with its JavaScript and CSS files. However, all of these files will be cached by the browser and will be usable in offline mode as long as they are listed in the manifest.
Another critical thing to notice in Listing 1 is the version info. This is not part of the specification. In fact, it is just a comment in the file. However, it is key to have something like this that you can use to tell the browser that there is a new version of your application. Suppose you changed some HTML or some JavaScript or even just an image. If you do not change the manifest, the browser will never bother to load the new version of the resource that you modified. There is no expiry on a cache manifest, so everything stays cached unless the user clears the cache or the manifest file changes. The browser will check to see if there is a new manifest file. To indicate a new manifest file, you simply need to change something/anything in the existing manifest file. Going back to your example of changing the HTML on the page, if you changed the HTML and changed the version string in the manifest file, then the browser will know that the resources have changed and to download them again. Putting a version number in a comment is an easy way to manage this lifecycle.
Tell the browser about the manifest
There is one more missing piece to enabling offline caching of your Web application. The Web browser needs to know that you want to enable caching and where to find your cache manifest file. Listing 3 shows this very easy way.
Listing 3. Offline enabled Web page
<!DOCTYPE html>
<html>
<html manifest="manifest.mf">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width; initial-scale=1.0;
maximum-scale=1.0; user-scalable=0;"/>
<meta name="apple-touch-fullscreen" content="YES" />
<link rel="apple-touch-icon" href="/iui/iui-logo-touch-icon.png" />
<style type="text/css" media="screen">@import "/iui/iui.css";</style>
<script type="application/x-javascript" src="/iui/iui.js"></script>
<title>Let's do it offline</title>
</head>
<body>
<div class="toolbar">
<h1 id="pageTitle">Going offline</h1>
<a id="backButton" class="button" href="#"></a>
</div>
<ul id="menu" title="Sports" selected="true">
<li><a href="#gym"><img height="80" width="80"
src="/images/gym.jpg" align="middle"/>
<span style="display:inline-block;
vertical-align:middle">Gymnastics</span></a></li>
<li><a href="#soccer"><img src="/images/soccer.jpg"
align="middle"/>
<span style="display:inline-block;
vertical-align:middle">Soccer</span></a></li>
</ul>
<div id="gym" title="Gymnastics" class="panel">
<img src="/images/gymnastics.jpg" alt="Boys Gymnastics"/>
</div>
<div id="soccer" title="Soccer" class="panel">
<img src="/images/soccer.png" alt="Boys Soccer"/>
</div>
</body>
</html>
|
The most important aspect of this HTML is the root html element. Notice that it has an attribute called manifest. This what tells the browser that this Web page can function offline. The value of the manifest parameter is the URL to the Web page's cache manifest file. Again, this can be a full URL, though in this case it is a relative (to the given Web page) URL. The other thing to note here is the DOCTYPE for the page. This is the canonical doctype for HTML 5 Web pages. The offline Web application specification does not dictate that you use this DOCTYPE; however, it is recommended that you do. Otherwise, some browsers might not recognize the page as an HTML 5 page and might ignore the cache manifest. The rest of the HTML is just a simple example of using iUI. Figure 1 shows what this page looks like on the iPhone simulator.
Figure 1. Offline Web application running on iPhone simulator
Testing an offline application can be a little tricky. If you can, the easiest way to do it is to deploy your application to a Web server. Then you can access the page once, turn off your Internet connection, and try to access it again. If anything fails, then you might have left out some files in the cache manifest. Before you give this a try, you will need to do one critical piece of configuration to your Web server.
Listing 3 showed that you indicate the location of your cache manifest
by using the manifest attribute on the root html element of
your Web page. However, the specification for cache manifests dictates that the
browser must do an additional validation step when it downloads and processes a cache
manifest. It must check the MIME type of the cache manifest, and that type must be
text/cache-manifest. This usually means that you need to
configure your Web server to set this MIME type for a static file, or you must write
some code to dynamically create the file and set the MIME type. The former is
definitely the more efficient way to do things, but sometimes you need to do the
latter if you do not have control over the server configuration (such as a server in a
shared or hosted environment). If you control the server and if you are using a
Java™ application server, you can configure this as part of the web.xml file of
Web application. Listing 4 shows an example of this.
Listing 4. Configuring web.xml to set MIME types
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<!-- Servlets go here -->
<mime-mapping>
<extension>mf</extension>
<mime-type>text/cache-manifest</mime-type>
</mime-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
|
The key section here is obviously the mime-mapping element. In this case you are saying
that for any files that end with the .mf extension, give them a MIME type of text/cache-manifest. Of course, it is even more efficient to
serve such files from a server that is dedicated to serving static content such as an Apache Web server. In a typical Apache installation, you will just need to modify the mime.types file in the httpd/conf directory as in Listing 5.
Listing 5. Setting MIME type in mime.types
# This file controls what Internet media types are sent to the client for # given file extension(s). Sending the correct media type to the client # is important so they know how to handle the content of the file. # Extra types can either be added here or by using an AddType directive # in your config files. For more information about Internet media types, # please read RFC 2045, 2046, 2047, 2048, and 2077. The Internet media type # registry is at <http://www.iana.org/assignments/media-types/>. # MIME type Extensions text/cache-manifest mf # many more mappings... |
In both examples, you use mf for the extension of your
manifest file, since that file was manifest.mf. This is entirely arbitrary. You can
make it .manifest or .foo, as long as the extension of the manifest file matches the
extension used in the mapping in your configuration file. Note that other application and Web servers can have different configuration mechanisms. Now that you have seen the essential ingredients in creating offline mobile Web applications using HTML 5, look at a more complicated example to explore more of the capabilities of offline mobile Web applications.
In the previous example, all of the content was static. It was nice to be able to see everything in offline mode. A more typical application needs to read dynamic data from its server and Web services. To make your example more realistic, pull in some data from Twitter. If you have read the previous articles in this series, then this will be familiar to you (see Resources). To start, look at your modified HTML for this example in Listing 6.
Listing 6. Modified HTML
<body onload="init()">
<div class="toolbar">
<h1 id="pageTitle">Going offline</h1>
<a id="backButton" class="button" href="#"></a>
</div>
<ul id="menu" title="Sports" selected="true">
<li><a href="#gym">
<img height="80" width="80" src="/images/gym.jpg" align="middle"/>
<span style="display:inline-block; vertical-align:middle">Gymnastics</span>
</a></li>
<li><a href="#soccer"><img src="/images/soccer.jpg" align="middle"/>
<span style="display:inline-block; vertical-align:middle">Soccer</span>
</a></li>
<li id="online" style="display: none"><img src="/images/online.jpg"/></li>
</ul>
<ul id="gym" title="Gymnastics"></ul>
<ul id="soccer" title="Soccer"></ul>
</body>
|
The main difference is that the gym and soccer elements are now lists, and are empty.
You will fill them with tweets from Twitter on gymnastics and soccer, respectively.
Notice also a list item element with id online that shows an image that will be used to indicate to
the user whether the application is online or offline. However, this element is hidden by
default, or, the default mode is offline. The body element specifies an init function
is to be called once the body loads. Listing 7 shows this function.
Listing 7. Page initialization JavaScript
function init(){
if (navigator.onLine){
searchTwitter("gymnastics", "showGymTweets");
searchTwitter("soccer", "showSoccerTweets");
$("online").style.display = "inline";
}
gymTweets = localStorage.getItem("gymnastics");
if (gymTweets){
gymTweets = JSON.parse(gymTweets);
showGymTweets();
}
soccerTweets = localStorage.getItem("soccer");
if (soccerTweets){
soccerTweets = JSON.parse(soccerTweets);
showSoccerTweets();
}
document.body.addEventListener("online", function() {
$("online").style.display= "inline";
applicationCache.update();
applicationCache.addEventListener("updateready", function() {
applicationCache.swapCache();
}, false);
}, false);
document.body.addEventListener("offline", function() {
$("online").style.display = "none";
}, false);
}
|
The first thing that this code does is check to see if you are online or offline. If
you are online, then it displays the online image. Even more importantly, if you are
online then data is loaded from Twitter by calling the searchTwitter function. Again, this is a technique (explained in
previous articles in this series—see Resources)
that lets you search Twitter directly from the browser using JSONP. Next, you attempt
to load existing tweets from localStorage. If you are
familiar with localStorage, this is another HTML 5
capability that works quite well with offline mode. Check out Part 2 in this series to
learn more about it (see Resources). Notice for both new
searches (kicked off if you detect that you are online) and for the loading of locally
saved tweets, the showGymTweets and showSoccerTweets functions are invoked. These are similar
functions, and Listing 8 shows showGymTweets.
Listing 8. Show Gym tweets
function showGymTweets(response){
var gymList = $("gym");
gymList.innerHTML = "";
if (gymTweets){
if (response){
gymTweets = response.results.reverse().concat(gymTweets);
}
} else {
gymTweets = response.results.reverse();
}
showTweets(gymTweets, gymList);
localStorage.setItem("gymnastics", JSON.stringify(gymTweets));
}
|
This function can display locally saved tweets, new tweets from Twitter, or a combination of both, if both exist. Most importantly, it saves everything locally, building your local data cache of tweets. This is all typical code for managing both locally cached data, and live data from the servers. It allows for the application to operate smoothly whether it is online or offline.
Going back to Listing 7, the last thing you do is register event
handlers. You are registering for online and offline events. This will tell you when
the online or offline status of the browser changes. At the very least you can change the
online image, toggling if it is displayed or not. In the case that the application
comes online after being offline, you access the applicationCache object. This is an object representing all
of the resources being cached as declared in the cache manifest. In this case, you
call its update method. This method tells the browser to
check whether it detects an update to the applicationCache.
As mentioned earlier, the browser first checks for an update to the cache manifest
file. You add another event listener to check for an update to the cache available. If so, then you call the swapCache method on applicationCache. This will re-load all of the files specified in the cache manifest file.
Speaking of the cache manifest file, you need one final touch for this advanced example. The cache manifest file needs to be modified as in Listing 9.
Listing 9. Modified cache manifest
CACHE MANIFEST # Version 0.2 CACHE: offline.html json2.js /iui/iui.js /iui/iui.css /iui/loading.gif /iui/backButton.png /iui/blueButton.png /iui/cancel.png /iui/grayButton.png /iui/listArrow.png /iui/listArrowSel.png /iui/listGroup.png /iui/pinstripes.png /iui/redButton.png /iui/selection.png /iui/thumb.png /iui/toggle.png /iui/toggleOn.png /iui/toolbar.png /iui/whiteButton.png /images/gym.jpg /images/soccer.jpg /images/online.jpg NETWORK: http://search.twitter.com/ |
In this example, you have added an explicit CACHE section to
the manifest. The manifest can have different sections, but if it only has one, then
it is assumed to be CACHE and can be omitted. The reason that you were explicit here is that you also have a NETWORK section. This indicates to the browser that anything coming from the domain specified (in this case search.twitter.com) should be fetched from the network and never cached. Since you are locally caching search results from Twitter, you certainly do not want the browser to do any more indirect caching of queries. Now, with this in place, the application will always load live tweets from Twitter, but it will also store those tweets and make them available to the user even when the user's device loses connectivity.
Web applications have come a long way since the days of Mosaic. Mobile Web applications have evolved even more. The days of WAP phones that only speak Wireless Markup Language (WML) are shrinking. Now you ask things of your mobile browsers that you don't even ask of their bigger desktop brethren. Offline functionality is one of those features. The standards specified in HTML 5 go a long way to making it simple for developers to offline enable their mobile Web applications. In the next article in this series you will look at how another HTML 5 standard, Web Workers, can dramatically improve the performance of mobile Web applications.
| Description | Name | Size | Download method |
|---|---|---|---|
| Article source code | offline.zip | 437KB | HTTP |
Information about download methods
Learn
- Creating mobile Web applications with HTML 5, Part 2: Unlock local storage for mobile Web applications with HTML 5 (Michael Galpin, developerWorks, May 2010): Explore an important new feature in HTML 5 for wireless apps. With the standardization of local storage and a simple API, store large amounts of data on the client and improve performance.
- Creating mobile Web applications with HTML 5, Part 1: Combine HTML 5, geolocation APIs, and Web services to create mobile mashups (Michael Galpin, developerWorks, May 2010): Find and track location coordinates to use in various Web services. Use the various aspects of the geolocation standard with HTML 5 and popular Web services to create an interesting mobile mashup in Part 1 of this series.
- Creating mobile Web applications with HTML 5, Part 4: Use Web Workers to speed up your mobile Web applications (Michael Galpin, developerWorks, June 2010): Web Workers bring multi-threading to Web applications. Learn to work with Web Workers and which tasks are most appropriate for them.
- Creating mobile Web applications with HTML 5, Part 5: Develop new visual UI features in HTML 5: Add Canvas, CSS3, and more semantic elements to mobile Web apps (Michael Galpin, developerWorks, June 2010): Provide full 2-D graphics in the browser with Canvas, the most eye-catching of the new UI capabilities in HTML 5. Learn to use Canvas and other visual elements in your mobile Web applications.
- HTML 5 Offline Application Cache documentation: Take a look at Apple's more detailed information on manifest files and application cache.
- Offline resources in Firefox: Offline is not just for mobile. Read about how Firefox implements this standard in Mozilla.
- Create Ajax applications for the mobile Web (Michael Galpin, developerWorks, March 2010): Explore how to use Ajax, a key part of any mobile Web application.
- New elements in HTML 5 (Elliotte Rusty Harold, developerWorks, August 2007): HTML 5 is not just about JavaScript. Read about some of the new markup in HTML 5.
- Android and iPhone browser wars, Part 1: WebKit to the rescue (Frank Ableson, developerWorks, December 2009): Do you like the mobile Web application approach using HTML 5 approach, but still want your application in the iPhone App Store and Android Market? See how you can get the best of both worlds in Part 1 of this two-part article series.
- Dive Into HTML 5: Check out this free book for a great look at HTML 5 detection techniques as well as the many features of HTML 5.
- Safari Reference Library: Keep this resource handy if you develop Web applications for the iPhone.
- W3C HTML 5 Specification (Working Draft, March 2010): Explore this definitive source on HTML 5.
- More articles by this author (Michael Galpin, developerWorks, April 2006-current): Read articles about XML, Eclipse, Apache Geronimo, Ajax, more Google APIs, and other technologies.
- My developerWorks: Personalize your developerWorks experience.
- IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
- XML technical library: See the developerWorks XML Zone for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
- developerWorks technical events and webcasts: Stay current with technology in these sessions.
- developerWorks on Twitter: Join today to follow developerWorks tweets.
- developerWorks
podcasts: Listen to interesting interviews and discussions for software developers.
Get products and technologies
- Modernizr project: Get a comprehensive utility for detecting HTML 5 features including like localStorage, Web Workers, applicationCache and others.
- The Android Developers Web site: Download the Android SDK, access the API reference, and get the latest news on Android.
- iPhone SDK: Get the latest iPhone SDK to develop iPad, iPhone and iPod touch applications.
- The Android Open Source Project: Get the open source code for the Android mobile platform.
- The Google App Engine SDK: Download Java and Python tools to build scalable Web applications using Google.
- IBM product evaluation versions: Download or explore the online trials in the IBM SOA Sandbox and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- Participate in the discussion forum.
- XML zone discussion forums: Participate in any of several XML-related discussions.
- developerWorks blogs: Check out these blogs and get involved.

Michael Galpin is an architect at eBay. He is a frequent contributor to developerWorks. He has spoken at various technical conferences, including JavaOne, EclipseCon, and AjaxWorld. To get a preview of what he is working on next, follow @michaelg on Twitter.




