Creating an application using Amazon's Mobile App Distribution Program is a great way for developers who have hosted web apps to create downloadable apps available on the Amazon Appstore. Web app developers benefit from the increased discoverability that the store provides when users are searching for new apps, as well as being reminded to use the web app by the icon on their device's home screen afterwards. In addition, all of a user’s linked devices that use the Amazon Appstore will have the icon waiting in their Cloud list of apps as well.
And because web apps are hosted online, developers have increased flexibility to re-use existing assets and make changes or fixes to the app quickly and easily, without having to re-create a new app that has to be re-installed by the end user. But what happens if the user wants to use the app offline? Obviously, if the app relies on live server-side content - such as streaming videos or airline reservations - then obviously it's not going to work. But if the web app is self-contained and doesn't need to talk to a server for its core functionality - like most games - then being able to take the app offline is something that should be an option for users.
Happily, enabling your web app to be used offline can be done using HTML5's built-in Application Cache with only a few small changes to your code. Below I'll outline the steps you need to take to create a basic offline web app. It's surprisingly easy to set up, but beware! Application Cache has a well deserved reputation for being difficult for developers to get a handle on.
Offline Web App Walkthrough
1. Create Manifest File
Here's the content of a basic manifest file:
# Version 1.0
- The first line needs to be CACHE MANIFEST.
- The second line in this example is just a comment, but is useful to make changes to your web app by simply incrementing the version number. Note: Only changes to the manifest file will invalidate the cache.
- The third line begins the CACHE: section where you list out the asset files used by your web app, either relative to the location of the manifest file, an absolute path or complete URL. Note: DO NOT list app.appcache in your manifest.
- The NETWORK: section has a wildcard which permits the browser to download files that are not listed in the CACHE: section. Note: Without the NETWORK: section, the browser will ONLY re-request files listed in the CACHE: section after the initial page load.
2. Confirm Server Settings
You need to also make sure your web server serves the correct MIME type for the manifest file. For Apache, it looks like this:
AddType text/cache-manifest .appcache
You also need to makes sure the manifest file is not being cached on the server. If the HTTP Cache-Control header for the manifest file doesn't update, or a 304 Not Modified is return, then the web engine won't be able to see if the manifest file has been changed or not, which is the only way to invalidate the offline cache.
3. Add Manifest Attribute
You then need to add an attribute to the tag of every HTML page you serve pointing at the manifest file, like this:
4. Add Update Script
Your web app should now be offline enabled! If you have Python installed, you can test this by setting up a local server to see what's happening both on the server and in the browser.
email@example.com:~/html5demos/offline$ python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...
220.127.116.11 - - [21/Jan/2014 13:42:52] "GET / HTTP/1.1" 200 -
18.104.22.168 - - [21/Jan/2014 13:42:52] "GET /app.appcache HTTP/1.1" 200 -
22.214.171.124 - - [21/Jan/2014 13:42:52] "GET /main.css HTTP/1.1" 200 -
126.96.36.199 - - [21/Jan/2014 13:42:52] "GET /main.js HTTP/1.1" 200 -
188.8.131.52 - - [21/Jan/2014 13:42:52] "GET /logo.png HTTP/1.1" 200 -
If you request the page again, you'll see that *only* the manifest is requested.
184.108.40.206 - - [21/Jan/2014 13:43:12] "GET /app.appcache HTTP/1.1" 304 -
By modifying the manifest file and reloading, you'll see that all the files listed will be re-downloaded again.
You can also connect the Amazon Web App Tester to see the client side of the process as well by using Remote Debugging. (See our previous overview of setting up the Tester here.) In the screenshot above, I've connected to a Kindle Fire HDX and loaded a demo offline web app stored on Github. By looking at the Resources tab and drilling down into the Application Cache folder, I can see the assets that are cached locally, and a log of the Application Cache events.
Application Cache Gotchas
Conceptually, it's important to understand that once you've enabled a manifest, your web app is now offline first and forever. Let's repeat that for clarity: OFFLINE FIRST AND FOREVER.
OFFLINE FIRST means:
- Your web app's files will then always be loaded from the offline cache first, and then a request will be made to the server for the manifest file to see if there have been any updates.
- The browser will not automatically refresh if the manifest has changed. It will in fact download the files from the server, but it will wait until the next time the page is requested to use them. This is why the script in step 4 above to detect a manifest change and immediately refresh the page is important.
- The only thing that can invalidate the offline cache and trigger a re-download of files is a change in the contents of the manifest file - not just the timestamp.
- There is no programmatic way to invalidate the offline cache from the browser. Even changing or deleting the manifest attribute in the tag will not invalidate the cache.
- Until the browser requests a manifest and receives a 404 or 410 from the server, it will continue to consider the web app as being offline and use the last downloaded version, rather than updating from the server.
Summary and External Resources
The info above should be able to get you started with offline web apps. Once you've added in the manifest, your web app will be available offline the next time your users load up your app. Fair warning: This can be a tricky feature to implement - especially if you misconfigure or forget some of the steps above. Getting the browser to let go of the manifest and refresh your code can be incredibly frustrating. I think the upside is worth it though, as enabling your web app to be used anywhere a native app can be used is incredibly satisfying.
To get more information about Application Cache, I encourage you to check out these great articles which dive into the topic in even more detail.
In future posts, I'll expand on offline apps by looking at topics such as offline data storage and efficient caching strategies.