Ios – Can you intercept NSURLRequests in a UIWebView without breaking the back button

cocoa-touchiosnsurlrequestuiwebview

I'm having trouble loading custom HTML into my UIWebView without breaking its goBack method.

What Works

I'm intercepting the URL requests of my UIWebView so I can load custom HTML. I have control over all the HTML, so I have my special app requests use a custom scheme (ie. myapp://arg1/?arg2=val) that I can parse in webView:shouldStartLoadWithRequest:navigationType:. I decide what HTML I really want to load and call loadHTMLString:baseURL and return NO to cancel the original request.

What Doesn't Work

The above works great. The problem is that I want to make use of the UIWebView's goBack method and loadRequest: appears to be the only UIWebView method that adds to its history stack.

I have a few ideas, but I'm not sure which are feasible and how to go about them. The main thing seems to be that I have to return YES in webView:shouldStartLoadWithRequest:navigationType and I have to use UIWebView's loadRequest method.

Idea 1: Modify NSURLRequest/Response:
Can I subclass NSURLRequest so that (when the UIWebView makes the request) it doesn't actually make an HTTP request and returns an NSURLResponse with my HTML in it? Or maybe modify/subclass/add a category method to NSURLResponse somehow? I like the idea of it being a real request, but I'm concerned about private APIs and being rejected from the App Store.

Idea 2: Handle a custom URL Protocol
Register a custom URL protocol so my app responds to it and I can have it return a legitimate NSURLResponse (filled with my custom HTML.)

Idea 3: Fool the cache Create the request with this cache policy NSURLRequestReturnCacheDataDontLoad and then somehow get my HTML in between the webView and the cache?

Or maybe I'm on the wrong track completely?

Best Answer

There is another really clever approach which I just tested out: Instead of tinkering with the NSURLCache or rewriting the entire navigation history code, just create a custom NSURLProtocol which is used by the standard NSURLConnection whenever a HTTP request is made. There, you create your own NSURLRequest to load the data and can inspect the MIME type, change the content of the request or cache your data to disk as you please. This idea comes courtesy of Rob Napier:

http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588

His code is now also on GitHub:

https://github.com/rnapier/RNCachingURLProtocol