public
Last active

ON PhoneGap-iOS, open external links in the external browser (Safari.app)

  • Download Gist
projectAppDelegate.m
Objective-C
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
/**
* Note: the following function should already exist in your application delegate file.
* Replace it with the following implementation.
*
* Thanks to @purplecabbage for implementation.
* Thanks to Ruddiger for the iFrame patch.
*/
 
// ...
 
/**
* Start Loading Request
* This is where most of the magic happens... We take the request(s) and process the response.
* From here we can re direct links and other protocalls to different internal methods.
*/
- (BOOL)webView:(UIWebView *)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = [request URL];
// Intercept the external http requests and forward to Safari.app
// Otherwise forward to the PhoneGap WebView
// Avoid opening iFrame URLs in Safari by inspecting the `navigationType`
if (navigationType == UIWebViewNavigationTypeLinkClicked && [[url scheme] isEqualToString:@"http"] || [[url scheme] isEqualToString:@"https"]) {
[[UIApplication sharedApplication] openURL:url];
return NO;
}
else {
return [ super webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType ];
}
}

Thanks for the tip!

Seems to me that the else enclosure is not needed since the if has a return in it.

Thanks.

You're certainly right, the else isn't required, but it does make the logic a little more explicit (to me). I'm not much of an objective-c developer, so I'm not sure what the expected convention would be.

Sorry I have no Idea of Objective-C, but is it possible to verify if the url is in the whitelist? I would like to open all not whitelisted URLs in external Safari

You can add URL schemes "mailto" and "tel" as well. That way , if you have < a href=" mailto:a@b.com" > or < a href="tel:1234" >call me</ a>, they open email client and telephone app respectively.

One issue with this fix is that iframes will also open in external Safari. Here is a solution (works with 1.4.1):

/**

  • Start Loading Request
  • This is where most of the magic happens... We take the request(s) and process the response.
  • From here we can re direct links and other protocalls to different internal methods. */
  • (BOOL)webView:(UIWebView *)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
    NSURL *url = [request URL];

    if(navigationType == UIWebViewNavigationTypeLinkClicked && ([[url scheme] isEqualToString:@"http"] || [[url scheme] isEqualToString:@"https"])){
    [[UIApplication sharedApplication] openURL:url];
    return NO;
    }
    else {
    return [self.viewController webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType];
    }
    }

Nice, thanks @Ruddiger!

update - with this code you can create a iframe with inside and external links.
you need inside links? add a relative url -> test.php
you need external links? add a absolute url with http: or https and #external

  • (BOOL)webView:(UIWebView *)theWebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
    NSURL *url = [request URL];

    // Intercept the external http requests and forward to Safari.app
    // Otherwise forward to the PhoneGap WebView
    // Avoid opening iFrame URLs in Safari by inspecting the navigationType
    if (navigationType == UIWebViewNavigationTypeLinkClicked && [[url scheme] isEqualToString:@"#external"] && [[url scheme] isEqualToString:@"http"] || [[url scheme] isEqualToString:@"https"]) {
    [[UIApplication sharedApplication] openURL:url];
    return NO;
    }
    else {
    return [ super webView:theWebView shouldStartLoadWithRequest:request navigationType:navigationType ];
    }
    }

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.