3

I am trying to run code when a page is finished loading in my webViewDidFinishLoad. However, if I visit google.com in my UIWebView then type in a search, the first query works, but all additional searches will not trigger the webViewDidFinishLoad. According to other articles this is because of google using ajax requests. To combat this inject javascript into the pages to trigger an iOS method once done loading. However, it doesn't seem to work properly for google, but works for other ajax sites like yahoo.

Am I doing the javascript properly? Does anyone have a suggestion on how to get the javascript to call the Obj-C method after the ajax is done loading?

ajax_handler.js (bundled with app)

var s_ajaxListener = new Object();
var originalReadyStateChange;
s_ajaxListener.tempOpen = XMLHttpRequest.prototype.open;
s_ajaxListener.tempSend = XMLHttpRequest.prototype.send;
s_ajaxListener.callback = function () {
    console.log(this);
    if (this.readyState == 4) {
        console.log("TRIGGERING HANDLER");
        window.location='x3AjaxHandler://' + this.url;
        console.log(originalReadyStateChange);

    } else {
        console.log("READY STATE NOT FINISHED");
    }
    originalReadyStateChange();
};

XMLHttpRequest.prototype.open = function(a,b) {
    if (!a) var a='';
    if (!b) var b='';
    s_ajaxListener.tempOpen.apply(this, arguments);
    s_ajaxListener.method = a;
    s_ajaxListener.url = b;
    if (a.toLowerCase() == 'get') {
        s_ajaxListener.data = b.split('?');
        s_ajaxListener.data = s_ajaxListener.data[1];
    }
}

XMLHttpRequest.prototype.send = function(a,b) {
    if (!a) var a='';
    if (!b) var b='';
    s_ajaxListener.tempSend.apply(this, arguments);
    if(s_ajaxListener.method.toLowerCase() == 'post')s_ajaxListener.data = a;

    console.log(this);
    originalReadyStateChange = this.onreadystatechange;
    this.onreadystatechange = s_ajaxListener.callback;
}

WebView

#define CocoaJSHandler          @"x3AjaxHandler"

static NSString *ajaxInjectionHandler;

+(void)initialize
{
    ajaxInjectionHandler = [NSString stringWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"ajax_handler" withExtension:@"js"] encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"js: %@", ajaxInjectionHandler);
}

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSLog(@"SHOULD LOAD");

    if ([[[request URL] scheme] caseInsensitiveCompare:CocoaJSHandler] == NSOrderedSame) {
        NSString *requestedURLString = [[[request URL] absoluteString] substringFromIndex:[CocoaJSHandler length] + 3];

        NSLog(@"ajax request: %@", requestedURLString);
        [self webViewDidFinishLoad:webView];
        return NO;
    }
    return YES;
}

- (void)webViewDidStartLoad:(UIWebView *)webView {

    NSLog(@"INJECTING");
    [webView stringByEvaluatingJavaScriptFromString:ajaxInjectionHandler];
}
Bot
  • 11,868
  • 11
  • 75
  • 131
  • What are you trying to do in `webViewDidFinishLoad`? Depending on that it may not make sense to try to treat searches as "separate page loads". – Rivera Apr 21 '14 at 01:06

1 Answers1

1

You could try to create and remove an iFrame with the url schema and path as src attribute. Setting window.location didn't worked for me. This worked for me so far:

function sendRequestToiOS(url) {
    // Create and append an iFrame to the document and set it with the url schema
    var iframe = document.createElement("IFRAME");
    iframe.setAttribute("src", "x3AjaxHandler://" + url);
    // For some reason we need to set a non-empty size for the iOS6 simulator...
    iframe.setAttribute("height", "1px");
    iframe.setAttribute("width", "1px");
    document.documentElement.appendChild(iframe);
    iframe.parentNode.removeChild(iframe);
    iframe = null;
}
  • Can you expand on this a bit more? I am not sure this would solve the issue as the `console.log` wasn't being triggered. It was almost as if `send` wasn't being triggered period. – Bot Apr 25 '14 at 15:46
  • After testing this it still has the same effect as the callback isn't being called – Bot Apr 25 '14 at 19:23