UIWebViewNavigationTypeOther – Distinguishing Click Events that Come from JavaScript OnClick Handlers in UIWebViews

Problem Description

When you create hybrid apps, meaning you integrate HTML-pages into you native app via a web view and want to be in control of how click events are handled.

If you don’t use any JavaScript, distingushing between events is fairly easy. The UIWebViewDelegate has a callback method called

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

You can use the navigationType to see what kind of event triggered the request loading and decide if the web view should load it. If you’re looking for the values UIWebViewNavigationType can have, here they are:
enum {
UIWebViewNavigationTypeLinkClicked,
UIWebViewNavigationTypeFormSubmitted,
UIWebViewNavigationTypeBackForward,
UIWebViewNavigationTypeReload,
UIWebViewNavigationTypeFormResubmitted,
UIWebViewNavigationTypeOther
};
typedef NSUInteger UIWebViewNavigationType;

 

This should be more than enough if, as I said, you’re not using any JavaScript. If you are, things get tricky, because any JavaScript request always ends up being a request with a UIWebViewNavigationTypeOther.
Having advertisements on a website for instance, combined with scripts for sharing buttons as well as some kind of Google Analytics tracking code on a mobile-optimized web page and this web page being integrated in your native app. You will get UIWebViewNavigationTypeOther when the sharing button scripts make calls to display the number of shares, as well as when analytics code is integrated into the page, as well as when advertisement banners are placed into the page. You will also get UIWebViewNavigationTypeOther when the user clicks advertisement banners that use JavaScipt for intercepting and handling user clicks.

So how do you distinguish the click from all the other stuff? At a first glance, you really can’t tell. Assume you want to have some specific behavior when the ads ads are being clicked, like opening them in Safari or an in-app browser. In this case, you should return NO to the delegate callback, so that the current web view doesn’t handle the request itself, but you handle it, e.g. by pushing a new UIViewController with the in-app browser. In order to return no, you need to make sure you’re not hindering the web view from loading other JS stuff, like the sharing buttons.

 

The Solution

You can distinguish these calls by looking more deeply at the NSURLRequest object that is passed to you in the same delegate method.

NSURLRequest has two  important properties: documentURL and URL. Depending on what kind of JS call is performed, these properties will look differently.

– If you have a JS call that loads a new page (which means the user clicked on an ad banner in our case) documentURL and URL will be identical.
– If for instance facebook or twitter are doing stuff with their buttons, the documentURL will be host URL of your web page (e.g. http://www.iriphon.com) and the URL property will point to some kind of facebook or twitter related URL.

In conclusion, have your app at hand in the simulator, print out those properties on the console and look what happens – you may find out a lot of other useful things! :-)