1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | [code language="c"] - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if(navigationType == UIWebViewNavigationTypeLinkClicked || navigationType == UIWebViewNavigationTypeFormSubmitted) { [self pushFrontWithURL:[request URL]]; //this will make a new webview and push it on our navigation controller return NO; } return YES; } [/code] |
That’s fine for regular links and forms, but as soon as you hook up some javascript to your a- tags
1 2 3 4 5 | [code language="html"] <a href="http://www.vg.no/test" onclick="myJsFunc();"> Run JavaScript Code </a> [/code] |
they will be ignorered by our code.
The problem is the navigationType, which has 6 possible values:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [code language="c"] typedef NS_ENUM(NSInteger, UIWebViewNavigationType) { UIWebViewNavigationTypeLinkClicked, UIWebViewNavigationTypeFormSubmitted, UIWebViewNavigationTypeBackForward, UIWebViewNavigationTypeReload, UIWebViewNavigationTypeFormResubmitted, UIWebViewNavigationTypeOther }; [/code] |
When javascript is attached to a link, the navigationType will no longer be reported as UIWebViewNavigationTypeLinkClicked – you will get a UIWebViewNavigationTypeOther instead. So we’ll just check for that! Unfortunately it’s not that easy. Every page load and iframe in your page will trigger this action as well.. How can we separate the javascript-bound links and a regular page load ?
NSURLRequest to the rescue
There are a couple of methods in NSURLRequest which might seems irrelevant at first, but we’ll use them to serve our purpose.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | [code language="c"] /*! @method URL @abstract Returns the URL of the receiver. @result The URL of the receiver. */ - (NSURL *)URL; /*! @method mainDocumentURL @abstract The main document URL associated with this load. @discussion This URL is used for the cookie "same domain as main document" policy. There may also be other future uses. @result The main document URL. */ - (NSURL *)mainDocumentURL; [/code] |
All iframes loading will have their URL pointing to a specific address, but the mainDocumentURL will still name our original document, in other words, they differ. But what happens when we click on our javascripted links ? The URL and mainDocumentURL will be the same, if they link to a new page. And that’s exactly what we’re interested in. The only problem that remains is the first page load, which happens to follow the same pattern. There are several ways to work around that, but one quick and easy solution is to check for the inital URL and handle that as a special case. Wrapping it all up you can try something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | [code language="c"] - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString* url = [[request URL] absoluteString]; //first page load, don't move away if( [url isEqualToString:self.frontpageUrlString] ) { return YES; } if(navigationType == UIWebViewNavigationTypeLinkClicked || navigationType == UIWebViewNavigationTypeFormSubmitted) { [self pushFrontWithURL:url]; //this will make a new webview and push it on our navigation controller return NO; } //push our own javascript-triggered links as well else if(navigationType == UIWebViewNavigationTypeOther) { NSString* documentURL = [[request mainDocumentURL] absoluteString]; if( [url isEqualToString:documentURL]) { //if they are the same this is a javascript href click [self pushFrontWithLink:url]; return NO; } } return YES; } [/code] |
You still might want to check for other URLs, such as links to Appstore and other apps and let iOS handle those, but your javascript links should now behave nicely. Happy hybrid coding!