Similar questions have been asked before, but I could never find a solution.
Here is my situation - my UIWebView loads a remote html page. The images used in the web pages are known at build time. In order to make the page load faster, I want to package the image files in the iOS application and substitue them at runtime.
[Please note that the html is remote. I always get answers for loading both html and image files from local - I have done that already]
The closest recommendation I got was to use a custom url scheme such as myapp://images/img.png in the html page and in the iOS application, intercept the myapp:// URL with NSURLProtocol subclass and replace the image with a local image. Sounded good in theory, but I haven't come across a complete code example demonstrating this.
I have Java background. I could do this easily for Android using a Custom Content Provider. I am sure a similar solution must exist for iOS/Objective-C. I don't have enough experience in Objective-C to solve it myself in the short timeframe I have.
Any help will be appreciated.
Ok here is an example how to subclass NSURLProtocol and deliver an image (image1.png) which is already in the bundle. Below is the subclasses' header, the implementation as well as an example how to use it in a viewController(incomplete code) and a local html file(which can be easily exchanged with a remote one). I've called the custom protocol: myapp://
as you can see in the html file at the bottom.
And thanks for the question! I was asking this myself for quite a long time, the time it took to figure this out was worth every second.
EDIT: If someone has difficulties making my code run under the current iOS version, please have a look at the answer from sjs. When I answered the question it was working though. He's pointing out some helpful additions and corrected some issues, so give props to him as well.
This is how it looks in my simulator:
MyCustomURLProtocol.h
@interface MyCustomURLProtocol : NSURLProtocol
{
NSURLRequest *request;
}
@property (nonatomic, retain) NSURLRequest *request;
@end
MyCustomURLProtocol.m
#import "MyCustomURLProtocol.h"
@implementation MyCustomURLProtocol
@synthesize request;
+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
if ([theRequest.URL.scheme caseInsensitiveCompare:@"myapp"] == NSOrderedSame) {
return YES;
}
return NO;
}
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest
{
return theRequest;
}
- (void)startLoading
{
NSLog(@"%@", request.URL);
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[request URL]
MIMEType:@"image/png"
expectedContentLength:-1
textEncodingName:nil];
NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"image1" ofType:@"png"];
NSData *data = [NSData dataWithContentsOfFile:imagePath];
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
[response release];
}
- (void)stopLoading
{
NSLog(@"something went wrong!");
}
@end
MyCustomProtocolViewController.h
@interface MyCustomProtocolViewController : UIViewController {
UIWebView *webView;
}
@property (nonatomic, retain) UIWebView *webView;
@end
MyCustomProtocolViewController.m
...
@implementation MyCustomProtocolViewController
@synthesize webView;
- (void)awakeFromNib
{
self.webView = [[[UIWebView alloc] initWithFrame:CGRectMake(20, 20, 280, 420)] autorelease];
[self.view addSubview:webView];
}
- (void)viewDidLoad
{
// ----> IMPORTANT!!! :) <----
[NSURLProtocol registerClass:[MyCustomURLProtocol class]];
NSString * localHtmlFilePath = [[NSBundle mainBundle] pathForResource:@"file" ofType:@"html"];
NSString * localHtmlFileURL = [NSString stringWithFormat:@"file://%@", localHtmlFilePath];
[webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:localHtmlFileURL]]];
NSString *html = [NSString stringWithContentsOfFile:localHtmlFilePath encoding:NSUTF8StringEncoding error:nil];
[webView loadHTMLString:html baseURL:nil];
}
file.html
<html>
<body>
<h1>we are loading a custom protocol</h1>
<b>image?</b><br/>
<img src="myapp://image1.png" />
<body>
</html>