2

I am working with a Drupal developer to develope an iPhone app that fetches a portion of it's content from a Drupal site, stores it in a file system, and displays it locally in a UIWebView. We've run into a bit of a problem though, and we're looking for a solution, either in Drupal or on the iPhone end of things.

The Setup

  • As Drupal content changes, it will create manifests of the changed content that the iPhone can download. The manifests simply list relative links to the new content to download.
  • Once downloaded, the app stores the content locally in a web page.
  • The iPhone loads the content into a UIWebView; links navigate between all the various pages.

The Problem

  • Drupals relative links are relative to the root of the site - i.e. they contain a leading '/'. Obviously when I'm loading pages, links relative to the root of the filesystem won't work, since the content resides in the app's document directory. I can prepend the document directory to links the user taps using -webView:shouldStartLoadWithRequest:navigationType:, checking to see if the NSURLRequest contains a url starting with the document directory and redirecting it if it does not. However, this does not help with page resources - e.g. CSS files and images.
  • Drupal does not append file extensions to paths, which creates a similar dilemma. UIWebView's -loadRequest method only seems to work if it is fed an NSURLRequest that contains a URL to a file with a file extension. Otherwise I receive a WebKitErrorDomain error code 102: "Frame load interrupted". It may be possible to work out a solution using UIWebView's -loadHTMLString:baseURL:, but that method is very unfriendly to the code when the user taps on links (I'm not sure why at this point).

Disregarding -release messages, the code I am using to load pages is:

NSString *fileToLoad = [appDelegate.webContentDirectory stringByAppendingPathComponent:filename];
NSURL *url = [[NSURL alloc] initFileURLWithPath:fileToLoad isDirectory:NO];
NSURLRequest *newURLRequest = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:(NSTimeInterval)5];

[self.webView loadRequest:newURLRequest];

I am open to creative thinking - e.g. is there an iPhone web server I could set up in-app that would automatically take care of both problems?

JoBu1324
  • 7,751
  • 6
  • 44
  • 61

3 Answers3

0

To solve the CSS/Image issue: You could read in the files content into a NSString when you are downloading the files refrenced from your manifest, append your document directory path to the path of your css/image files, then just save that string overwriting the "old" file.

Björn Kaiser
  • 9,882
  • 4
  • 37
  • 57
  • Does this basically require parsing and rewriting the HTML on the fly? I think we will end up figuring out a way to do that on the web-server end if we decide to go down that route; for now we were trying to avoid HTML-rewriting in general if it's at all possible (I'm the Drupal developer mentioned in the question). – Ben Dunlap May 12 '11 at 20:25
  • Agreed. At the moment we're looking into subclassing NSURLProtocol to override the default http:// request behavior. However, I don't have much experience on that end of things, so some confirmation that I'm on the right track would certainly be appreciated! – JoBu1324 May 12 '11 at 21:47
0

Sorry if I don't fully understand what you want to do. But from my understanding you are locally caching the HTML source of a node page, keeping all resources (images, CSS, JavaScript, etc.) on the server side.

Why don't you use UIWebView's method:

- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL

http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIWebView_Class/Reference/Reference.html#//apple_ref/occ/instm/UIWebView/loadHTMLString:baseURL:

Where the parameters are:

  • string: your locally cached HTML source
  • baseURL: the full domain NSURL of the web site

The UIWebView should then seamlessly load any resource without any problem.

jchatard
  • 1,881
  • 2
  • 20
  • 25
  • Oh sorry I just notice the last bullet point. What's wrong when you say 'but that method is very unfriendly to the code'? – jchatard May 13 '11 at 06:26
  • Without going into details, the NSURLRequest acted differently than I expected when the user clicked a link. There could have been a number of factors involved, though. Thanks for your answer anyway - but I found what I was looking for. Subclassing NSURLProtocol solved all our problems! – JoBu1324 May 13 '11 at 17:51
0

Subclassing NSURLProtocol is exactly the answer we were looking for. After registering our subclass with the system and configuring it to selectively handle html requests (effectively overriding the default html protocol handler where we saw fit), I was able to load whatever content I wanted to for each request. In essence I redirected http requests to the load files from the cached content.

For any who are interested, the answer was from this very interesting question: Allow UIWebView to load http://localhost:port/path URIs without an Internet connection

Community
  • 1
  • 1
JoBu1324
  • 7,751
  • 6
  • 44
  • 61