Wednesday, April 6, 2011

Opening popup links in UIWebView, possible?

Hey guys,

I have a UIWebView which I'm using as an embedded browser within my app.

I've noticed that links in webpages that open new windows are ignored without any call into my code.

I've tried breakpointing on

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType

and then selecting a link that would open a popup window, and the breakpoint is never hit. Is there anything I can do to intercept that selection of the popup link and get the URL and just load it normally?

I'm not interested in displaying a popup window in the app itself, I just want the URL of whatever is going to be loaded in the popup window to load in the main webview itself.

Is this possible?

Thanks!

From stackoverflow
  • Yes this is totally possible, and is the entire point of the shouldStartLoadWithRequest: delegate method.

    The core issue here is to figure out why you're not hitting your breakpoint in that method. My gut instinct would be that you haven't properly set the UIWebView's delegate property to the object implementing this method.

    Jasarien : Thanks for the suggestion, but the delegate is set. I hit the breakpoint if normal links are clicked. It would seem that interally, the UIWebView class purposefully ignores links that will open in a new window.
  • So after a small amount of research, it's clear that the UIWebView class purposefully ignores links that will open in a new window (either by using the 'target' element on the a tag or using javascript in the onClick event).

    The only solutions I have found are to manipulate the html of a page using javascript. While this works for some cases, it's not bulletproof. Here are some examples:

    links = document.getElementsByTagName('a');
    for (i=0; i<links.length; i++)
    {
        links[i].target='_self';
    }
    

    This will change all links that use the 'target' element to point at _self - instead of _blank or _new. This will probably work across the board and not present any problems.

    The other snippet I found followed the same idea, but with the onClick event:

    links = document.getElementsByTagName('a');
    for (i=0; i<links.length; i++)
    {
        links[i].onclick='';
    }
    

    This one is just plain nasty. It'll only work if the link tag has it's href element correctly set, and only if the onclick event is used to open the new window (using window.open() or something similar). The reasons why it is nasty shouldn't need explaining, but one example would be if the onClick is used for anything other than opening a window - which is a very common case.

    I guess one could go further with this and start doing some string matching with the onClick method, and check for window.open(), but again, this is really far from ideal.

  • I ran into this as well, and HTML rewriting was the best solution I could come up with. The biggest issue that I ran into with that approach is that the web browser is interactive for up to a couple of seconds until the webViewDidFinishLoad: method is called, so the links seem to be broken for a few seconds until they're rewritten.

    There's three areas that I rewrote: links, form posts, and calls to window.open().

    I used a similar approach to the first code snipped in Jasarian's answer to overwrite the target for links and forms by iterating over tags and forms. To override window.open, I used code similar to the following:

    var oldWindowOpen = window.open;
    window.open = function(url, sName, sFeatures, bReplace) {
      oldWindowOpen(url, '_self');
    };
    
  • Here's how I get twitter links to work (i.e. link to pages that try to open with new windows):

    -(BOOL)webView:(UIWebView *)mainWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {

    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
        //Allows for twitter links
        [self.mainWebView loadRequest:request];
        return NO;
    }
    
    return YES;
    

    }

0 comments:

Post a Comment