iPhone Offline Web Apps – the RESTful Way – Part 1 of 2

html5 [Concrete/Very Interesting] Whist building a web application for the iPhone, I was presented with a problem. One of my team managed to replicate the work we've been doing using Objective-C. I looked at the code – didn't like it but it worked. The problem was, it worked offline.
‘Can't have this’ I thought, so I embarked on making my application offline capable.
Sounds easy – well in principle, it is. In practice, there were a few pitfalls that I thought I'd better blog about. Of course, I had a cold and had just received an H1N1 vaccination, so maybe on a good day…
Anyway, here is some background and my tips to Offline Web Apps, the RESTful way.

HTML5 Offline Application Cache

You can find out lots of good stuff about this on the Internet. The official reference from Apple can be found here. The key is to create an cache manifest file naming all your resources - HTML files, Scripts, Style Sheets, images, and so on… You then reference the manifest file (.manifest) in your HTML page(s) in the HTML tag:
<html xmlns="http://www.w3.org/1999/xhtml" manifest="app.manifest">
When the application runs, it follows (roughly) the logic outlined below:

  • Manifest Named – load the server manifest
  • If no response from server, load manifest from cache and all resources named in the manifest from cache
  • If server manifest found, compare to cached manifest – byte by byte comparison
  • If server manifest is different to cached manifest, load all the resources named in the manifest from the server
Using a manifest and application cache is easy enough but there are some gotchas, so here are some tips to help you along:

Tip1: Test in Safari 4 on your desktop
Safari is a really good emulator for the iPhone and is a excellent place to start. It is far easier to test your code, clear the cache, manage resources, and so on, while working on your laptop than it is on the iPhone. And you get Developer Tools which is a real bonus. Web Inspector is a superb debugging tool will give you everything you need to debug your app, resources and even the database.

Tip2: Add the manifest at the start of development
If you start with offline, you can quickly ensure you have got the basic structure of the manifest and resources correct. My tip is to implement the offline cache when there are only static resources to worry about, before we complicate matters with service calls. It’s much easier to validate.

Tip3: Version your app and manifest.
When working offline, your cache is only refreshed if the application fetches a newer manifest file from the server. I will say this again – changes to your application won’t be seen, that is, you will read from the existing cache up until the manifest changes. So to keep everything in line, it is a good idea to put a version string into your application, something you can see from the app or a debug menu, and a copy of that version in your manifest file. Every time you make a code change, change the version in the app and in the manifest.


CACHE MANIFEST
# Version 0.9.4.1129.004
 
NETWORK:
/iretailpassportsvc/clientservices.svc
 
CACHE:
index.htm
 
images/arrow.png
images/background.png

By doing this you ensure the manifest changes along with the application and because the manifest changes, your cache will update with your changes.

If you are generating your manifest server side in PHP, ASPX or similar, you should be able to automate this, creating a version with a unique number or date/time stamp (see Tip 5:).

One other thing. When you deploy and run your app after a change, the change is loaded to your cache for future executions. But the first time running after deployment, you won’t see a change in your app. Seems odd but it is just like releasing any program update – the update is sent down to your machine, but you only see the update the next time you run. So when you are testing, remember to:

  • Deploy
  • Run to refresh the cache
  • Re-run to see the change (check the app version).

Tip 4: Make sure the manifest file is served with type "text/cache-manifest"
You have to ensure your web server recognises the manifest file type and associates this with the required MIME type.

IIS 7 is especially irritating. It uses .manifest for ‘Click Once’ (now back off, don’t start me on that subject). So it recognizes this extension but associates it with the MIME type "application/x-ms-manifest". This won't work. You can change this at the server level or application/file level in IIS – either way, change the MIME type to "text/cache-manifest".

I found a very cool site to test the HTTP Response Headers – if you request the manifest file, you can check your web server is serving with the correct MIME type. The site is called http://web-sniffer.net/ . You can also use tools like Fiddler2.

Tip5: Make sure the manifest file contents are 100% correct
And I do mean 100% correct. You need to name ALL the resources used to serve up your app. If anything is missing, the app will not load from the cache. Worse still, if it was working and you subsequently make a mistake in the manifest file, it will load from the old cache, and you will not see your changes. You could be puzzled for hours trying to work out why you can't see your changes!

The simplest approach to ensure you have a correct manifest file is to list all the files in your project, including files in sub-directories. You need to specify the files and their paths relative to the manifest file and the manifest file should be placed in the application root.

As an alternative strategy, you can dynamically generate the manifest together using server side code (such as PHP or ASPX).

For example in PHP:

<?php
$version "3.1.0000";
header('Content-Type: text/cache-manifest');
echo "CACHE MANIFEST\n";
echo "#Version: ".$version;
 
$dir = new RecursiveDirectoryIterator(".");
foreach(new RecursiveIteratorIterator($dir) as $file) 
{
if ($file->IsFile() &&
$file != "./manifest.php" &&
substr($file->getFilename(), 0, 1) != ".")
{
echo $file . "\n";
}
}
?>


Save the file in your app root as manifest.php, then in your HTML file(s):


<html xmlns="http://www.w3.org/1999/xhtml" manifest="manifest.php">

Tip 6: Testing in ‘Airplane Mode’
You should be able to test your app at this stage. On the iPhone, you can place the phone into “Airplane Mode”. If your offline cache is working, you should be able to load and run you app.

If it is not, you will get an alert informing you you are not connected to the Internet.

A bit tricky but…

Ok, that was a bit tricky – especially if you have “Man Flu”, and part of the problem was I wasn’t convinced this “offline mumbo jumbo stuff’ really worked. But it does. And when it does it opens up a whole world of opportunities for writing applications for the iPhone.

But that’s not the whole story – I still hadn’t managed to build a offline RESTful app.

What about your service calls?

[Part 2 Discusses a strategy for RESTful caching].

Comments

Popular posts from this blog

"Better to say nothing and be thought a fool..."

Carving Rings

Using IActiveAware and INavigationAware