How to enable the popup window on UIWebView

Posted by Yoshimasa Niwa on 02/06, 2009

UIWebView is most important UIKit class of iPhone SDK, as you know, it includes all methods and functions of Mobile Safari. Though, I doesn’t accept the “open new window” or “popup window” of the link.

<a href="somehere" target="_blank" />Open this link in new window</a>

If this kind of link are shown in the UIWebView and user clicks it, nothing happens. Of course UIWebView is high-abstracted class and we SDK developer can invoke only a few methods, so there is not complete but good solution for this problem. The key methods are

language:objc
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
- (void)webViewDidFinishLoad:(UIWebView *)webView
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script

Hook all events of popup window

At first, we hooks all events of opening the new window from the current web page. How to do that? We can use JavaScript. The key concept is hooking all popup request and rewrite them to normal requests with special url in JavaScript then hooking these requests again in Objective-C and show the popup by ourselves.

language:objc
- (void)webViewDidFinishLoad:(UIWebView *)webView {
  [webView stringByEvaluatingJavaScriptFromString:/* string of next JavaScript */];
}

Than pass next JavasScript to stringByEvaluatingJavaScriptFromString.

language:javascript
var tags = document.getElementsByTagName("a");
for(var i=0; i < tags.length; i++) {
  var tag = tags[i];
  var t = tag.getAttribute("target");
  var h = tag.getAttribute("href");
  if(/* check the target and href */) {
    tag.setAttribute("target", "");
    tag.setAttribute("href", /* make a special url from href */);
  }
}

When the webViewDidFinishLoad is invoked, we run a javascript to hook all anchor tags and remove the target attribute and replace href attribute to the special one. also, we need another hooks for form and javascript events.

language:javascript
var tags = document.getElementsByTagName("form");
for(var i=0; i < tags.length; i++) {
  var tag = tags[i];
  var submit = tag.submit;
  tag.submit = function() {
    var t = tag.target;
    var a = tag.action;
    if(/* check target and action */) {
      tag.target = "";
      tag.action = /* make special url from action */
    }
    return submit.apply(this, arguments);
  };
}

This hook should work in many situations. This code though doesn’t work for all situations, especially, the form has a submit event listener.

language:javascript
window.open = function(url) {
  if(/* check the url */) {
    var t = document.createElement("a");
    t.setAttribute("href", /* make a special url */);
    var e = document.createEvent("MouseEvent");
    e.initMouseEvent("click");
    t.dispatchEvent(e);
  }
};

This hook is quite strange because we make a hidden anchor tag and click behind the screen to invoke the HTTP request with a special url so that we can hook the popup event inside Objective-C code.

Hook the popup event inside Objective-C

Okay, now we back to the Objective-C world. Now we can get the event of popup in the delegate of UIWebView.

language:objc
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
  if(navigationType == UIWebViewNavigationTypeLinkClicked || navigationType == UIWebViewNavigationTypeFormSubmitted) {
    NSURL *url = [request URL];
    if(/* check the url is special or not */) {
      NSString *urlstr = /* convert special url to normal url */;
      NSMutableURLRequest *req = [request mutableCopyWithZone:nil];
      [req setURL:[NSURL URLWithString:urlstr]];

      if(/* is popup window close? */) {
        /* open a popup window */
      }
      [popupWebView loadRequest:req];
      return NO;
    }
  }
  return YES;
}

Yes, we can get all HTTP request of normal anchor tag at this absolute long name delegate method. Checking the request URL and if it is special one created inside our hook code of JavaScript, we convert it to normal URL and make a NSURLRequest then pass it to the popup window. By these hooks, we can open a popip window with UIWebView!

How to make the special URL

Good question, I didn’t mention this problem. Actuaylly, this is quite difficult, because we want to preserve the base urls of the requests. We couldn’t replace some safe part of the URL like schema or hostname etc. When we replace them, the base urls of the requesta may be discarded and we cannot create the new request inside webView:shouldStartLoadWithRequest:navigationType. My idea is appending special hash to the end of the URL. This is not safe for all situations but should work well in many situations.

