19

I'd like to be able to use the html5 cache manifest to store images locally on an iPhone that is visiting the page via a UIWebView within an app.

I've set up a sample that I think conforms to the specs, and appears to work in safari 4 and mobile safari, but not in my app's UIWebView.

The sample html is set up at http://bynomial.com/html5/clock3.html.

This is very similar to the sample provided in the HTML5 draft standard.

Here is the entire (non-template) code of the sample app I'm using for testing:

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

  // I thought this might help - I don't see any difference, though.
  NSURLCache* cache = [NSURLCache sharedURLCache];
  [cache setDiskCapacity:512*1024];

  CGRect frame = [[UIScreen mainScreen] applicationFrame];
  UIWebView* webView = [[UIWebView alloc] initWithFrame:frame];
  [window addSubview:webView];

  NSString* urlString = @"http://bynomial.com/html5/clock3.html";
  NSURL* url = [NSURL URLWithString:urlString];
  NSURLRequest* request = [NSURLRequest requestWithURL:url];
  [webView loadRequest:request];

  [window makeKeyAndVisible];
}

I've reviewed a few related questions on stackoverflow, but they don't seem to provide info to solve this. For example, I'm pretty sure the files I'm trying to cache are not too large, since they are just a couple small text files (way < 25k).

Any ideas for how to get this to work?

Tyler
  • 28,498
  • 11
  • 90
  • 106

5 Answers5

26

I got this to work using a .manifest file in a UIWebView. I discovered the trick on the Apple developer forums.

you must deliver the proper mime-type for the manifest file: it must be of type "text/cache-manifest" - if it is anything else, then you won't get your files cached.

you can use web-sniffer at http://web-sniffer.net/ to look at the headers returned by your server.

if you are using .htaccess files on your web server, then add the following line to the .htaccess file:

AddType text/cache-manifest .manifest

make sure to clear your browser cache after making this change to see the effect.

HTH Mark

edit: this is only supported on iOS 4.0 and later. You will need to implement your own caching mechanism for iOS 2.x and 3.x :-(

Mark Lummus
  • 740
  • 8
  • 17
  • Very cool, but needing iOS4 is still a deal breaker right now for many developers. But a step in the right direction for sure. – Alex Wayne Feb 08 '11 at 19:21
  • 4
    Extra tip for anyone searching: you don't need a web sniffer for this. Just fire up a terminal session and issue this: `curl -I http://YOUR_DOMAIN/PATH/TO/CACHE_MANIFEST` – Ben Jun 29 '11 at 17:36
  • 3
    It's not a deal breaker anymore. – Bruno Bronosky Jul 27 '12 at 02:53
3

You could use the cachePolicy param on the NSURLRequest.

request = [NSURLRequest requestWithURL:[NSURL URLWithString:reqString] cachePolicy:NSURLRequestReturnCacheDataDontLoad timeoutInterval: 10.0];

documented here.

Eoin
  • 767
  • 3
  • 12
  • This doesn't work. Here is how I know: I built a sample file with a cache manifest, and I loaded this file in 3 browsers: (1) Firefox (2) mobile Safari, (3) a UIWebView using NSURLRequestReturnCacheElseLoad (if I use DontLoad then it _never_ loads). Then I modify a cached image on the server. Firefox and Safari both correctly display the old image; my UIWebView gets the new image. – Tyler Nov 04 '09 at 19:35
2

UIWebView's cannot (or will not) use the HTML5 appcache. They just don't. Maybe in iPhone OS 4.0.

But what you can do is fetch all the files yourself with network calls (or just have them in your app bundle) and load up the webview with a local URL pointing to your local HTML file, which can have relative URLs to local assets.

There is no super simple "it just works" way to make this happen, however.

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • 3
    After much investigating, I agree that there simply is no easy way to solve this problem. The closest I could get was to implement my own subclass of NSURLCache and set that as the cache. However, even with all that, I found that often my cached results were rejected by the OS for reasons which were opaque to me. It seems that the OS is extremely picky about accepting cached responses, no matter what cache policy or other parameter tweaks I attempted. Quite frustrating to work with! – Tyler Mar 20 '10 at 23:52
1

Have you tried to create a customised NSURLCache object and use the setSharedURLCache: method, as recommended in the documentation:

"Applications with more specific needs can create a custom NSURLCache object and set it as the shared cache instance using setSharedURLCache:"

William Niu
  • 15,798
  • 7
  • 53
  • 93
  • 1
    Yes I have. It does not cause the cache manifest to work, although you can use that technique to try to create your own cache -- but this is trickier than it sounds like, because the NSURL framework rejects some cached responses for unknown reasons. – Tyler Dec 08 '09 at 15:46
  • I've noticed the same thing. It's quite finicky. – Alex Wayne Jan 20 '10 at 08:03
1

I was experiencing the same problem. Although I used:

[NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0];

It didn't seem to want to use the cached data. Meaning it constantly made the request to my webservice to retrieve the latest content and thus made caching useless.


I did find a work-around. When loading the URL in the UIWebView use the following code:

NSString *html = [NSString stringWithFormat:@"<html><head><script type=\"text/javascript\">location.href='%@';</script></head><body></body></html>", [[currentURLRequest URL] absoluteString]];
[self.webView loadHTMLString:html baseURL:nil];

This has been tested on the OS 4.2, since I use the manifest to handle the caching (HTML5). There is a big chance that it won't work on OS 2.x/3.x, thou this needs to be confirmed.

The cons about using this method is that you can't send any POST data with your request.

Hope this helps anyone.


You still need to send the request with 'cachePolicy:NSURLRequestReturnCacheDataElseLoad' else it will still not work.

Mark
  • 16,906
  • 20
  • 84
  • 117
  • What would I need to do if I am loading a UIWebView from a pre-generated html body NSString which refer to the files I need cached? Basically I assume it may be a different Java call? Any ideas? – Marius May 04 '11 at 22:11