Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading text file by AJAX call in UIWebView using custom NSURLProtocol fails

Tags:

ios

uiwebview

I want to display a website on an iOS app using a UiWebView. Some components of the site (namely the webservice results loaded using AJAX calls) should be replaced by local data.

Consider the following example:

text.txt:

foo

page1.html:

<html><head>
    <title>test</title>
    <script type="text/javascript" src="jquery.js"></script>
</head>
<body>
<div id="target"></div>
<script type="text/javascript">
    function init(){
        $.get("text.txt",function(text){    
            $("#target").text(text);
        });
    }
    $(init);
</script>
</body></html>

View Controller:

@interface ViewController : UIViewController <UIWebViewDelegate>
    @property (nonatomic,assign) IBOutlet UIWebView *webview;
@end


@implementation ViewController
    @synthesize webview;
    //some stuff here
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [NSURLProtocol registerClass:[MyProtocol class]];
        NSString *url = @"http://remote-url/page1.html";
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];
        [request setCachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
        [webview loadRequest:request];
    }
@end

MyProtocol:

@interface MyProtocol : NSURLProtocol

@end

@implementation MyProtocol

+ (BOOL) canInitWithRequest:(NSURLRequest *)req{
    NSLog(@"%@",[[req URL] lastPathComponent]);
    return [[[req URL] lastPathComponent] caseInsensitiveCompare:@"text.txt"] == NSOrderedSame;
}

+ (NSURLRequest*) canonicalRequestForRequest:(NSURLRequest *)req{
    return req;
}

- (void) startLoading{

    NSLog(@"Request for: %@",self.request.URL);
    NSString *response_ns = @"bar";
    NSData *data = [response_ns dataUsingEncoding:NSASCIIStringEncoding];
    NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[self.request URL] MIMEType:@"text/plain" expectedContentLength:[data length] textEncodingName:nil];

    [[self client] URLProtocol: self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    [[self client] URLProtocol:self didLoadData:data];
    [[self client] URLProtocolDidFinishLoading:self];
    [response release];
}

- (void) stopLoading{
    NSLog(@"stopLoading");
}

@end

If I don't register my custom URLProtocol the page is displayed properly. If I do startLoading() is called, the content is loaded and stopLoading() is triggered afterwards. But on the UIWebView nothing happends at all. I tried to do some error-handling, but neither is a JS AJAX error thrown nor is didFailLoadWithError of the UIWebViewDelegate called.

I tried another scenario and created a HTML page that just loads an image:

<img src="image.png" />

and modified my URLProtocol to just handle the loading of the image - this works properly. Maybe this has anything to do with AJAX calls?

Do you have any idea what the problem might be?

Thanks in advance!

like image 466
muffel Avatar asked Jan 16 '23 22:01

muffel


1 Answers

I had the same problem and finally solved it after days of hair pulling :

Your problem comes from the way you create the response, you have to create a status 200 response and force the WebView to allow cross-domain request if necessary :

NSDictionary *headers = @{@"Access-Control-Allow-Origin" : @"*", @"Access-Control-Allow-Headers" : @"Content-Type"};
NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:request.URL statusCode:200 HTTPVersion:@"1.1" headerFields:headers];

You can see my full working implementation in my answer here :

How to mock AJAX call with NSURLProtocol?

Hope this helps, Vincent

like image 180
vdaubry Avatar answered Jan 30 '23 03:01

vdaubry