language:javascript
function makeSpecialURL(url) {
  return url + (url.match(/#/) ? "_open" : "#open");
}

then inside webView:shouldStartLoadWithRequest:navigationType we can strip the additional hash.

language:objc
if([[url fragment] hasSuffix:@"open"]) {
  NSString *urlstr = [[url absoluteString] substringToIndex:[[url absoluteString] length] - 5];
  ...
}

Another methods?

I hope we can solve this problem using hidden API or delegate(webView:createWebViewWithRequest:), but there are no way to solve this problem inside the SDK documented area except using JavaScript hooks. This is hard and not so good implementation but I hope it helps your applications on iPhone!

Share

Comments

  • Dan Grigsby said at 02/17, 2009
    Very clever! Thanks for posting this to iPhoneFlow too.
  • Mike said at 06/18, 2009
    Thanks for the info. Just FYI - the first snippet, using "context.document.getElementsByTagName()" didn't work for me and took a while to debug without a proper Javascript debugging environment on the phone. Just change it to "document.getElementsByTagName()" and it works fine.
  • Yoshimasa Niwa said at 06/19, 2009
    Hi Mike, Exactly! I forgot strip "context." from the snippet. actually I had to use this hack inside frame so I'd add context var to change target frame.
  • RokaJoka said at 06/19, 2009
    What do you mean by?

    "/* is popup window close? */"
  • Yoshimasa Niwa said at 06/19, 2009
    Hi RokaJoke, It's my mistake... I cleaned up this snippet!
  • RokaJoka said at 06/19, 2009
    You mean this right?

    /* Is the popup window not already open? */

    //Open a popup window
  • Yoshimasa Niwa said at 06/20, 2009
    Hi RokaJoka, Yes. Nothing special there, you do just open a popup window!
  • Baskaran said at 07/09, 2009
    Do you have any idea on how to identify and navigate to individual pages in a UIWebView loaded with a PDF or word or pages? I tried windows.scrollByPage() funciton - but it does not work.
  • Yoshimasa Niwa said at 07/15, 2009
    Hi Baskaran, I think PDF or Word file is not rendered by WebKit directly and also, it is not HTML file. you can't use any JavaScript with them. Some hidden API may navigate the pages inside PDF or Word though, I have no idea about it.
  • Shin said at 12/03, 2009
    I am actually loading some text from a webpage and then the image associated with it in UIWebView . I have seen many news apps where u can click on the image and a larger zoomed images pops open. Any ideas how I can implement that. I have tried scalestofit but that isn't something which i would like to use since it makes the text very tiny to read. Also I'm not loading the whole webpage I am only loading some text and image so please give me a solution on how to open up a larger version of the image when a user clicks on the small thumbnail image.
  • siva said at 07/01, 2010
    Hi

    i need the favour in Webview,actually im using the webpage of my site to login,after logging in the user have to take to my application.i mean have to display the next page in another view.where it has our toolbar and bottom bar.when the user enters inside the next page he have to be logged .there is any way to solve this issue.


    Thanks in advance...
  • Sg said at 07/01, 2010
    Hi, this looks like just what I need; I just want all urls to open regardless of whether they're new pages or not. But this code is full of /* ... */ comments and I have no idea how to do all this JavaScript code - I work in obj-c. Can I humbly request someone post a completed implementation with the comments replaced? Thanks for this.
  • Mahesh said at 11/27, 2010
    Hi,
    Thanks for the info.
    I have problem on showing Menu list button ( when you click this button, list of Menu will be shown) of a webpage in UIWebView. That is, if I see the web page in iPad safari the menu list button is aligned properly as we see in the desktop browser. But when I load this page in UIWebView, the page loaded correctly, but the Menu List button ( which might be Javascript) is not shown properly and placed one pixel down from the actual position. I should not change anything in the website for this issue. I need to solve this problem only in the native app,( i.e., only with UIWebView controller). Is it possible to solve this problem? Please support me on this. I have lot of issue like this when I show the Webpages in the UIWebView controller.
  • Kenneth Lewis said at 08/08, 2011
    How can you enable the popup when the very first page is the popup like for a wireless router like Netgear. The only way I am able to get past it is by adding authentication to the loadRequest:forHTTPHeaderField:@"Authentication" but then the wireless router uses frames and so nothing displays after that. Now when I enable popups for Safari itself in settings then the popup shows and Safari does handle the frames correctly so how can we get the same in UIWebView as Safari?

    Thanks,

    Kenneth
  • Android said at 09/22, 2015
    hello friends i have seen a good example ....

    http://androidexample.com/Show_Loader_To_Open_Url_In_WebView__-_Android_Example/index.php?view=article_discription&aid=125&aaid=145
  • Android Example said at 05/07, 2016
    Hi dude, i have also find out one good example
    <a href="http://androidexample.com/Show_Loader_To_Open_Url_In_WebView__-_Android_Example/index.php?view=article_discription&aid=125&aaid=145"> Show Loader To Open Url In WebView</a>
  • Android Example said at 09/22, 2016
    Hi dude, i have also find out one good example
    <a href="http://androidexample.com/Show_Loader_To_Open_Url_In_WebView__-_Android_Example/index.php?view=article_discription&aid=125&aaid=145">
    Show Loader To Open Url In WebView - Android Example</a>
  • Android Example said at 06/29, 2017

    Hi dude, i have also find out one good example
    <a href="http://androidexample.com/Show_Loader_To_Open_Url_In_WebView__-_Android_Example/index.php?view=article_discription&aid=125">
    Show Loader To Open Url In WebView </a>
Your name
Your email
(optional)
Your url
(optional)
Your comment