How to create offline webapps on the iPhone

Apr 28
 
How to create offline webapps on the iPhone

Recently Google launched their latest mobile version of Gmail optimised for iPhone and Android based browsers. One of the features that stood out was the offline access thanks to the browsers support of html5 application cache.

Documentation on the application cache feature supported in safari iPhone 2.1+ is scarce and of that documentation it doesn’t go into great detail. The best place to learn about this is on the Safari DevCenter under the mobile section, there it has 2 documents introducing the user to offline webapps; the first is a quick rundown on just the manifest file and the second article touches on a few more features available to offline webapps such as the javascript events for updating the cache when the user is online. We’ll delve into these later in the article but first let’s take a look at a working example.

Update: Added additional information about the event summary and the order in which events get executed. Added link to useful tool for sniffing file Content-Types.

To see the offline webapp in action, load the demo on your iPhone, then turn Airplane Mode on, re-open Safari and reload the demo. This time it will fetch the files from the cache that was created on the initial load.

How does it all work?

To get a basic offline webapp up and running is incredibly simple but it does have one caveat which tends to get a lot of people frustrated quickly when for some reason the offline feature isn’t working. We’ll explain that issue shortly.

The first thing we need to do is create what is called a cache manifest file which has references to all the resources we want to save. Whether it be JavaScript, CSS, images or html, below we can view the manifest file used in the demo.

CACHE MANIFEST

# Offline cache v1
# html files
article.html

# css files
assets/_styles.css

# js files
assets/_javascript.js

# images
assets/ico_ninja-star.gif

The manifest file is a simple plain text file that holds the file names you wish to cache, the paths are relevant to where you saved the manifest file which is recommended to be in the root of the site. This file will be saved as filename.appcache, where filename is anything you wish. Lines that start with a # are comments and are ignored by the cache.

Referencing the cache file

We now have our cache manifest file setup and named, the next thing we need to do is reference that file in the html so this offline access will function for the specified files in the manifest.

<html manifest="thecssninja.appcache">

The manifest file is referenced in the html tag through the manifest attribute and just points to the filename.

Now the one issue that catches a lot of people when trying this out is not setting up the mime type correctly in their chosen web server. Whether it be IIS, Apache or something else, you’ll need to make sure that the .appcache file is fed through as text/cache-manifest.

For Apache you can add the text/cache-manifest to the mime.types file found in the conf folder in apache and add the following to the bottom of the file.

# html 5 application cache - offline access
text/cache-manifest    appcache

For IIS open up the IIS manager found in Control Panel > Administrative Tools > Internet Information Services double click the Mime Types icon in the manager and scroll down the list until you find the .appcache file and edit the mime type to have text/cache-manifest.

IIS 7.0 Manager Mime Types

That’s it, to get a basic offline webapp to work is incredibly simple all it takes is the manifest file to specify which files to cache, declare it in on the <html> tag using the manifest attribute and you have yourself a site still accessible even if the user has no network connection.

UPDATE: GeoNomad in the comments suggested a great tool to make sure your manifest file is being fed through with the correct mime type, Web Sniffer. I put my manifest file through the Web Sniffer tool, you can see that the Content-Type is set as text/cache-manifest.

Updating the cache

If you want to update the cache you either need to change/add file references to the manifest and then tell the cache to update. Updating a file that the manifest calls will not make the cache reflect the changes. The mozilla developer article on applicationCache makes a good suggestion to version your manifest file as the JavaScript events described below will only fire if there is a change to the manifest file. To update the cache we have:

window.applicationCache;

This object has various stages depending on what the cache is doing which can be checked by using the .status method. There are 6 different stages:

  • Status 0 (UNCACHED) is returned which means that there is no cache available
  • Status 1 (IDLE) is returned means the cache you have is currently the most up-to-date
  • Status 2 (CHECKING) is returned means there is a change in your manifest file and it is checking it for changes
  • Status 3 (DOWNLOADING) is retuned means changes have been found and they are being added to your cache
  • Status 4 (UPDATEREADY) is retuned means your new cache is ready to be updated and override your current cache
  • Status 5 (OBSOLETE) is returned means your cache is no longer valid meaning it has been removed

These available statuses can be attached to the applicationCache object with event listeners so we can tell the web app what to do on what status. In our case we want to update the cache to reflect changes we have done.

var webappCache = window.applicationCache;

function updateCache() {
    webappCache.swapCache();
}

webappCache.addEventListener("updateready", updateCache, false);

In the above example we attach an event listener to the applicationCache looking for the updateready status which means there is a change to the manifest file and our cache is ready to be updated we do so by using the swapCache() method.

There is 2 more event handlers which do not appear in the window.applicationCache.status these are part of the event summary. Those are error & progress. We’ll take a look at how to use the error event, the progress event is basically the same as the downloading event handler.

var webappCache = window.applicationCache;

function errorCache() {
    alert("Cache failed to update");
}

webappCache.addEventListener("error", errorCache, false);

All the error event handler does is return the specified function we attached in the event listener when the cache is not available or does not exist.

Event summary

In the applicationCache we have various events available so when the cache is being updated, or as mentioned above when something goes wrong. We can attach to those events and keep the user informed on what is happening. These events will execute in specific order based on what is happening with the cache and therefore give us useful hooks to represent that back to the user.

Pete who commented below and needed a way of indicating to the user that the cache was downloading prompted me to look further into the events that get fired and which ones would be useful in this scenario. I created a demo which will indicate to the user that the cache is downloading by showing a loading icon and once the cache had finished downloading, the loader would be hidden.

The event order for this example was as follows:

  • checking – The page loads and the cache is checked for any changes.
  • progress – The download event actually gets fired before this but we don’t need to hook into that. The progress event will fire for each file that is referenced in your manifest until the cache has finished downloading.
  • cached – The cache has successfully downloaded and the cached event is fired so we utilise that to hide the loader.
  • updateready – This event is fired so we can then swap the old cache with the newly downloaded one.

In the above mentioned demo we also attached event listeners to the error and noupdate events so we can handle errors and if the cache is already up-to-date.

Is the user online

There is also a new method on the navigator object called onLine which returns a boolean value if there is a network connection or not.

navigator.onLine

In the article example the onLine method is used to update the title if the user is on/offline.

Only the beginning

The applicationCache is not yet finalised and is of course subject to change with newer and refined features. I’m sure there will be additions in the upcoming iPhone OS 3.0 release. If there are updates unfortunately these cannot be discussed until the NDA is lifted. But of course this won’t stop us speculating.

Some of the features available in applicationCache on firefox 3.1 and safari 4 will inevitably be added in future releases of the iPhone OS. Such as the NETWORK: and FALLBACK: sections in the manifest file, these allow for the developer to specify a file they wish to never cache or to have a file load if something fails with the first option.

Short sharp facts about the appcache: http://appcachefacts.info/

 
 

Post filed under: css, javascript, xhtml.

Skip to comment form.

