UIWebView shouldStartLoadWithRequest only fires once when calling a modal view from inside

ぐ巨炮叔叔 提交于 2020-01-04 13:42:14

问题


I have part of my app written in JS and running inside of a WebView. I'm using the UIWebView shouldStartLoadWithRequest method to capture http requests as a means of communicating between JS and obj-c. This works great until I attempt to load a Modal View Controller over my webview from inside the shouldStartLoadWithRequest method. Once this happens, shouldStartLoadWithRequest is no longer called. Sometimes I need to dismiss this modal view controller and go back to the webview and do some things and then re-present the modal controller. The modal controller comes up the first time just fine, then I dismiss it and attempt to present it again by navigating to a URL from javascript and it no longer will present itself. NSLogs inside shouldStartLoadWithRequest are never run.

In my javascript I do something like this:

 window.location='myapp:whateverMethod';

objective c code looks like this:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    NSString *requestString = [[request URL] absoluteString];
    NSLog(@"REQUEST URL: %@", requestString);
    if([requestString hasPrefix:@"myapp:"]) {
        NSArray *components = [requestString componentsSeparatedByString:@":"];
        NSString *function = [components objectAtIndex:1];
        if([self respondsToSelector:NSSelectorFromString(function)]) {
            [self performSelector:NSSelectorFromString(function)];
        }
        return NO;
    }
    return YES;
}

-(void) whateverMethod {
    NSLog(@"whateverMethod called!");
    // This is a quick way to grab my view controller from the storyboard, so assume it exists
    UIViewController *splash = [self.storyboard instantiateViewControllerWithIdentifier:@"splashViewController"];
    [self presentModalViewController:splash animated:NO];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
        [self dismissModalViewController:splash animated:NO];
    });
}

At this point my webview is still visible. I navigate from page to page in my webapp and all javascript works great in it but the "shouldStartLoadWithRequest" delegate method of the webview no longer is called. I cannot figure out why. Does anyone have any ideas?


回答1:


I noticed that Cordova doesn't set the window.location property. Instead it has two options: it either creates an iframe and sets the src of the iframe to that url, or it creates an XMLHttpRequest object e.g. in the iOSExec() function:

    if (bridgeMode) {
        execXhr = execXhr || new XMLHttpRequest();
        // Changeing this to a GET will make the XHR reach the URIProtocol on 4.2.
        // For some reason it still doesn't work though...
        execXhr.open('HEAD', "file:///!gap_exec", true);
        execXhr.setRequestHeader('vc', cordova.iOSVCAddr);
        if (shouldBundleCommandJson()) {
            execXhr.setRequestHeader('cmds', nativecomm());
        }
        execXhr.send(null);
    } else {
        execIframe = execIframe || createExecIframe();
        execIframe.src = "gap://ready";
    }

That being said, it may be beneficial to use something like Cordova instead of trying to roll it yourself (even if it's just embedding their view controller), since they handle a lot of the headaches that come up with webview delegates.




回答2:


I've just had the same problem, but related to using a href="#" anchor.

This Stack Overflow answer sorted it

There are more answers on that thread that deal with widow.location, so you may have luck with them.




回答3:


Checked out Cordova and they have their own queuing system, not really a help. But...

Disobedient Media's answer gave me an idea. Instead of window.location, why not try window.location.hash.

Now some JS code for logging is:

function sendMsgToNative(msg)
{
    window.location.hash = '~cmd~' + msg;
}
console.log = function (msg) { sendMsgToNative('log~js ' + msg); };

and the Objective-C code is:

NSString *req = [request.URL absoluteString];
NSArray *components = [req componentsSeparatedByString:@"~"];

// Check for your protocol
if ([components count] > 1 && [(NSString *)[components objectAtIndex:1] isEqualToString:@"cmd"])
{
    // Look for specific actions
    if ([(NSString *)[components objectAtIndex:2] isEqualToString:@"log"])
    {
        NSString *logStr = [(NSString *)[components objectAtIndex:3] stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
        LOGI("%@", logStr);
    }
}

You get the full URL including 'http:...' so I chose tilde instead of colon, and incremented the indices. Now you can log all willy-nilly and send whatever amount of commands you want and they will all get through :-)




回答4:


I (embarrassingly) spent a couple of hours working on this today, and realised that in my viewDidDisappear: I was setting the UIWebViewDelegate to nil!

All I needed to do to fix was once the modal was dismissed, re-set the UIWebViewDelegate and everything worked again.



来源:https://stackoverflow.com/questions/17627838/uiwebview-shouldstartloadwithrequest-only-fires-once-when-calling-a-modal-view-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!