Comments

  1. Very interesting … but is there a limit as to what can be cached? Just tried based on your model, total site is 5 mb size with hundreds of small files (4 – 15 kb). It just will not cache, while your sample on the same server performs well.

    cheers

    pete, June 17th, 2009
  2. No I haven’t come across a size limit nor have I found any references anywhere to indicate that there would be a size limit. One thing that did stop my web app from caching was misspelling file name in the manifest, have you made sure your manifest hasn’t got any spelling mistakes? A good way to debug any issues is to attach an event listener to the error event and see if it’s failing the cache, you can also check the status of the applicationCache and see what it’s returning. Take a look at the JavaScript file I’m using for the example it has a switch statement in their and logs useful messages to the browser console to see what the status is.

    The Css Ninja, June 18th, 2009
  3. Hi, I learned last night that the current cache limit for webapps is supposed to be 5mb. I reduced some stuff, so that took care of one thing.

    My true problem seems to be, when I go into a hierarchy. All links straight off the index.html page work perfectly well, but when I do the following, safari on the iPhone (not on the mac) crashes gloriously:

    FILE: my.manifest
    Content:
    CASH MANIFEST
    this.css
    that.js
    Vegetables/AtoZ.html
    Vegetables/Spinach.html
    Vegetables/Chickpeas.html

    FILE: index.html
    Links to:
    Vegetables/AtoZ.html
    Vegetables/Spinach.html
    Vegetables/Chickpeas.html

    Offline all three links work fine, however:

    When I tap on Vegetables/AtoZ.html and from within there want to get to the Spinach or Chickpea file Safari iPhone crashes.

    It is as if there was an undocumented “it only works on the the first hierarchy level”.

    Have you tried a second or third level hierarchy with manifest yet? Be interested to hear from down under.

    Cheers

    pete, June 19th, 2009
  4. Just quoting your email so the comments make sense.

    Hi, just put 300 files flat next to index.html and voilà …. all works fine. Looks like it currently only likes it “flat”…

    So your saying you are just referencing all the files directly and not listing their folders names before and that caches all of them? Can you provide a link to a test version that crashes the browser and one that works?

    …Tell me: When the phone or touch is online and checks for an update manifest, etc. can one let the user know that that is what it is doing and allow him to stop it or not? Or just advise?

    You could in theory attach to the downloading event handler for the cache webappCache.addEventListener(“downloading”, promptUser, false); which would call a prompt to ask a user if they would like to cache the site. Then depending on their answer either continue or throw an exception.

    The Css Ninja, June 19th, 2009
  5. I have a question on the applicationCache status, having copied your js sample:

    Changing a file and changing the manifest I get Status 2 (checking) in an alert box which I place at the top:

    (function(){
        var webappCache = window.applicationCache;
     
        alert(webappCache.status);
        ...
    })();

    Afterwards the newly modified file is being displayed.

    At which point can I get in with an alert box to actually confirm that the cache has indeed been updated?

    I tried the following, but none of the desired alert boxes trigger:

    function updateCache() {
        if(webappCache.status == 4)
        {
            alert ("We wil update. Pre");
        }
        webappCache.swapCache();
        /* ahora = new Date() */
     
        if(webappCache.status == 4)
        {
            alert ("We have updated. Post");
        }
    }

    BTW: The hierarchical problem seems to be solved. Somebody else looked into it and it might have been, because the manifest contained files which did not exist anymore. Preciser analysis in a few days.

    pete, June 23rd, 2009
  6.  if(webappCache.status == 4)
    {
    	alert (”We wil update. Pre);
    }

    That will always return false, what you need to do is attach an event listener to the status itself. Status code 2 will always return first if there is a change to the manifest, followed by downloading and updateready. Just do the following:

    webappCache.addEventListener("updateready", updateCache, false);

    This will fire the updateCache() function and alert you that the cache has been updated.

    BTW: The hierarchical problem seems to be solved. Somebody else looked into it and it might have been, because the manifest contained files which did not exist anymore. Preciser analysis in a few days.

    Yep same issue I had when doing the demo, although I misspelt my file names therefore it was looking for files that didn’t exist.

    The Css Ninja, June 24th, 2009
  7. Okay.

    You Ninja. Me not even a half boiled rice corn.

    Will this give me the right message upon update?

    (function(){
        var webappCache = window.applicationCache;
        function updateCache()
        {
            if(webappCache.status == 4)
            {
                alert ("We just updated.");	
            }
            webappCache.swapCache();
        }
        function errorCache()
        {
            console.log("We are viewing it offline.");
        }
        window.addEventListener("load", loaded, false);
        webappCache.addEventListener("updateready",updateCache,
        false);
        webappCache.addEventListener("error", errorCache, false);
    })();
    pete, June 24th, 2009
  8. Lol, we’ve all got to start somewhere.

    Your code looks fine only change I would make is removing the if statement in your updateCache method as that only gets fired when the updateready status is passed to listener which is already status 4 so no need to check for it again. Your onload event listener doesn’t need to be there if your not calling anything after load.

    The Css Ninja, June 25th, 2009
  9. tks a lot. and now an off-topic one: the app works fine when i run it on my local server and pick it up with the iphone as part of the local network. the moment i upload the whole thing to the external providers place no caching happens. i am told it was “bad formatting” of the manifest file and that the provider reformatted it, but nothing changes the non-workability of caching on the distant server. what could be the right debug procedure? .. email me privately, if you wish.

    pete, June 27th, 2009
  10. Have you set up the .manifest extension to be fed through as text/cache-manifest in your mime types on the server your uploading to? If it’s working on your local there should be no problem with your manifest file.

    The Css Ninja, June 27th, 2009
  11. on the external one the declaration is in an htaccess file.

    pete, June 27th, 2009
  12. I did have trouble setting the mime type through my htaccess file on my hosting, I ended up setting the mime type through my admin control panel. Just do a check for the applicationCache status to see what it’s returning on your server, if you get 0 it would most likely mean the mime type isn’t setup correctly on the server.

    The Css Ninja, June 27th, 2009
  13. problem sorted. cause: reference in an html file to a css class which was no longer defined …. would you like a little js-contract? need a progress indicator during download so people know it is happening and do not interrupt too early (as downloads are approx. 4mb).

    pete, July 5th, 2009
  14. If you need to indicate that something is happening I would show an animated gif icon and display it when the cache is downloading, then use the updateready event to hide once the download is done e.g.

    var webappCache = window.applicationCache;
     
    function downloadingCache()
    {
    	// Show animated gif
    }
    function updateCache()
    {
    	webappCache.swapCache();
    	// Hide animated gif
    }
     
    webappCache.addEventListener("downloading", downloadingCache, 
    false);
    webappCache.addEventListener("updateready", updateCache, 
    false);

    This won’t give you exact progress, but it will indicate to the user that something is happening and if you position a container over the top of the site with the animated gif this will stop the user from doing anything until it’s loaded.

    The Css Ninja, July 5th, 2009
  15. I implemented this and it works amazingly well, in Safari. But what I really want is for it to work with UIWebView, and it doesn’t seem to be doing that – does anyone have any idea on putting the two together? Any success stories?

    Gavril, July 10th, 2009
  16. Just got a brand new 3GS and trying to get some off-line webapps going. I’ve been having some trouble with mine not working offline and just tried yours with the same results.
    I notice through using a proxy that the phone is never requesting the “manifest” file. Seems like a bug in the phone?
    What versions have you had this working on?

    Mark, July 12th, 2009
  17. @Gavril – I dont see why it wouldn’t work in a native app as it would essentially be calling an instance if safari in your app. I’d be interested to know if you find the solution.

    @Mark – That’s strange I have the 3GS also and it’s working fine. Try enabling the debug bar in safari, the demo logs messages to the console it should let you know if something has gone wrong.

    The Css Ninja, July 12th, 2009
  18. So I try to get the anim.gif to run by doing this:

    function downloadingCache()
    {
    	// Show animated gif
     
    	function makewindow() {
    		newWin = open("", "displayWindow", "height=400,width=600");
    		newWin.document.open();
    		with (newWin.document) {
    			write("On the fly");
    			write("This window made in js ...");
    			write("&lt;img src='imgs/anim.gif'");
    			write("");	
    		}
    	}
    }

    After that one I have this:

    function updatedCache()
    {
    	// Hide animated gif
    	webappCache.swapCache();
     
    	alert ("The app has been updated. Please refresh to use the 
    		latest version");
    }

    The log file gives me the protocol “Downloading” but does not show the page i create to show the anim.gif

    and also I get this javascript error message:

    an error for line “webappcache.swapCache()” -> INVALID_STATE_ERR: DOM Exception 11

    Bit stuck now. Still half-boiled rice corn. ;-)

    pete, July 14th, 2009
  19. Why are you trying to open a new window? I put together a quick demo that simulates lots of content being cached. It will show a loading icon when the downloading status is passed to the applicationCache when the cache has finished downloading and the updateready status is returned the loading icon will be hidden. I delayed the hiding of the loading icon for 2 seconds using a setTimeout, for your implementation I would just do the hiding in the updateCache function.

    The Css Ninja, July 15th, 2009
  20. Learning, master, learning … I thought I need to open a window so I can close the thing again afterwards. Obviously that is not the case, so I’ll have to learn how to do that. — In the demo, thank you very much indeed for your time, the icon does not disappear however. It runs and runs and runs. ;-)

    pete, July 15th, 2009
  21. Ok so the demo should work as expected now, thanks to your scenario I have discovered quite a few more useful bits of information. I’m going to update the article in the coming days and shed some more light on those discoveries.

    The Css Ninja, July 16th, 2009
  22. Wonderful! The demo works in showing the gif.

    Now where would I go and look for a mistake I made, when in the next step in the line

    “webappCache.swapCache();”

    I get this error message: INVALID_STATE_ERR: DOM Exception 11

    pete, July 20th, 2009
  23. Can’t really say without actually looking at the site. Based on the W3C explanation of the exception.

    If an attempt is made to use an object that is not, or is no longer, usable.

    Looks like you’re potentially trying to access webappCache object outside of it’s current scope.

    The Css Ninja, July 20th, 2009
  24. Seem to have solved the EXCEPTION 11 error:

    I deleted under

    function updateCache() {

    this:

    webappCache.swapCache();

    … and inserted

    loader.display = “none”;

    … plus an alert box to advise the user that the update has been completed.

    The modified files have obviously been downloaded to the iPhone cache and the app works. No “swapCache” required. — This is good, but what exactly happened?

    PS: Is the gif your copyright or public domain?

    pete, July 28th, 2009
  25. Hmm the swapCache() method is what changes over the current cache with the updated cache. Removing that will never update the cache, even though it has detected a changed, downloaded it and fired the alert to inform the user that this has happened without swapCache all of that work will be for nothing. If you reload it will load the old cache as the new cache was never swapped.

    The gif was generated from ajaxload.info just generate your own one there to better suit your web app design.

    The Css Ninja, July 28th, 2009
  26. Well that IS the strange thing: SwapCache() is off, after the update and subsequent turning on of flight mode on the iPhone all changed files appear as changed, all other files can be called without problems. — Really strange. As if progresscache was performing an immediate caching.

    pete, July 28th, 2009
  27. Ah but that’s the issue, SwapCache is only called if the user already has a cache. If there is an update SwapCache will swap the old cache with the newly downloaded one. If you try to push out an update to one of your cache files all the events will fire and it will act like it’s downloading a new cache but without the final SwapCache method in the onupdateready event it will never change over and the user will be stuck with the original.

    The Css Ninja, July 29th, 2009
  28. UPDATED: Updated article to reflect some of the ideas expressed in the comments.

    The Css Ninja, August 1st, 2009
  29. There still seems to be one problem somewhere along the line with “some” users.

    While 4 testers have no problems updating, one tester with an up to date (3.0) iphone 3G reports that the update messages goes on and on and on. He finally escapes the scene, restarts the iPhone and everything appears to have been updated. — This is something we talked about before. It is a hangup at the swapcache point.

    The javascript call now comes at the end of the html file (just before ) so the loader div is before it.

    So it works almost as it should, but this one tester gives me a mystery, and as I had the same phenomenon before I just wonder what is not known about updatecache which could cause this.

    As a separate note: Your in-depth insight into these new features and your helpfulness is very much appreciated on this side of the globe. Thanks.

    pete, August 1st, 2009
  30. Hi, I’m probably the noob-iest one here, but I’m trying to make my soundboard web app work while offline. I haven’t gotten it to work with my 50+ images, but I’m willing to pursue it once I’m sure that it can cache mp3 files. Is MobileSafari capable of caching mp3s specified in the manifest?

    Thanks for all your help, your site has been a great resource!

    Harry Shamansky, August 19th, 2009
  31. I believe based on previous comments there is a size limit of 5mb, though this is unconfirmed. If your total assets are higher than that it may not cache or will return an error. You should be able to cache any file regardless of format, it will depend more on the file size than type.

    You’re very welcome, thanks for reading.

    The Css Ninja, August 19th, 2009
  32. That makes sense, though I’ve also heard that the user is prompted if the cache is over 5mb.

    On an unrelated note, there isn’t a way to play a short sound without the full screen player opening in a web app, right? It’s not a big deal, as it opens and closes pretty quickly, but it still would be great if there were an alternative.

    Harry Shamansky, August 19th, 2009
  33. I’m not sure if the iPhone prompts the user for more space, I know the desktop does.

    Yeah audio and video on the iPhone will only play through the fullscreen player no way around it.

    The Css Ninja, August 19th, 2009
  34. This is great stuff!
    I got this working perfectly in the regular browser but have had no success getting it to work within a UIWebView. It returns Status 0 all the time within the view.
    If you or anyone has had any luck please let me know! Thanks for the great write up.

    Josh, August 20th, 2009
  35. Yeah a few people have mention not being able to get it working in UIWebView which is strange. Will keep you posted if I find out anything.

    The Css Ninja, August 21st, 2009
  36. Hi there,
    I’m trying to set this Cache thing up and I can’t seem to make it work.

    I made the cache.manifest file and it’s correct.
    I added the MIME type in my mime.conf file (Apache locally installed on my iMac).

    I load the app from Safari on the iPhone, save it on my homescreen. But everytime I load it up, i get the spinner in the status bar RELOADING everything.

    It’s not a matter of life and death right now, as I can run the “App” locally instaled on the iPhone through SSH, but it would be cool to cache everything on the phone.

    Alex Buga, September 2nd, 2009
  37. Hi Alex,

    Have you attached the various events to your applicationCache object to see if you are getting an error in the caching. Make sure in your cache file that there are no misspelt assets or non existent references in there otherwise it won’t cache.

    The Css Ninja, September 2nd, 2009
  38. Hi Ninja,
    do you have any news about the UIWebView not working with this method?

    Robert Selldorf, September 2nd, 2009
  39. Hi Robert,

    I did post on a thread in the Apple developer forums asking why the appCache wouldn’t work in UIWebView and it doesn’t look good. I haven’t got official word from an Apple employee, but from what people are saying it’s not supported.

    The Css Ninja, September 2nd, 2009
  40. hi!

    1- I have a problem with your demo, with firefox 3.5.. when I reload the page, i get ”

    Content Encoding Error
    The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.

    2- I just created a manifest file on my website. The firefox preference menu show “mysite” in the list of cached sites… Does it mean the mime type is set?
    it’s 0bytes, though

    thanks cssninja!

    yvan, September 6th, 2009
  41. edit : answer for #2 – the mimetype wasnt set but I could edit .htaccess

    yvan, September 7th, 2009
  42. Is that an issue with the demo I’m hosting on my site or is it the demo files you have downloaded? I’m using FF 3.5.2 and I don’t get that error, I do however get a JavaScript error because of the google analytics in the page but that doesn’t stop the page from caching.

    The Css Ninja, September 7th, 2009
  43. I have had no problem creating offline apps this way, but I have a problem getting rid of them.

    If I delete the icon from the screen and then access the same URL in safari, it starts to load and then crashes. (OS 2.2).

    I have tried resetting the iPod but the crash persists. Clearly something remains in safari that tells it to look in the now non-existent cache.

    I have tried clearing the History, but no joy.

    Is there any advice on how to remove offline apps properly once you have created them?

    TIA

    GeoNomad, September 8th, 2009
  44. Since this thread is still current, I think it’s worth mentioning that Dashcode *3.0* (it comes with Snow Leopard when you install XCode) has an option to “make your webapp available offline”

    It basically does all the caching work for you. I have yet to see whether it works for me, but I’ll find out soon.

    Harry Shamansky, September 8th, 2009
  45. Just so you’re aware you don’t need to add the website to your home screen for the cache to work.

    To clear your cache close the window in safari then quit the app go to Settings > Safari > Clear Cache, that should kill off the cache. Crashing seems a bit extreme it should throw an exception if the cache is invalid or non-existent. Perhaps that is a bug in 2.2?

    The Css Ninja, September 8th, 2009
  46. That’s great news, I imagine it would purely create a manifest file which references all your assets.

    Would be interesting to know if it attaches any listeners for you to do things like progress etc.

    The Css Ninja, September 8th, 2009
  47. Well, it’s still very basic. Dashcode won’t even show you or let you edit the manifest file until after you’ve saved to disk or exported. Less room for error this way, I suppose.

    Harry Shamansky, September 8th, 2009
  48. Clearing the cache did the trick. In fact I thought of it during the night and did it this morning before I came back here. Don’t know why I didn’t try that before.

    I think it did throw an exception. For a brief second there was an Error Message bar, but Safari crashed before I could read it. Been too lazy to look in the crash log to see if there was anything relevant. Maybe I will later.

    Yes, I had noticed that the cached version is used even if you type the URL offline, so there is benefit and danger to using the manifest without paying attention.

    Thanks.

    GeoNomad, September 8th, 2009
  49. If the only way to really remove an offline web application is to clear the cache, that means that all offline web apps will also be removed.

    Is there really no way to remove a single app?

    This seems like a serious problem. I already have several offline webapps on my iPod and expect many more.

    GeoNomad, September 9th, 2009
  50. It’s still not right that the browser would crash just because there is an error.

    Unfortunately clearing the cache is an all or nothing process, much like resetting the location services does it for every single app rather than individually. Seems they should really make it work like the notifications does.
    Even with finer control over cache clearing it would still be at the app level and not the individual cached site level.

    If the cache returns a 404 or 410 the obsolete event is fired and the browser will naturally delete the cache, that could be an alternative to going through the menu?

    The Css Ninja, September 9th, 2009
  51. After a few hours of bug fixing I got mine running except for one thing. I like to cache some .mov files. I kept it all under 5 MB, but in Mobile Safari it gives me a “broken” play button. It works fine in firefox for example. I can’t find it anywhere on the web, but I think the native iPhone players do not use the files stored by Safari and look for the online files, right?

    Matthijs, September 9th, 2009
  52. I’m not entirely sure what you mean? Is the cache not working on .mov files?

    The Css Ninja, September 10th, 2009
  53. Just an update to everyone, I got official word from an Apple employee that the applicationCache is not supported in the UIWebView. But they did recommend another forum post that shows you how to have a website run locally using a different technique, in short put your files in the Resources folder http://retromaccast.ning.com/profiles/blogs/iphone-programming-for-apple

    The Css Ninja, September 10th, 2009
  54. What I mean is the .mov file is cached by the browser (at least that is the case on a regular browser as I can play the movie while offline) but when I want to play the movie by clicking a link in the cached html files on the iPhone, the native application for video playback will open and I think it will look for the file on the original URL and not the file Safari cached.

    About the “Resources” solution above. It is quite nice but the great thing about UIWebView is that you do not need to distribute an app.

    Matthijs, September 10th, 2009
  55. Have you tried using a smaller filesize video, or just the video by itself? Perhaps there is a size limit, this is only speculation.

    The Css Ninja, September 10th, 2009
  56. The video is just 1.4 MB, so it should not be a problem. In Firefox it is easy to see how much data is in the cache for each domain (firefox>preferences>advanced>network) and there the movie is included. I think only Safari can use the cache and not other programs (like the video player)

    Matthijs, September 10th, 2009
  57. I wrote last week that your demo, here, crashed my firefox 3.5.2.

    I upgraded to 3.5.3 today and it still does… Well.

    It might be a bug specific to the linux version.

    I’d didn’t dive into this technique yet, so before I do, I’d like to know if the caching speeds up an online web-application with the iphone (dynamic website with a lot of content fetched online)? What’s the best way to do? cache as many files as possible? the javascripts?

    yvan, September 11th, 2009
  58. That’s a very good point. I’m sure it could be due to the fact that video and audio tags in iPhone Safari don’t act the same way as a desktop browser and would probably bypass the cache. Will investigate further, but good find.

    The Css Ninja, September 11th, 2009
  59. Must be a bug with the linux version It seems fine on 3.5.3 in Vista & 7.

    The whole point of the applicationCache is purely for offline access rather than speeding up the web app. Though it would make the initial visit to the site much snappier as you can cache all the pages before the user will get there. Caching all the static content would definitely speed up the responsiveness, but if you have a lot of assets you wish to cache it can make the first time visit very slow.

    The Css Ninja, September 11th, 2009
  60. @Matthijs
    My recent experience also suggests that embedded video is not possible offline… and that was the whole point of trying to make this small offline app.

    I still hold a small flicker of hope… the iphone… no video… doesn’t sound right to me.

    I did get the rest of it working offline after some problems… being that the manifest is aggressively cached and after fixing a small problem in it I had to rename it to make offline work at all. That was my biggest caveat.

    Martin Westin, October 19th, 2009
  61. First thing I tried when I read this was downloading the demo.
    It didn’t work on the iPhone, but the original demo did!!!
    Is it because of my server?
    The demo is on: http://projecten.maxmakes.nl/cache11/index.html

    Max

    MaxMakes, October 26th, 2009
  62. Looking at the console.logs it’s returning a status of uncached, if it was working it would return status checking. It’s also firing the error method so you may want to print whats happening.

    function errorCache(error)
    {
    	console.log(error);
    	console.log("You're either offline or something has 
    		gone horribly wrong.");
    }

    Just add error to the error method and log it to the console, do this in Firefox with firebug so you can get more in-depth results.

    I would start stripping back items in the manifest and see if that works.

    The Css Ninja, October 26th, 2009
  63. I tried this but he now said it is an object event.
    How can I get the error.
    You can see the problem in the example of my previous message.
    Thanks for helping me

    Max

    MaxMakes, October 26th, 2009
  64. http://projecten.maxmakes.nl/cache11/thecssninja.manifest

    is returning content-type: text/plain so it won’t work.

    You can check the headers using this handy tool: http://web-sniffer.net/

    FYI, another working example is at http://benlo.com/jaipho – an offline slide show builder.

    GeoNomad, October 26th, 2009
  65. @GeoNomad – Thanks for the handy tool. Will have to do an update to the article as quite a few people get stuck on setting the right mime type.

    The Css Ninja, October 27th, 2009
  66. The mime type can be tricky, especially if you don’t have access to the server configuration. But a nice trick is to use a php script to generate the whole file, including the header. Safari is happy with a manifest file such as manifest.php and as the php can generate the content on the fly, life is easy.

    Also, the php script can generate a random version number while debugging, so you can just forget about the whole manifest thing. Just remember to load twice every time. If you want a copy of one of my scripts, just email me.

    For small webapps, this method means that content is always downloaded when online, and always works offline with the last load. No fuss, no muss.

    GeoNomad, October 27th, 2009
  67. My company has been working on an issue with UIWebViews and caching and the solution was to build our own caching that reads the manifest.

    On a separate issue – I am writing a web app and trying to cache an mp4 file and a pdf. The cache is under 5 megs. It seems the pdfs and the mp4s just will not cache. With pdf’s, it’ll try to go to the URL regardless of cache, and with the mp4, it tells me it can’t play the file. Anyone have a solution or see anything like this?

    Mike D, December 5th, 2009
  68. Yeah the official word from Apple is that you cannot use applicationCache in UIWebViews.

    The reason video/audio/pdf won’t cache is because they are loaded in external applications e.g. HTML5 videos get loaded in the media player and will always pull the source from the server. Same goes for audio and pdf.

    The Css Ninja, December 5th, 2009
  69. Actually i was able to get a pdf to cache by loading it in a base64 encoded string (data:), but the results were REALLY slow. still, for those who really need it, may be a worthwhile solution – didn’t work for video though.

    Mike D, December 5th, 2009
  70. You might try serializing with toDataURL and saving to LocalStorage.

    GeoNomad, December 5th, 2009
  71. Hey does anyone know if its necessary to create a manifest file if you are using Dashcode 3.0 to create a web app for the iPod????

    ryan, December 9th, 2009
  72. Depends if you are going to want it to work offline, without a manifest file offline will not work. Dashcode 3.0 allows you to tick a box to make a webapp function offline, all that does it creates a manifest file for you listing all your assets. I’m not sure how dashcode allows you to handle errors/events for the applicationCache if at all.

    The Css Ninja, December 9th, 2009
  73. I have downloaded the sample zip file and after I add an htaccess file it works fine.. However, I can not add images to the small website? I did have everything working for quite sometime and had many images working, yet i keep getting a safari error when i turn off wi-fi on my ipod touch. Please help!

    my .htaccess file just contains the text below:

    AddType text/cache-manifest .manifest

    I am super frustrated as I had everything working, yet now i can not get it to work anymore…..

    Stephen, December 14th, 2009
  74. Hard to tell without some sort of example or link?

    The Css Ninja, December 14th, 2009
  75. Here is the project I am working on right now.. But I have changed the manifest file, but even with the manifest file containing all the images it still breaks.. link is here.

    http://www.stephencarr.net/ipod/nursing/nursing.html

    Stephen, December 15th, 2009
  76. You’re image doesn’t exist, http://www.stephencarr.net/ipod/nursing/images/bg_full_screen.png, I get a 404. If you reference files that the cache can’t resolve the offline caching will fail.

    The Css Ninja, December 15th, 2009
  77. It works NOW!!!! Thank you! You were correct, I was referencing a wrong background image. I corrected that and it still didn’t work, so I simply erased everything off the server just to be sure there weren’t any bad files floating around, and re-uploaded and now we are good to go! That was a pain!! But totally worth it, thanks again man!

    Stephen, December 15th, 2009
  78. I’ve gotten the app manifest and offline caching working, many thanks for the article! I’m able to bookmark my site/app to the home screen and load it from there. But, once opened from the home screen, certain links will jump out and open in mobile safari – despite the fact that i preventDefault() on all link clicks!

    I have an onclick event handler bound at the body level. Using event delegation, it catches any click on any link, looks at its href, and dynamically calls a templating function to update the page. I call preventDefault() on the event object – for *some* of my links this works, and the page is updated with my template. For the links that result in a hit against the local database before outputting the results of the template, the links are opened in mobile safari.

    In desktop safari, all the links work even when i’m offline – something is happening that’s mobile safari specific.

    Any thoughts on why some links would open offline, but others not? None of the link URLs in question are listed in the manifest file, but they don’t need to be since the link action is prevented

    Jo, December 20th, 2009
  79. It’s hard to say without seeing exactly what you are doing.

    You should check out iUI or jQTouch and see how they handle page loads. I’d imagine they would be hijacking the links like you are but there might be a quirk to get around the issues you’re having.

    The Css Ninja, December 20th, 2009
  80. what do these links point to? are they all just regular http? some other protocols are not supported in the same manner in full screen mode as they are in mobile safari. Another reason might be your target (if any). Also, AJAX requests are not supported for caching

    Mike D, December 20th, 2009
  81. can you please help me … am new to web apps but produced one using Dashcode 2.04 as only have leopard not snow leopard and need to now make the app available for offline use. Can someone tell me how to do this ? I can see from another blogg that Dashcode 3 does this for you . But i do not want to do the whole app again . Any offers on this? would be very grateful if anyone can help as there is not a lot of info on dashcode around. I know i need to create manifest but need simple guide after producing the files and deploying. thank you

    nerissa, January 2nd, 2010
  82. I don’t use dashcode so I can’t help you there. I imagine updating your dashcode version won’t require you to do the web app again.

    The Css Ninja, January 2nd, 2010
  83. hi there sorry just if you could let me know how to make a manifest from the files I have deployed from Dashcode anyway please. Is it the same process you have above. thanks

    nerissa, January 3rd, 2010
  84. Thanks, worked flawlessly.

    Dae, January 9th, 2010
  85. hi all,

    just a question:

    what’s the easyest way to let the user “switch” from “local” and “not local” (without manifest)?

    (allowing to download the app “data” only on request?)

    using PHP would be useful to include() or not the .manifest, but i wonder how to “persist” the state because PHP is processed on the server-side before client execution…

    thank you in advance for any advice…

    Joachim, January 15th, 2010
  86. cookies?

    Joachim, January 15th, 2010
  87. @Joachim – cookies could be a good option you can then check with PHP if it’s local or not.

    The Css Ninja, January 15th, 2010
  88. thanks! this was my initial idea… I was wondering if there are other (better?) options…

    I’ll try it this way :)

    have a nice day
    Joachim

    Joachim, January 15th, 2010
  89. Cookies and a php controlled manifest works well.

    It is possible to implement a user button in the app to clear the cache which sets a cookie which causes php to return an empty manifest. Javascript can be used to force immediate reloads to complete the implementation.

    It can get hairy debugging the sequence but once you have it working it seems to be reliable.

    GeoNomad, January 16th, 2010
  90. I’ve got a question for Mike D.
    I’ve been busy creating a very cool webapp and now I want to get it in the apple store.
    Can you explain what you mean with: “build our own caching that reads the manifest”.
    Thanks

    Max

    maxmakes, January 17th, 2010
  91. Hi Ninja and GeoNomad,

    I’m developing an iPhone web app that utilizes cached data. The dialog here has been invaluable to debug various problems I’ve encountered.

    I, too, have used a dynamically generated manifest file, but even though the content type is clearly “test/cache-manifest” (thanks web-sniffer.net), the status of the applicationCache is Uncached. Static manifest files work just fine.

    Geonomad, did you set any other headers other than the Content-Type?

    Thanks

    CrazyIvan

    CrazyIvan, January 19th, 2010
  92. Hi CrazyIvan, if you’re are still getting uncached status even though the mime type is correct. This usually means your are referencing an asset that doesn’t exist or you have the wrong path to one or more of your assets.

    The Css Ninja, January 19th, 2010
  93. No other headers were needed.

    As Css Ninja says… look for non-existent items.

    When debugging, if something had gone wrong earlier, sometimes a respring of the iPhone was necessary to get cacheing to work again.

    GeoNomad, January 19th, 2010
  94. No problems with the files listed in the manifest.

    There was a newline before the CACHE-MANIFEST header. I was using Web-sniffer.net, but I didn’t have “Raw HTML View” selected. Without that option checked, the newline is not displayed.

    I knew that CACHE-MANIFEST had to be the first line, but the way I had written the ASP created a “hidden” newline. See below:

    <%
      Response.ContentType = "text/cache-manifest"
    %>[CRLF]
    CACHE-MANIFEST[CRLF]
    [CRLF]
    #yada[CRLF]
    #yada[CRLF]
    #yada[CRLF]
    

    The altered layout below corrected the issue:

    <%
      Response.ContentType = "text/cache-manifest"
    %>CACHE-MANIFEST[CRLF]
    [CRLF]
    #yada[CRLF]
    #yada[CRLF]
    #yada[CRLF]
    

    Thanks,

    CrazyIvan

    CrazyIvan, January 20th, 2010
  95. Hi Ninja,
    Your demos and this discussion have been invaluable.

    I am using an iTouch 3.1. In my tests I can open both a .pdf and a MS Word .doc file in mobile Safari while on line. If I list only the .pdf in the cache manifest file, it gets cached with no errors. This is good.

    If I list the .doc file in the manifest, I get an error event when loading the cache and the .doc file is not cached, even though it views OK when on-line. The manifest file is super simple and there are no typos. Here is the file:

    CACHE MANIFEST
    index.html
    cache_debug.js
    test.html
    test.pdf
    test.doc

    Leave out ‘test.doc’ from the manifest and everything is cached without errors. Put it in and we get a cache error even though the server downloaded with 200 OK.

    Here is the test with the .doc in place. Open the .doc while on line, it works, but it is not cached.
    http://sky-report.com/test/cache-test/index.html

    Have you heard any more on this? Does safari only cache a limited set of file types? It is strange that it fails to load the .doc into the cache.

    Also, do you know how to see the specifics of the error event? I am trying to see why safari is throwing an error on the .doc.

    THANKS!

    Pb, January 29th, 2010
  96. That’s an interesting find, there could be an undocumented list of files that will not be cached. So far we know audio, video and now doc files don’t cache. The audio and video is due to them opening in an external player but doc I’m not sure why it wouldn’t cache. I tested the page in firefox and everything caches fine including the .doc file, this leads me to believe mobile safari may have a balcklist of files it won’t cache?

    One theory could be that it won’t cache propriety formats, which would make all office documents fail when trying to cache. You could try saving the .doc as .rtf instead and see if that works?

    The Css Ninja, January 30th, 2010
  97. Hi Ninja,

    I have updated my test at
    http://sky-report.com/test/cache-test/index.html
    with an .rtf file instead of the doc. It behaves the same. I have some cache event logging so you can watch. It gets the file with 200 OK, but the DOMApplicationCache throws an error as soon as it hits a .doc, .rtf, .xls, and .ppt. Which are all files that can be opened by safari while on-line.

    So here is another theory. Mobile Safari may have a plug-in structure similar to other browsers, so it will render files of different types using its plug-in. We see that with PDF, audio and video. I believe in iPhone 2.x, the PDF would not cache for offline viewing.

    So this problem may not be a Safari problem in-as-much as a plug-in not being cache-aware.

    I think safari can also open some apple formats, I will try those also. More theories, testing and comments are welcome.

    BTW – how do I submit these questions to Apple? I have the free Dev registration but not the $99 yet. THANKS NINJA – YOU ROCK!

    Pb, January 30th, 2010
  98. That sounds quite plausible that the plugins may not be cache aware for certain file types.

    You can try the devforums, not sure if you need a paid account to get access. You could also file a bug.

    The Css Ninja, January 30th, 2010
  99. Hey Ninja,

    Since I couldn’t get this to work, I downloaded the source and uploaded it up another server. When o Reyes to so this again, it didn’t work like on your site.here is my testing link:

    manifesttest.atspace.com

    If you can tell me why this is so.

    Thanks,
    Gerome

    Gerome, February 3rd, 2010
  100. @Gerome – See GeoNomads comment for a useful tool to let you know if you are sending the manfiest through as the right mime type. Running your one returns text/plain you need to setup on your server to feed all .manifest files as text/cache-manifest.

    The Css Ninja, February 3rd, 2010
  101. Hi Ninja, i tried manifest to cache background image, the page is still reloaded and the page is refreshed. do you know how to fix this? thanks! (i wanted to cache the background image to avoid reloading the image when the site is online)

    atom, February 14th, 2010
  102. by the way, i’ve tried ‘offline’ of the page, it works fine. Just when it is online, i see the background image is always being refreshed.

    Thanks,
    Ray.

    atom, February 14th, 2010
  103. Someone heard about improvements to make video caching possible with HTML5?

    NicoVB, February 15th, 2010
  104. @Atom – Is it actually requesting and downloading the image again? It could be reloading it from the cache and that could appear to look like it’s downloading from the server again.

    The Css Ninja, February 15th, 2010
  105. WWWHHHYYYYY cant i get this to work lol,
    ok so i suck at this but heres what i wanna do ,
    i wanna use iWebKit on an app, no internet at all, just iWebKit and the app…i created a manifest file but in xcode, do i point to the manifest file or just to the index.html but make sure i have the manifest file in there?

    z3r01, March 2nd, 2010
  106. @z3r01 – Xcode should take care of the referencing and creating of the manifest file so all you need to so is load the index.html page. If you look at the source there should be an attribute on the html tag i.e. <html manifest=”…” >

    The Css Ninja, March 2nd, 2010
  107. Great stuff! The demo is working and I created my own example from your info and that’s also working.

    But, none of them work for me if I close the page in Safari and re-open, then I get a no connection alert from the browser and a blank page. Is this supposed to work like that? I don’t see the point if the user is not allowed to close the page in Safari..

    Btw, using a 3GS with everything up-to-date.

    Hansn, March 3rd, 2010
  108. @Hansn – Hmm, I just tried it myself using my demo (I’m on an updated 3GS too), put it into airplane mode went back in to safari and reloaded the page and went to the second page without a problem. I also closed the window, opened a new one and typed in the address again and it loaded without issue all while still in airplane mode.

    I did however get the connection error on the second page when clicking the “back to home” link, but I think that was because it was trying to load /index.html instead of just / and the fact that it isn’t added in the manifest. Looks like the cache gets confused when you try to link to the same file by using different names.

    The Css Ninja, March 4th, 2010
  109. Cheers for the testing! What I’m trying to do is to cache a web app that’s added to the home screen. This shouldn’t be any different from opening a page in Safari (right?). But what do you get if you:

    Open your demo, add it to the home screen, open safari, close the page, close safari and click the web app icon?

    That’s my problem here, I always get a connection error, but maybe it has something to do with trying to open / vs /index.html as you said.

    Hansn, March 4th, 2010
  110. Did a test and renamed your index.html to index1.html, created a new index.html with an onload redirect to index1.html just to have the home screen icon pointing to a file and not /. But I still get the same connection error. It feels like Safari is dumping the cache when the app is closed without having the page in it.. weird!

    Hansn, March 4th, 2010
  111. @Hansn – So I followed your steps of loading it in safari, putting it on the home screen etc. All works fine for me, loads the pages without issue and all the cached assets appear.

    Have you changed the demo at all, or is it the exact same as my hosted demo?

    The Css Ninja, March 5th, 2010
  112. It pretty much the same but I get the same thing when I run your demo, long step by step with your demo:

    1. Empty Safari cache, just to get a clean start…
    2. Open Safari
    3. Browse to Ninja demo, not loading the second page
    4. Add to home screen
    5. Open Safari
    6. Close demo tab
    7. Close Safari
    8. Enable Airplane Mode
    9. Run Ninja Demo with homescreen icon
    10. Safari is opening a new tab, saying “Turn off Airplane Mode…”
    11. Then saying “Cannot Open Page…”
    12. Blank boring page showing :(

    Something is very fishy here if you get the demo when doing this..

    Hansn, March 5th, 2010
  113. I can’t re-create your problem. I followed your steps exactly and it all worked fine for me? Have you got anyone else with an iPhone to try this demo out and follow your steps?

    The Css Ninja, March 8th, 2010
  114. Thanks, I’ll check with some people and post the result.

    Hansn, March 8th, 2010
  115. we just had a similar problem with one of our apps. turns out a complete shutdown of the iphone and a restart did the trick. the cache is caching again properly.

    pete, March 8th, 2010
  116. Do you know of any way to tell Safari to only download changed or newer files? It seems that if the manifest has changed at all, every file is re-downloaded.

    dosboy, March 15th, 2010
  117. No unfortunately it’s all or nothing. There is no real way for the application Cache to tell what files have been updated or added, it works off the manifest time stamp to detect if any changes have occurred.

    The Css Ninja, March 15th, 2010
  118. hmmm…. seems like if you add your webapp to homescreen, user opens it, navigate to an internal page, and then receives a call (interruption). On awake it will execute the script tags. Is there anyway of stopping it?

    simon, March 24th, 2010
  119. Do you mean once you end the call and it goes back to safari, does it try reloading the page? If you’ve added it to your home screen it will have already cached the assets. Could you explain in a bit more detail what exactly is happening?

    The Css Ninja, March 24th, 2010
  120. Just to help those that, as me, don’t know how to alter the conf file on a public server, the Apache has an option to do so. Just create a file .htaccess with the following content: “AddType text/cache-manifest .manifest” and place it on the same directory as the index file. This should solve any problem you may face!

    Vasco, March 24th, 2010
  121. Just a quick cache manifest question. I am using php to create a dynamic page using a framework. So when I create a page it is not with an extention. So my application would be located at something like http://somedomain.com/my/mobile/app. Can I include this in the manifest and have it cache my html output of that url? I started as a static html file but have to dynamically generate the html.

    Justin, April 10th, 2010
  122. Justin, if that generated page references the manifest file it’s considered whats called a master file which will automatically be cached and available for offline use. You shouldn’t have to do anything other than make sure the html tag has the manifest attribute.

    The Css Ninja, April 10th, 2010
  123. hmm. for some reason it does not cache. when it was just an html file it was fine, but as soon as it is dynamically generated, it does not cache.

    Justin, April 10th, 2010
  124. Have you tried just specifing the folder in the manifest? e.g. my/mobile/app/

    The Css Ninja, April 10th, 2010
  125. Thanks for the help, I had some path issues. Is there a way to force the cache to refresh even if the manifest has not changed? So if they are online it refreshes everything anyway?

    Justin, April 13th, 2010
  126. Justin, I haven’t tested it but you could try doing a swapCache() call on the noupdate event e.g.

    var webappCache = window.applicationCache;
     
    function updateCache() {
    	webappCache.swapCache();
    }
     
    webappCache.addEventListener("noupdate", updateCache, false);

    Not sure if that will work or not. Otherwise you’ll have to make an update to the manifest like a comment version number in my example.

    The Css Ninja, April 13th, 2010
  127. I’ve read the article that explains how to implement HTML 5 offline resource caching in web apps. I’ve tried testing this locally: added the MIME type to the list, created a Cache Manifest (as described), changed my doctype to the HTML 5 doctype, specified the manifest attribute and the correct path on the HTML element — but still I don’t see the manifest file being consumed by the Safari Browser at all.

    But, my offline-caching Enabled Page refreshes successfully at IE 6.0 & Google Chrome browsers even when the LAN is disconnected.

    I just don’t know how to further troubleshoot the issue and would welcome any suggestions.

    Tapobrata, April 13th, 2010
  128. It’s hard to say what your issue is without seeing it. Can you provide a link?

    The Css Ninja, April 14th, 2010
  129. I was trying to find a way to give the user feedback on how far the downloading of the files that are mentioned in the manifest is progressing. You mentioned in your article that the progress event will fire for each file that is referenced in the manifest until the cache has finished downloading.

    So I thought here is my solution. I just put a counter in the handler function of the progress event and I know exactly where I am with my download.

    Unfortunately this did not work out well. I have 38 files in my manifest and my counter goes up to 75.

    Do you any idea?

    Timo, May 24th, 2010
  130. Could one build the cache into the actual web page you are caching? Similar to how one can include css and javascript in the page without having to reference the file.

    The reason I ask is because I am trying to build an ‘e-publication’ that I would like to be able to allow to be read offline. Rather than have to create a separate file, it would be really useful to create a manifest for the page that will eventually be downloaded and read offline.

    Much easier than creating five separate files (one for css, one for js, one for images, one for the actual page and one for the manifest)

    This is currently being created as a WordPress theme (you can follow the link above, which works on iphones/touches and kinda-sorta on the ipad)

    If you know of a way that I could actually build a webarchive ala safari’s, or collect all relevant files in one location, that would be awesome too.

    Gerry Straathof, June 10th, 2010
  131. Could one build the cache into the actual web page you are caching? Similar to how one can include css and javascript in the page without having to reference the file.

    The reason I ask is because I am trying to build an ‘e-publication’ that I would like to be able to allow to be read offline. Rather than have to create a separate file, it would be really useful to create a manifest for the page that will eventually be downloaded and read offline.

    Much easier than creating five separate files (one for css, one for js, one for images, one for the actual page and one for the manifest)

    This is currently being created as a WordPress theme (you can follow the link above, which works on iphones/touches and kinda-sorta on the ipad)

    If you know of a way that I could actually build a webarchive ala safari’s, or collect all relevant files in one location, that would be awesome too.

    (repeated because I screwed up my email)

    Gerry Straathof, June 10th, 2010
  132. Hi,

    Just a quick question, can I access cache.db file located at ~/Library/Caches/com.apple.Safari/Cache.db through javascript.

    Ketaki, June 25th, 2010
  133. Hi,

    so i am new to creating web apps for iphone.
    my cacheing seems to work correct but this may be off the subject.
    so i am calling

    to get rid of the nav bar on the top and the bottom (to make it look like a real app) when online it is working properly but offline it is not. i always get a “cannot open page for BLAH” retry or cancel this is when i add it to my homescreen button. any ideas or have you guys seen this problem. i am also using jqtouch for my simple animations.

    thanx again

    Robert, June 28th, 2010
  134. Let’s say i have index.html & HELLO.html in the manifest.

    index.html contains a link to HELLO.html (which in fact is just a div with some text).

    HELLO.html will work when i’m online but not when i’m offline, even though HELLO.html is in the manifest.

    Any ideas? :)

    Dennis K., June 29th, 2010
  135. > You can check the headers using this handy tool: http://web-sniffer.net

    There several other free tools available as well. Live HTTP Headers firefox addon or FREE Web Tools from HTTP Debugger Team:
    http://www.httpdebugger.com/tools/

    web developer, July 3rd, 2010
  136. @Ketaki – In short no. Is that what dashcode names it’s manifest file? You can’t access local files in javascript on mobile safari.

    The Css Ninja, July 5th, 2010
  137. @Robert – can’t say without seeing an example.

    The Css Ninja, July 5th, 2010
  138. @Dennis K – That’s exactly what my demo has, an index file and a link to another page. You don’t need to visit the second page in order for the cache to save it locally, compare my demo to your files.

    The Css Ninja, July 5th, 2010
  139. @Timo – The progress event should only fire for each file in the manifest, can you provide a link to the demo?

    The Css Ninja, July 5th, 2010
  140. I love the way your demo includes a facility to check if the user is currently on/off line. I’m wondering; have you encountered a way of seeing if the user is online via wifi or cellular? I’d presume it’s impossible with a webapp although possible for native apps?

    kheda, July 23rd, 2010
  141. @kheda – The navigator.onLine property can’t tell you what connection you have only if you have a connection. Sskype can tell when you’re on wifi or 3g so it would be possible in a native app but not through the browser.

    The Css Ninja, July 23rd, 2010
  142. I am trying to work with SVG fonts in a project (trying not to have any bitmap scaling for logos and such)

    SVG fonts in mobile safari require a font id in the url, which is indicated as a #123456789 after the svg (font-name.svg#123456789)

    because the cache manifest registers the # as a comment, is there any way of ‘tricking’ it into not seeing the # in the font name?

    Thanks. Thanks a whole bunch.

    Gerry Straathof, August 11th, 2010
  143. @Gerry – In order to cache the svg file I don’t think you would need to have the fragment identifier in the manifest file, you only need it when you reference it in the css file. Just add it as font-name.svg and it should be cached.

    The Css Ninja, August 11th, 2010
  144. SVG files aren’t working. Period.

    I tried the following: I forced the site to use only the SVG fonts. I ensured the manifest was accessing only the .svg (no Font id)

    In chrome, while running an audit I get the errors:
    Resource interpreted as font but transferred with MIME type image/svg+xml.

    In the .htaccess for the font folder I have added:
    AddType image/svg+xml svg

    Note: I have singe removed all references to the web fonts and cannot get it to work. In chrome, there are no errors in the audit except spcifying image dimensions, serving static content from cookieless domain and minimize cookie size. Sit is: http://straathof.acadnet.ca/beta2.4/ (webfonts turned back on right now)

    Gerry Straathof, August 11th, 2010
  145. I just tried adding an svg file to my example manifest and it’s caching fine.

    Go to my demo on your iPhone let the cache update and then go into offline mode and visit the svg file it will load fine in offline mode and is getting cached.

    The Css Ninja, August 11th, 2010
  146. Yup. the file caches fine, but can you use it?

    Here is a small sample. the larger text should appear in veggieburger bold. It will work well in safari when you open it, and if you open it from a saved homepage icon online it will work and display the font. When you open it offline, though it will not.

    the @fontface reference in the stylesheet looks for a url that ends in a name associated to the font within the svg file. It is after a #. The one for veggibold is: veggibol-webfont.svgz#webfontfLhiEZTN

    because this complete url is not part of the cache manifest it can’t find it. It won’t fail because it will still find the svgz file, but it will not render with the font. I need a way around tat before I can use webfonts in mobile safari, either by fooling the cache.manifest or inside the @fontface call…

    Example: http://www.straathof.acadnet.ca/pinch/

    Gerry Straathof, August 14th, 2010
  147. @Gerry – I double checked the spec to see if they say anything about fragment indetifiers in URLs and came across this interesting side note.

    Comments must be on a line on their own. If they were to be included on a line with a URL, the “#” would be mistaken for part of a fragment identifier.

    This may be a bug then if according to the spec a # in a url should be taken as a fragment indentifier and therefore work…

    The Css Ninja, August 14th, 2010
  148. i am using html5..i just made a simple html5 page. here manifest is given to thehtml5. that page run correctly on dekstop…it works in work offline mode too…but when i run that same page in samsung wave mobile. then it dont cache the html page.
    please tell wat can i do for this
    content in manifest file as givenbelow:
    CACHE MANIFEST
    index.html

    and in html page manifestadded as:

    after this thrs only static data give

    now please tell any other modification need to be done for mobile

    Puneet, August 20th, 2010
  149. @Puneet – The page that calls the manifest file is automatically included in the cache you don’t need to specify it. Just having the cache and putting the attribute on the html tag will suffice. I’ve never used a Samsung Wave so wouldn’t know if it has any quirks. Try this checklist web app on your wave it uses a manifest for offline access.

    The Css Ninja, August 20th, 2010
  150. Sir thanks for reply
    1. can you please tell, is this necessary to place manifest attribute
    on each html page or it just place on front page??

    2. in manifest file smarty templates need to be added or not??
    3. i cant access the sql database on mobile, do u know any working example of offline database on client-side??

    Puneet, August 20th, 2010
  151. as i am using smarty and php in my project, is there any need to add all templates that are in my project to specify in the manifest file??

    Puneet, August 20th, 2010
  152. hello sensei , ive got some troubles over here that i think im not supossed to have ,i’ve been trying to make something to go offline but i just cant i even try the easyest example ever , something like this

    index.html:

    Stuff

    some stuff to be offline here

    ————————————————————————————

    style.css:

    p
    {
    border:1px solid black;
    }

    —————————————————————————————

    stuff.manifest:

    CACHE MANIFEST

    index.html
    style.css

    —————————————————————————————-

    im running apache with the mime type already added

    its supossed that the browser automatically ‘saves’ the manifest file as it reads the manifest attribute on the HTML tag right?

    after it loads , i turn the server off and the page just wont load after reloading and i dont know what im doing wrong , please some help over herre newbie in troubles

    Gustavo, August 23rd, 2010
  153. @Puneet – You only need to place the manifest attribute on the initial page then inside the manifest you list all the assets you wish to cache.

    The Css Ninja, August 23rd, 2010
  154. @Gustavo – Grab my demo and try that on your server. If that’s working you’re doing something wrong with yours. If it’s not make sure the mimetype is set, double check it with the web sniffer tool mentioned in the article. Lastly make sure you’re testing it on a browser that actually supports the application cache.

    The Css Ninja, August 23rd, 2010
  155. hi well i tried with your demo on my server and it runs smoothly , im using chrome 5 ,so i guess the trouble its me xD , but how can somebody make any mistake with a example like the one i posted :S!!

    so i guees ill keep on trying to find out what am i doing wrong thx!!

    Gustavo, August 23rd, 2010
  156. ok now its working i dont know what was the problem i just moved the css file to a folder and change the url in the manifest file and voila , but now i have a question , i added some lines to index.html more specifically i added elements but they just dont render at first i tought it was because the server was down but it wasnt so i dont know whats happening! :S

    Gustavo, August 23rd, 2010
  157. @Gustavo – Most likely it was a bad reference to that css file, if there are any 404 on files you list in your manifest it will fail.

    i added some lines to index.html more specifically i added elements but they just dont render at first i tought it was because the server was down but it wasnt so i dont know whats happening! :S

    Make sure you clear your cache and you’re using the appcache event model to detect changes in the manifest so you can swap the old with the new, otherwise it will load the originally cached assets and you won’t see any changes.

    The Css Ninja, August 25th, 2010
  158. i am making web application that works offline. I used database system in my application. i successfully save data on client side during offline. now i don’t know how to synchronize client side data storage with the server?
    as gmail runs in the iphone. we can do all work during offline but when internet connection comes it synchronize with the server.
    i want same thing in my application i don’t know how to send request back to server after internet connection comes.
    please reply

    Puneet, September 3rd, 2010
  159. @Puneet – Onload of the web app you can check navigator.onLine status and if it’s true sync your local databse with your server.

    If they drop connection while using your web app and then regain it you have two events that get fired on the document called “online” and “offline”. Capture these events and delegate what to do when they lose or gain a connection.

    The Css Ninja, September 4th, 2010
  160. thankx sir
    i got it

    Puneet, September 7th, 2010
  161. Thanks for sharing such a nice sharing..

    sahibinden, September 11th, 2010
  162. hey i’m having problems with an app i’m making, and wondered if you might be able to help… i’m trying to make a browser based app that just displays my website. this works fine but when i click a linkto an external site, i have no way of going back as there is no back button. is there any way to make certain links open up the safari app, so my app just navigates pages that i have made? i’d appreciate any help you can give – this is really frustrating!

    nightleaf, September 23rd, 2010
  163. @nightleaf – If you save a website to your home screen and it has the meta tag to make it full screen any external links should automatically open the safari app. Are you loading any javascript that may be hijacking these link clicks?

    The Css Ninja, September 23rd, 2010
  164. hey, i’m not saving the website to the homescreen, instead i’m making a standalone app that is simply a browser window that links to my website. the idea being that i would submit it to the app store and upon download it would navigate around my website within the app, but upon clicking a link to an external site it would open safari.. i just wondered if there was anything i can do to make this happen?

    nightleaf, September 23rd, 2010
  165. @nightleaf – Ah right just did a quick search and found a solution to loading links in safari from a UIWebview. Looks like that’s what you need.

    The Css Ninja, September 24th, 2010
  166. ah that’s fantastic, thanks very much

    nightleaf, September 24th, 2010
  167. I’m just working on my first iPhone offline app and came across your site. I’ve just tried your demo in offline mode (airplane mode on), and the site tells me it’s online still and it complains about not having internet access.

    I’ve tried adding it to my home screen and this fares no better.

    Am I doing something wrong?

    Thanks

    John

    John Polling, October 1st, 2010
  168. Thank you CSS Ninja. I’ve learnt a lot from your tutorial, comments and participants.
    I’m newbie in the whole matter; webapps as well as javascript.

    I want to know if there is a way to force the iphone to add your webapp to the home screen automatically without tapping (+).

    regards,

    Ahmed, October 2nd, 2010
  169. @John P – It’s hard to say, what iOS version are you running? Have you tried other offline examples? I just tried it myself on iOS 4 and it’s working fine.

    The Css Ninja, October 4th, 2010
  170. @Ahmed – Unfortunately you cannot force it to save to the home screen, you have to go through the devices predefined steps to get it there.

    The Css Ninja, October 4th, 2010
  171. I am finding it impossible to get my app to work in offline mode. When I put my iPhone 4 running iOS 4.1 into airplane mode, I just keep getting an error that it “could not be opened because it is not connected to the Internet.”

    webApp

    I’ve read through all the comments here and many other sites and have been unable to find a solution. I did use the Web-Sniffer and my manifest seems to be the correct mime type.

    I’m at a loss and hope that someone here might have a solution.

    Steve V, November 4th, 2010
  172. @Steve V – Looking at this in Firefox the cache is zero so something isn’t caching. The application cache will not work if any of your references return a 404 or some other error code. Having a quick look at your manifest you point to two assets, rightOn.jpg and rightOff.jpg, that are getting a 404 which causes the cache to fail. If you remove them from the manifest it should work fine.

    The Css Ninja, November 4th, 2010
  173. Thanks! You’re awesome! That did the trick. Figures it would have to be something “simple” like that.

    Steve V, November 6th, 2010
  174. Hi CSS Ninja! I developed an iPhone web app that works alright when my iPhone 3G (iOS 4.1) is online, but when I’m going offline (Airplane mode) I get an error “Cannot Open App: App could not opened because it could not connect to the server.” My manifest (offline.manifest) file contains all of my files and I’ve set mime-types on my (local) server (Apache). I checked it using Web-Sniffer.net and the result is “Content-Type: text/cache-manifest”. I cleared the cache, rebooted my device and then I tried to open the web app at “http://MyIP/folder/index.html” (not just “http://MyIP/folder/”), but I got the same error. Also, I removed all of my “window.location” and “location.replace” JavaScript code, because I read that other users had problems with JavaScript redirections. I’m desperate… I just want to run offline a web app (HTML, CSS, JavaScript and images). Can someone please help me?

    Note: I don’t know if this is important, but my CSS code has WebKit animations.

    Dinos, November 7th, 2010
  175. @Dinos – If you’ve verified that everything being done correctly, then strip back your manifest references to eliminate the chance that your are referencing an assets that doesn’t exist. Quickest way to resolve issues is to strip it back to the raw functionality.

    The Css Ninja, November 7th, 2010
  176. I have found this php snippet which is supposed to go through all the files in the directory and include them in a manifest cache…

    isFile() &&
    $file != “./manifest.php” &&
    substr($file->getFileName(), 0, 1) !=”.”)
    {
    echo $file .”\n”;
    $hashes .= md5_file($file);
    }
    }
    echo “# Hash: ” . md5($hashes) . “\n”;
    ?>

    You call it with this code:

    I have been trying to use it, but since my webapp is too large (over 5M due to images) but it may work for others…

    Gerry Straathof, November 7th, 2010
  177. Well, that trick didn’t work… sorry. not sure if you can find it, but you can find some of the missing code if you meander through this site:

    http://straathof.acadnet.ca/beta6.6/iphone/

    http://straathof.acadnet.ca/beta6.6/iphone/manifest.php

    Gerry Straathof, November 7th, 2010
  178. Hello,

    I tried this demo on iPad but it is not working. It is working on my laptop.

    Do I have to set anything on my iPad that this (and other offline pages) will work?

    best S

    Sobis, November 7th, 2010
  179. Is there a way to make a progress bar (using css/javascript) that indicates the percent of the cache that has downloaded?

    Charles Thompson, November 8th, 2010
  180. I just tried it on my iPad and it worked fine.

    The Css Ninja, November 8th, 2010
  181. @Charles T – The applicationCache does have a progress event that will fire for each file in your manifest as they are being downloaded. I did do a demo that uses the progress event.

    The Css Ninja, November 8th, 2010
  182. Hello, I was trying to get my app working on my ipad and it does seem as if there is a limit on the file size. Currently my app is in total 16mb and I couldn’t figure out what was keeping it from working without using the java. Is there any way to get a website to work locally offline on the ipad other than a web app? Or is there a way that I could get this to work without reducing the file size? Thanks!

    Zack, November 13th, 2010
  183. @Zack – There is a 5mb limit for cached items using the applicationCache for the iPhone. I’m pretty sure it’s the same for the iPad.

    Is there any way to get a website to work locally offline on the ipad other than a web app?

    How else would you store a website offline? You don’t need to save a website to your home screen to store assets in the users cache it’ll work in the safari app just fine.

    The Css Ninja, November 16th, 2010
  184. hi
    First of all I can’t help but congrat you for the quality of your code writing. It’s become sufficiently rare to be worth noting :)
    2ndly I’ve been playing for a while with caching on the ipad, and I wanted to confirm that it works using UIWebViews with iOS 4.2
    And lastly I get an error at the end of your demo firing the errorCache function. And I’m not sure I understand your (function() {})(); syntax forvthe js code. Any hint ? Thx !

    Alan, November 16th, 2010
  185. Just for clarity sake…: I tested it on the iPad Safari with debug console on, which gave me the errorCache message.

    Alan, November 16th, 2010
  186. @Alan – Thankyou!

    Interesting, can anyone else confirm applicationCache works with iOS4.2 in a UIWebView? Thanks for the heads up Alan.

    (function(){})() that syntax creates a closure in javascript so as not to pollute the global scope. Basically you can have private variables.

    The Css Ninja, November 16th, 2010
  187. Ok for the private scope trick. Neat…
    But still have the errorCache problem: the logged messages I got when I launch your demo in iPad’s Safari are (in this order):
    - “Cache status: Uncached” (applicationCache.status == 0)
    - “Downloading cache…” (progressCache)
    - …
    - “Downloading cache…” (progressCache)
    - “You’re either offline or bla bla bla” (errorCache)

    and btw I get the same problem using UIWebView app (iOS 4.2).
    It seems that updateready never occurs and I get an error state instead.
    Other than that, as I said, the site pages remain visible in my UIWebView app even when in Airplane mode (but that didn’t work prior to iOS4.2, at least for the iPad).

    Alan, November 17th, 2010
  188. I had issues with debug in safari affecting my scripts. If you have it on expect problems and I would suggest not leaving it on all the time.

    Also be careful about clearing cache indescrimnately during testing. I have found it clears the cache for all bookmarked files. Since I have stopped clearing it my tests have been much more durable (although it is around 50m cached total right now)

    I would rather Apple saved the bookmarked site as a web archive, bypassing the hassle of caching for offline stuff.

    Gerry straathof, November 17th, 2010
  189. @Alan – I’ve tried this demo in my iPad and the error event isn’t firing. Will investigate further and see if I can reproduce it.

    The Css Ninja, November 17th, 2010
  190. When my webapp is “online”, why can I not pull new content through AJAX? It tries to locate everything in the CACHE, but it isn’t in the CACHE so it just gives me an error. Is there some secret to loading new data that I don’t know about, can it even be done (without having to completely download a new cache)?

    Charles Thompson, November 17th, 2010
  191. ok. thx for trying to reproduce. the only diff between your setup and mine could be the os version (4.2 8c5115c on my side).
    this is the link i used: http://www.thecssninja.com/demo/offline_webapp/loader/
    Thx again for sharing your great experience
    A.

    Alan, November 17th, 2010
  192. Hi,

    Firstly, I must say this link is immensely helpful!! Thanks a lot guys,keep up the good work!

    Secondly, I have a very basic question (Im new to this whole thing)

    @Ninja: you mentioned “If you save a website to your home screen and it has the meta tag to make it full screen any external links should automatically open the safari app.”

    Does this mean that if I have a added “m.abcd.edu/index.html” app to my home screen and i have a link to “http://pqrs.html” it will open up a new safari window, even if i have it cached in the manifest?

    So can i only add ” m.abcd.edu/anotherfile.html” (i.e: a file somewhat relative to my current path ) if I dont want to open a new safari window. I basucally want the capability to seamlessly redirect to a new page (even if its on a completely different path) as long as i have it cached.

    Thanks!

    PS

    PS, November 18th, 2010
  193. @Charles T – Are you caching the file you’re calling to in your XMLHttpRequest? In your cache manifest you can specify files that must always be called from the network.

    The Css Ninja, November 18th, 2010
  194. @PS – You can get around that issue by loading in your pages using XMLHttpRequest. I’m sure one of the many webkit frameworks already handle this.

    The Css Ninja, November 18th, 2010
  195. @Ninja :

    So this is what I want to do. Please! let me know if thats what you are referring to when you say XMLHttpRequest

    I want to store “site.edu/index.html” on my home screen.

    This index.html is going to contain 4 separate widget files : site.edu/eat.html ,
    hotel.html,
    fitness.html,
    movie.html

    My index.html’s manifest is going to contain all resources : the 4 htmls and their own resources like images,js etc..

    Now, what I want to do is! :

    1) Open the saved “index.html” from my homescreen (when im in airplane mode)

    (So this will basically open it using UIWebview and not my actual safari browser , i assume)

    –And NOT have it jump to my safari browser when I click on eat.html

    So basically I want a BIG app that has 4 SMALL app widgets in it..which shouldn’t have to load in new safari windows. (But since each is a completely different app, I do need 4 html files, I cant just use divs..)

    I hope I didn’t lose you’ll midway :P

    Thanks!!

    Do let me know if you’ll hav any suggestions

    PS, November 19th, 2010
  196. So, if I have to put every URL in the “white list”… then what happens when I load a page through XMLHttpRequest that has images on it? Do those images have to be on the “white list” as well?

    Charles Thompson, November 21st, 2010
  197. @Charles T – If you’re doing XHR calls to load extra data and you want to cache that page and it’s assets. You’re probably going beyond what the applicationCache was designed for.

    The Css Ninja, November 22nd, 2010
  198. @Ninja

    Basically, I have a webapp that has cached files so the layout loads faster. I want to be able to load external content inside a div using XHR, whether it be text, images, or movies. I am able to achieve loading text just fine, but I cannot load images through XHR because they are not listed in the cache manifest file.

    Charles Thompson, November 22nd, 2010
  199. @Charles T – Well loading images or movies through XHR will return the file in binary format which is pretty useless, you can’t just insert a blob of binary data into a document and expect it to render the image/movie.

    If you can get the relative URL to the asset create a new video/img element and set it’s source to the url and insert it into the document.

    The Css Ninja, November 22nd, 2010
  200. Hey Master Ninja,
    Any update on the errorCache problem by any chance ?
    I hate to get this error not knowing why, while I am just using the demo on your very web site. Are you using the 4.2 beta iOS on the iPad ?
    Please advise. Thanks !

    Alan, November 22nd, 2010
  201. @Ninja,

    My XHR loads data from a PHP document on my server. The data from the PHP document is render as HTML. I have tags in the data that comes from the XHR call that reference images on my server. My issue is that the I cant seem to load images that are not listed in the cache manifest, which is really silly.

    Charles Thompson, November 22nd, 2010
  202. @Alan – I’m not running iOS4.2 on the iPad so won’t be able to test.

    The Css Ninja, November 22nd, 2010
  203. @Charles T – Hmm that is weird, hard to say without seeing a demo. Do you have any test code that reproduces your problem that I could look at?

    The Css Ninja, November 22nd, 2010
  204. You can see what I am working on here, it’s very much in beta still…

    iota42.com/tixczar

    Charles Thompson, November 22nd, 2010
  205. Well after many trials which more or less “screwed up” Safari’s cache I used the good ol’ method that works 9 out of 10 times…:
    I power cycled my iPad and it now works like a charm….
    I get coherent cache messages and no more error message…
    mmmmhh… I’m not very enthusiastic as I still dont understand what happened. If something goes wrong again i’ll let you know.
    Thanks anyways…

    Alan, November 23rd, 2010
  206. @Charles T – Looks like iOS4.2 got released today will update my iPad when I have a chance and have a look.

    The Css Ninja, November 23rd, 2010
  207. I can confirm that on the iphone3G there is a 5MB cache limit. It wouldn’t cache the files until I got it all down to under 5MB (no other changes). You can simply remove a bunch of images from the manifest until caching works. On the iphone4 the limit is higher, but I have no idea what it is. I think 12MB worked fine.

    Jacob Mouka, November 27th, 2010
  208. Hi,
    my Webapp is still not working if I am offline.
    I’m using an iPod Touch 2g with iOS4.2, the cached Files are under 5mb, and the content type is text/cache-manifest!
    I’ve also included the manifest in the Tag!

    Any ideas why it doesn’t work? :)

    Flo, November 29th, 2010
  209. @Flo – Strip your manifest file back to bare essentials, there’s a 90% chance you’re referencing something in there that either doesn’t exist or has the wrong path.

    The Css Ninja, November 29th, 2010
  210. Thanks so much for the information on the post

    Madhusudhan, December 2nd, 2010
  211. Ninja, do I understand these comments correctly:
    Ajax requests can not be cached via the manifest file?
    I use jquerymobile, which uses Ajax to retrieve the different pages/screens in the app. In the standalone version with manifest file the cache does not return pages (html) through Ajax.

    Humble greetings,
    Hans

    Hans, December 2nd, 2010
  212. @Hans – No applicationCache cannot store ajax requests. I think jQuery Mobile can also use hidden containers with ids as “pages” rather than loading in html from another page.

    The Css Ninja, December 3rd, 2010
  213. This is so interesting. It makes me want to improve my study habits while taking these Java, JavaScript classes and getting ready to use HTML 5. I wish you lived next door and I could pay you to teach these classes! Awesome website for explaining How to create offline webapps on the iPhone!

    Carla, December 6th, 2010
  214. Great article!! Any thoughts on doing this with audio/streaming? I’m guessing that we are in the same world, just dealing with different mime-types.

    Jonathan Coe, January 27th, 2011
  215. @Jonathan C
    Same deal with video as it uses the external player to load and play audio, caching the audio wouldn’t work offline.

    The Css Ninja, January 27th, 2011
  216. Thanks for the great guide. If I could offer some advice to anyone who is having trouble getting this to work, it would be to make sure that you clear the cache on Safari iPhone after making changes. I was having trouble getting the app to load offline and troubleshooted for several hours to no avail. Finally, I decided to try loading the app offline on OSX with Safari and Firefox and it worked perfectly. That clued me in that it was the iPhone that was the problem. I ended up clearing the cache, cookies, and history on the iPhone and then restarted the phone. Afterward, the app worked perfectly. Thanks again for the guide, it helped a lot.

    Kush, January 29th, 2011
  217. That’s a good idea. I have taken to renaming the folder I am drawing my site from. For instance, it’s named “beta10″. I make some changes and change it to beta10.1 and so on. I don’t have the cache turned on until after I have all my alterations made to the web site, however. I learned from experience that not all changes recache properly.

    Gerry Straathof, January 30th, 2011
  218. I’ve used your code – awesome BTW! However I have a question that is slightly OT.

    I am trying to use localStorage for my offline app that I create using a different page in the online site. That is, I want to download data for the offline app using a different page while online. However, none of the data shows up in the the offline version, but I can see it if I go to the url of the page online.

    Any ideas/suggestions?

    Thx.

    snelldl, March 17th, 2011
  219. @snelldl

    So If I get this right you’re caching a page that stores data using localStorage. But when you’re offline you can’t access that localStorage data until you go to the page that executes the code to do so? Do you have a demo or something to show whats happening?

    The Css Ninja, March 21st, 2011
  220. I got it figured out. Not sure what I was doing wrong.

    However, I do have a different question.

    On the iPhone, when I add my app to the home screen, changes I make to localStorage when I use it don’t get picked up by the online version unless I go in and out of airplane mode at least once. I’ve seen other people with the same problem in various forums.

    Any ideas?

    BTW, I didn’t get your reply in my email.

    snelldl, March 23rd, 2011
  221. @snelldl -

    That’s a weird issue would be worth putting a test case together, could be a bug with iOS safari.

    The Css Ninja, April 6th, 2011
  222. Dear Ninja, thanks for the how to!

    However I’m having issues with my webapp caching. Thanks to your JS I could discover that the log says “Uncached”, and for some reason my webapp isn’t caching. I’ve double checked everything, even stripping the manifest to the bare essentials, and it still doesn’t seem to work. Any idea why? Thanks.

    Here’s the demo:
    http://iphone.spoon.cl/ilupa/

    leo prieto, April 7th, 2011
  223. @leo prieto

    Seems it’s an issue with your server. I slurped your site down and tried it locally and it caches for offline access just fine.

    The Css Ninja, April 7th, 2011
  224. Hi.
    At first i have to say you got a great blog and its very useful for everyone. congrats.

    I am facing a big problem using Sencha. there is a lot of JS and CSS. I have put all files in cache.manifest file but still not working. I dont what i can do anymore.

    Have you seen any problem using Sencha Touch?

    Thanks in advance.

    Filipe Menossi, April 14th, 2011
  225. @Filipe Menossi

    Take a look at their tutorial on the very subject.

    The Css Ninja, April 14th, 2011
  226. Hello,

    I’m having a very strange issue with the mime type setup. I downloaded your example and tested it on my webspace…it works offline…great!

    I’m also having a dedicated webserver. So I started to test the offline feature there. It was not working. I checked the mime.type and the manifest decleration was missing.

    So I added the the line text/cache-manifest manifest to my mime.types file and restarted apache. I double checked with web-sniffer and the output mimetype was correct. However the webapp was still not displaying offline. I ran another test and typed in the URL to the manifest file into my firefox:

    - On my webspace (offline is working) firefox wants me to download the manifest file; The same behavior occurrs when I type in the URL to your manifest file

    - On my webserver (offline not working) firefox just display plain text.

    On both systems web sniffer tells me that the content-type is text/cache-manifest

    What am I doing wrong? Do I have to setup anything else in my apach configuration?

    Thanks in advance

    mojorisin, April 15th, 2011
  227. Thanks the tutorial, very helpful – though I am having a problem with my app. I can get it to store offline but the Javascript fails to work?

    Any ideas?

    jonathan bennett, April 19th, 2011
  228. @mojorisin -

    Make sure know assets referenced in the manifest are 404′ing if that happens the whole manifest is thrown out.

    The Css Ninja, April 21st, 2011
  229. I ahd dveloped a html page with offline capability uisng the manifest ,it is working fine with firefox but not working on the safari .

    ragini, April 28th, 2011
  230. ur app is gr8 but i have a que about web offline. if my html generate dynamic means it not a .html or php file even its a servlet call, where as parameter pass the name of app and server read app name xml files and generated html content and return browers, how can we make these kind of sites webapps offline work? any idea?

    Neha, May 3rd, 2011
  231. Thank you for putting together a great introductory piece. This was very useful in getting me up and going and I referenced this in my blog post at http://mattsnerdwerd.blogspot.com/2011/05/ios-and-application-cache.html.

    Matt Ray, May 6th, 2011
  232. Hi, thanks for your tutorial, I have a question, how can create a dynamic manifest file, with ASP code, because in my online application the user can active and desactive mode offline and I can’t to erase cached files. I tried with two distinct files, but both files are cached and don’t delete files.

    Ej:

    First Manifest

    CACHE MANIFEST

    styles.css
    image1.jpg
    file.html

    Second Manifest

    CACHE MANIFEST

    Network
    *

    Also I tried with ASP code in manifest.asp

    styles.css
    image1.jpg
    file.html

    But this manifest don’t working.

    Thanks for your help

    Fernando, May 15th, 2011
  233. I’m having a hard time adding the Custom Mime type on my server. My website is hosted on Godaddy, IIS 7, Windows.

    There are no Mime Types on the Control Panel. I try creating the MIME with web.config file at the root folder, and all I got was to shut down all my website with an internal message error. I try creating a .htaccess file too but no success… any idea how could I try to fix this???

    Thomas, May 25th, 2011
  234. @Fernando

    It’s very hard to say without seeing a some sort of testcase to get an idea of what you’re trying to do.

    Ryan Seddon, May 27th, 2011
  235. @Thomas

    If you can access the IIS manager on your server it’s an easy change. IIS doesn’t use .htaccess so if you want to add a mimetype you can do it through the web.config if the IIS manager is not accessible.

    <mimeMap fileExtension=".manifest" mimeType="text/cache-manifest" />
    Ryan Seddon, May 27th, 2011
  236. A key note.

    I found that iOS (iPhone, notably) appears to not support Apache Last-Modified / If-Modified-Since headers.

    So, for an application cache to work it’s critical that you’re using access based cache expiration headers instead of modification based cache headers.

    Would be curious if you’ve seen the same behavior!

    Thanks,

    Sam

    codeviking, June 1st, 2011
  237. @codeviking

    I have not come across that behaviour! Do you have a testcase showing the issue? I would like to update the article and point to an example of it happening.

    Ryan Seddon, June 8th, 2011
  238. Nice article, Good job.

    Thanks to guide.

    Cheers!

    Incircle Media, June 15th, 2011
  239. Very good tutorial. Great job.

    Nithin, July 7th, 2011
  240. WebKit browsers won’t cache it.

    For some reason, Chrome and MobileSafari won’t cache my site.
    So I double checked that the mime-type on it was right and it was.
    Firefox does it fine. When I checked the Chrome Console it said:

    Application Cache Error event: Invalid manifest mime type (text/plain) http://i.finalscalc.co.cc/cache.manifest

    I’ve put it through the web sniffer and it identifies it as text/cache-manifest.

    The cache file is below.

    I can’t figure out what’s wrong. Thanks for your help, PitaJ

    ]CACHE MANIFEST
    ]
    ]CACHE:
    ]# Offline cache v1.0
    ]# html files
    ]index.html
    ]about/index.html
    ]
    ]# css files
    ]css/developer-style.css
    ]
    ]# js files
    ]javascript/functions.js
    ]finalsCalc.js
    ]
    ]# images
    ]images/arrow.png
    ]images/tributton.png

    PitaJ, July 19th, 2011
  241. @PitaJ -

    Looks like you’re missing the CACHE: bit just after CACHE MANIFEST.

    Ryan Seddon, August 3rd, 2011
  242. I made a iPhone4 webpage using html5, canvas, audio, javaScript and others. It works well. For a while it wroks off line. But soon it disappears. So I would learn your instructions here to make my site stand alone.
    The page itself is a page for Schoenbrg and Kandinsky.
    http://www.geocities.jp/imyfujita/air/air.html

    Iori Fujita, August 13th, 2011
  243. Made the manifest file and added the html code. Loaded it on safari, saved bookmark to home screen so I can run it as a web app, turned on airplane mode, then loaded the bookmark and I get a popup saying: “…could not be opened because it is not connected to the Internet.”

    But it loads fine after I hit “Retry”. Am I not added enough files in the manifest? Anyway of getting rid of this window that pops up? I want it to run just like an app when offline. Thanks.

    lmwong, August 22nd, 2011
  244. @lmwong

    Hard to say without seeing exactly what you’re doing.

    Ryan Seddon, August 22nd, 2011
  245. It could be that 45 of the resources don’t have expiration dates. I usually leave a two year expiration date for the items on my sites. lib2obf_b8.js has a short life as well (once it runs out, it will have to reload)

    I found this using the audit in safari’s developer menu.

    Gerry Straathof, August 22nd, 2011
  246. I have found the cache initialization is not ‘instant’ on the advices, and usually takes 30 seconds or more before the device realizes that “oh. you want to SAVE this stuff… pfft… here. Baby. there. satisfied?”

    I certainly wish they had just used a web archive system like on the desktop version of safari. So much less complicated.

    Gerry Straathof, August 22nd, 2011
  247. Great article, helped a good deal. I have an issue with the status always returning 0. Using several tools to verify my cache.manifest, it returns the correct mime type and has no syntax errors. Trying to troubleshoot the process and there really aren’t a lot of places to set breakpoints. I’m using IIS 7 and the site has the mime type of mime type set correctly to text/cache-manifest. Am I missing something here? I’ve tested the manifest on the latest versions of chrome, safari, and firefox with no success except for being able to determine the 0 zero status.

    Jeremiah, October 13th, 2011
  248. @Jeremiah

    The applicationCache API is very fragile and will break at any given chance it gets. Your error seems like you either have a misspelt asset in your manifest or one that doesn’t exist. Do you have an online version to look at?

    Ryan Seddon, October 16th, 2011
  249. Thanks!
    Any idea how to be able to use more than 5MB for?
    Is it per page, per site or per “app” the limit is set?
    Cheers!

    Anders, November 2nd, 2011
  250. I don’t know what i’m doing wrong!

    I made the mobile site and used the almost the same code of the DEMO.

    Please, take a look and tell me why images aren’t going to the iphone cache.

    The mobile:
    http://www.rincaogrill.com.br/beta/iphone/

    TNX

    Rodrigo Aranha, November 8th, 2011
  251. @Rodrigo A

    Your manifest file has the wrong mimetype web-sniffer is telling me it’s application/octet-stream.

    Ryan Seddon, November 8th, 2011
  252. I am having lots of problems with this, so if you don’t mind I would like to ask you a few questions. I have checked everything, but my real scenario is complicated, so I have tried to upload your project and it is not working for me:

    http://www.portfoliomultimedia.es/apps/offline_webapp

    http://www.portfoliomultimedia.es/apps/offline_webapp/thecssninja.manifest

    The only thing I have changed is the .manifest, because it is the myme termination I added.

    So, my questions would be:

    - Is there something more to check in the server than the myme type?

    - All the files loaded by the initial index must be in the manifest?

    - If I have a video added to the manifest it fails or it just doesn’t cache it?

    - Are you all sure about the 5mb limit?. I have been trying and think that I have seen a dialog asking me to let the app grow the mb limit.

    - Is there any issue related to the app being in fullscreen mode?

    Thank you very much for this great tutorial

    Jorge

    Jorge, December 21st, 2011
  253. @Jorge

    Your hosted demo is missing a reference to the vomzom.svg file, if any file is missing that’s declared in the manifest it will fail.

    All the files loaded by the initial index must be in the manifest?

    No, just the files you wish to cache so they’re available offline.

    If I have a video added to the manifest it fails or it just doesn’t cache it?

    I believe iOS5 may allow videos and audio to be cached offline, before that it didn’t work.

    Are you all sure about the 5mb limit?. I have been trying and think that I have seen a dialog asking me to let the app grow the mb limit.

    I’m not a 100% sure this is what other people have found to be the case, there may very well be a prompt to increase storage size.

    Is there any issue related to the app being in fullscreen mode?

    Fullscreen mode should be fine, if it’s a UIWebView inside an app offline caching is not available.

    Ryan Seddon, December 22nd, 2011
  254. The message that comes up when you visit a cached site is to increase the cache storage of your device, not the individual site. I’ve had.mine go up to 50M when doing beta testing. if you installed the Kindle reader you will also get a confirmation.

    The individual site allowance is above 5M on ios5, but i am not sure how much more. the highest mine has gone is 9.75M for a website magazine that was part of a class project.

    I use a php file which builds a manifest file for a site using everything in the folder. it has made it much easier to control changing documents.

    I think the kindle reader and new York times(?) use sql to hold their downloaded data, but have notdirected their codes behaviour with chrome or safari audits…

    Gerry Straathof, December 22nd, 2011
  255. Hi Mr Ninja
    Thanks a lot for all your great work and help!
    I ve installed a launch screen to your demo app on my iPad (ios4.2.1)
    I have the very same problem as many people above: works fine online/offline but if I 1/ go offline 2/suppress the screen in safari , then I get the message ” cannot acess bla bla bla… ” when i restart the webapp, which makes it not very usefull…
    Unless I missed a line, I think you answer has always been up to now: ” i don’t have this problem with my IOS version”. Is it still the case or have you experienced the problem and found a solution? what ios version do you use?
    Thank in advance for you enlightments.

    Jmv, December 30th, 2011
  256. Hi Mr Ninja
    (previous post continued)
    I have done a lot of tests with your files on my website (jmv38.comze.com). Thanks to your console-data-logger I have found the following strange facts, please comment if this sounds correct to you:
    - your code makes an offline app from the file ”index.html”, but on the ipad/safari I can access to the offline page only by calling ”jmv38.comze.com”, and not ”jmv38.comze.com/index.html” that returns an ”no connection” error.
    - then the call back to ”index.html” from ”article.html” never works offline. Putting href=”jmv38.comze.com” doesnt work either because it seems to call ”jmv38.comze.com/index.html”…
    So I thought I was now ready to make of my own page (a game timer) a webapp. I have done everything as in your code (and copied your console-data-logger with minor modifications), and… ‘:-(( it doesn’t work! The cache apparently downloads the files, but at the end of the process an error is fired. If I put 1 or 2 html files only in the cache the errors fires much faster. I have used the sniffer to verify that my manifest has the correct mime-type: ok. So I have no idea of what is happening… Could you give a look to the problem? Your help would be very very very much appreciated! Thanks in advance!
    Jmv

    Jmv, December 31st, 2011
  257. This totally kicked ass! Thanks for the great article.

    I just wanted to share that the article.html page links back to

    http://www.thecssninja.com/demo/offline_webapp/index.html

    instead of just http://www.thecssninja.com/demo/offline_webapp/

    which causes a “Cannot Open Page” error; no doubt because it thinks that “index.html” is different to “/”. Changing the url back to

    http://www.thecssninja.com/demo/offline_webapp/

    fixes the problem. you might want to correct this in the link itself :)

    thanks again!

    Brett, January 4th, 2012
  258. Hi Mr Ninja, it’s me again.
    I have done some more tests I’d like to share with you.
    I have put your code in a new domain name, and everything worked very fine online, offline, all the console message were OK.
    Then I have added a single line in the 2 html files:

    <meta content="yes" name="apple-mobile-web-app-capable">
    

    This is to make the app open like a stand-alone app, not in SAFARI.
    And then everything went wrong: always an error fired after downloading of the cache.
    So I suppressed the line, changed the cache revision so it updates the files, but it never worked back again… My safari seems to be stuck in a ”problem state” from where it won’t go out. Don’t know what to do…
    Any advice?
    Best regards.

    Jmv, January 5th, 2012
  259. @Jmv

    I just tested your web app in firefox, chrome and iOS5 safari, they all work offline and the caching works correctly. I can’t see any problems with your code of manifest file (although your manifest file should now have the extension .appcache over .manifest, but that shouldn’t effect anything).

    Ryan Seddon, January 5th, 2012
  260. @Brett -

    Thank you! I’ve updated the demo and demo files to add “index.html” to the manifest file so now that link back to “index.html” will work offline correctly.

    Ryan Seddon, January 5th, 2012
  261. Thanks for the post. Very helpful. When I read about the Mime type I thought “That’s why it’s not working!” but alas things are still quirky.
    Using an iPad2:
    1. I visite your demo page online
    2. I then go offline and visit the demo page again by entering http://www.thecss... in the navigation bar. I select the demo page from the drop down and the demo webapp comes up fine.
    3. Hit refresh; Safari come up with message. Cannot Open Page: Safari cannot open the page because it is not connected to the internet.
    4. If I enter the whole address in the bar and click ‘Go’ I get the same error message.
    5. If I make a bookmark and click it offline I will get your webpage without the error message.

    My application on the otherhand will only continue to work after being disconnected if I do not navigate away from the page. I can’t bring the page back up with out getting the error message when I have disconnected from the network.

    Is there a setting that will instruct safari to look for a cached website before it tries to connect to the internet? That seems to be the issue.

    Thanks, Doug

    Doug, January 10th, 2012
  262. @Ryan Seddon
    (previous post continued)

    Hi Mr Ninja

    Thank you very much for having looked to my problem.
    So for you everything was ok and for me there was an error.
    I have tried again my own webbapp after not trying for one week and..
    It worked! No error, everything fine! Even as a stand-alone webbapp (with a launch screen and not opening in Safari). Why is it so unpredictable?

    I have found an excellent site that give some explaination of what might be happening here. In short: it has to do with the fact that files send by the web server to safari have themselves some ”lifetime” and are not resend systematically, even if they have changed. Another ”cache” is involved here, the native browser cache, that is different from the ”appCache” we are trying to put in place. So although we change our file on the server side, it may not be changed on the iPad-Safari side, at least for some time, depending on how the lifetime is parametered on the server side! The site gives some advice on how to put some more commands on the .htaccess file to makes sure files are resent each time they are requested on the client side. I haved tried these commands, and also forced the safari cache to empty, but since everything was fine it has not changed anything.

    This excellent site is: http://diveintohtml5.info/offline.html , see the chapter named: THE FINE ART OF DEBUGGING, A.K.A. “KILL ME! KILL ME NOW!”

    The file refresh problem I just described might well be the cause of the problems many other users have experienced, driving them nuts! So I hope this post will help them.

    So now i should be happy with my webapp… but not quite. I have implemented some sound effects in an .mp3 file: they work fine online but not offline. Do you have any idea of what might be going on? Maybe caching mp3 is not allowed on ios 4.3? I have found no clear answer on the web.

    Any help on the subject would be highly appreciated

    Thanks
    JMV

    Jmv, January 15th, 2012

Trackbacks

  1. [...] research into offline capabilities.  HTML 5 offers some exciting new capabilities in this area. Here’s a great article on how to take advantage of offline access to content in HTML [...]

    Going Offline with HTML5 | PointAbout: Mobilize Your Brand, July 22nd, 2009
  2. [...] und lässt sich sowohl dynamisch als auch von Hand erstellen. Richtig gute Anleitungen zum Thema gibt es bei thecssninja und auf [...]

    iFUN.de/iPhone :: Alles zum iPhone − Offline, mit Icon und im Vollbild: Tipps für den Entwurf eigener Web-Applikationen, December 30th, 2009
  3. [...] This article has gotten me started. [...]

    Caching content « fredsherbet.com, January 29th, 2010
  4. [...] How to create offline webapps on the iPhone [...]

    How to Make an HTML5 iPhone App, March 27th, 2010
  5. [...] How to create offline webapps on the iPhone [...]

    How to Make an HTML5 iPhone App - Programming Blog, March 27th, 2010
  6. [...] How to Create offline Webapps on the iPhone [...]

    HTML5 Unleashed: Tips, Tricks and Techniques | MyInfoNetHome.Info, May 19th, 2010
  7. [...] Things might fail if the Cache Manifest MIME type is wrong, so use your browser's debugging tools or a service like Web Sniffer to check it (thanks CSS Ninja). [...]

    Offline Apps with Application Cache: Quickstart, Tips, and Deep Dive, May 19th, 2010
  8. [...] How to Create offline Webapps on the iPhone [...]

    彼岸(Into the wild) » Blog Archive » HTML5 Unleashed: Tips, Tricks and Techniques, May 24th, 2010
  9. [...] How to create offline webapps on the iPhone [...]

    Как сделать HTML5 приложение для iPhone | Web-Sence - под влиянием интернета, June 23rd, 2010
  10. [...] How to create offline webapps on the iPhone [...]

    如何用HTML5制作iPhone App | yakjuly's blog, June 27th, 2010
  11. [...] How to create offline webapps on the iPhone [...]

    How to Make an HTML5 iPhone App « Delicious Mangoes, July 19th, 2010
  12. [...] 如何在 iPhone 上创建离线应用程序 [...]

    解读 HTML5:建议、技巧和技术 - 幸福收藏夹, July 20th, 2010
  13. [...] 如何在 iPhone 上创建离线应用程序 [...]

    给HTML5的建议、HTML5的技巧和技术 | 实时信息(shtion.com), July 21st, 2010
  14. [...] 如何在 iPhone 上创建离线应用程序 [...]

    解读 HTML5:建议、技巧和技术 | FEDEV, July 23rd, 2010
  15. [...] 如何在 iPhone 上创建离线应用程序 [...]

    解读 HTML5:建议、技巧和技术 | 田园牧歌, July 31st, 2010
  16. [...] 如何在 iPhone 上创建离线应用程序 [...]

    Soun's Blog » Blog Archive » 解读 HTML5:建议、技巧和技术。, August 17th, 2010
  17. [...] found a link http://www.thecssninja.com/javascript/how-to-create-offline-webapps-on-the-iphone. According to their advice, I tried using Web Sniffer to determine if the manifest is served [...]

    Problem with HTML5 Offline Applications « Ng Pan Wei, October 10th, 2010
  18. [...] Nochmal gute Übersicht und viele Tipps und viele Kommentare: http://www.thecssninja.com/javascript/how-to-create-offline-webapps-on-the-iphone [...]

    Application Cache Manifest « Der faule Programmierer, November 15th, 2010
  19. [...] 如何在 iPhone 上创建离线应用程序 [...]

    Html5从入门到精通 – 王魏博客-关注前端,记录生活,记录互联网, December 6th, 2010
  20. [...] 如何在 iPhone 上创建离线应用程序 [...]

    解读 HTML5:建议、技巧和技术 | 飞翔代码, March 2nd, 2011
  21. [...] How to Create offline Webapps on the iPhone [...]

    HTML5 Unleashed: Tips, Tricks and Techniques - Leebay's Blog, March 6th, 2011
  22. [...] How to create offline webapps on the iPhone [...]

    如何用HTML5制作iPhone App【转】 - html5时代 - HTML5/CSS3/移动互联网资讯与技术交流分享博客, March 28th, 2011
  23. [...] http://www.thecssninja.com/javascript/how-to-create-offline-webapps-on-the-iphone http://html5demos.com/storage http://diveintohtml5.org/storage.html ← .htaccess Tricks for Better WordPress SEO & Security [...]

    iPhone webapp with HTML5 localStorage | van der Straten, March 28th, 2011
  24. [...] 如何在 iPhone 上创建离线应用程序 [...]

    解读 HTML5:建议、技巧和技术 | blog.moocss.com, June 20th, 2011
  25. [...] 如何在 iPhone 上创建离线应用程序 [...]

    解读 HTML5:建议、技巧和技术 - yhkyoの程序员修炼之道 – yhkyo.com, June 22nd, 2011
  26. [...] How to create offline webapps on the iPhone [...]

    Как сделать HTML5 приложение для iPhone | SAP R/3 готовые решения – коллективный блог специалистов SAP, July 10th, 2011
  27. [...] How to Create offline Webapps on the iPhone [...]

    解读 HTML5:建议、技巧和技术 - Leebay's Blog, July 10th, 2011
  28. [...] 如何在 iPhone 上创建离线应用程序 [...]

    解读 HTML5:建议、技巧和技术 | 2Kid, August 23rd, 2011

Leave a comment