42

I have a UIWebView embedded within an iPhone app of mine. I want to be able to have certain links within that webview open into the full Mobile Safari app (i.e. not my embedded version of it).

Is there a simple way to structure some of my hrefs to force this, instead of every link opening within my embedded webview?

Thanks.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
tbacos
  • 733
  • 2
  • 7
  • 12
  • [http://stackoverflow.com/questions/4452719/how-do-i-open-links-in-safari-instead-of-uiwebview/12103579#12103579][1] [1]: http://stackoverflow.com/questions/4452719/how-do-i-open-links-in-safari-instead-of-uiwebview/12103579#12103579 – Rajesh_Bangalore Aug 24 '12 at 05:41

5 Answers5

60

To expand upon what Randy said, this is what I use in my application to make every http://, https://, and mailto:// URL open in the external Safari or Mail applications:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType; 
{
    NSURL *requestURL =[ [ request URL ] retain ]; 
    if ( ( [ [ requestURL scheme ] isEqualToString: @"http" ] || [ [ requestURL scheme ] isEqualToString: @"https" ] || [ [ requestURL scheme ] isEqualToString: @"mailto" ]) 
        && ( navigationType == UIWebViewNavigationTypeLinkClicked ) ) { 
        return ![ [ UIApplication sharedApplication ] openURL: [ requestURL autorelease ] ]; 
    } 
    [ requestURL release ]; 
    return YES; 
}

As Randy says, you'll want to implement this within whatever class you set to be the delegate of the UIWebView. To have only select URLs launch Safari, you could change their scheme from http:// to safari://, or something similar, and only kick those URLs off to the system (after replacing the custom URL scheme with http://).

I do this within my internal help documentation, which is HTML displayed in a UIWebView, so that I don't run into issues in the review process with having a general-purpose web browser embedded in my application.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • Isn't retaining and releasing the URL really paranoid? – morningstar Oct 21 '11 at 01:31
  • @morningstar - Perhaps, and it is obsolete with ARC now, but at the time I was struggling with threading-related crashes in other places (autoreleased objects that were passed into methods on different threads being deallocated in the middle of that method), so I erred on the side of being paranoid. Again, this is done for you now by ARC, so my code no longer has this in it. – Brad Larson Oct 21 '11 at 14:26
  • Yes, okay, I can see how it might be necessary because of threading issues. – morningstar Oct 21 '11 at 15:16
  • How can I make this work with #links? At present they are also opening in Safari? Thanks – Phil Hudson Sep 11 '12 at 12:58
20

Ok I got it. Maybe its not the perfect solution, but you can do it like this:

Only in your WebViewController.m:

add the line webView.delegate = self; to the viewDidLoad procedure:

- (void)viewDidLoad {
    webView.delegate = self;
    .... your code ....
}

Then you can add as described above somewhere in the Controller.m File following boolean resulting function:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
        [[UIApplication sharedApplication] openURL:request.URL];
        return false;
    }
    return true;
}
splattne
  • 102,760
  • 52
  • 202
  • 249
aqm
  • 201
  • 2
  • 3
12

I haven't tried this myself but I think that you can implement the UIWebViewDelegate method

webView:shouldStartLoadWithRequest:navigationType 

which will be called anytime a link in the UIWebView is clicked on. In that method you just need to determine if the clicked link should result in launching Safari or not and use openURL if it should.

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

    // Check if this was a click event and then some other criteria for determining if you want to launch Safari.
    if (navigationType == UIWebViewNavigationTypeLinkClicked && [Some other criteria]) {
        [[UIApplication sharedApplication] openURL:request.URL];

        // Return false to indicate to the UIWebView to not navigate to the linked target
        return false;
    }

    // Return true so that the UIWebView loads the link target
    return true;
}

Don't forget that you need to set your UIWebView delegate property to an instance of the class that implements the UIWebViewDelegate.

WrightsCS
  • 50,551
  • 22
  • 134
  • 186
Randy Simon
  • 3,324
  • 21
  • 19
1

This is how we solved it, add this to your ViewController.m file:

    - (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    first.delegate = (id)self;
                [first loadRequest:[NSURLRequest requestWithURL:[NSURL     URLWithString:@"http://my.FellowshipNWA.org?publicapp"]]];
}

// Add section below so that external links & PDFs will open in Safari.app
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request     navigationType:(UIWebViewNavigationType)navigationType {
    if (navigationType == UIWebViewNavigationTypeOther) {
        NSString *checkURL = @"http://my.fellowshipnwa.org/?givenowsafari";
        NSString *reqURL = request.URL.absoluteString;
        if ([reqURL isEqualToString:checkURL])
             {
                 [[UIApplication sharedApplication] openURL:request.URL];
            return false;
    }
        else {
            return true;
        }
    }
    return true;
}
Dwight Mix
  • 11
  • 1
1

Swift version of Brad Larson's answer:

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {

    var url: NSURL = request.URL!
    var isExternalLink: Bool = url.scheme == "http" || url.scheme == "https" || url.scheme == "mailto"
    if (isExternalLink && navigationType == UIWebViewNavigationType.LinkClicked) {
        return !UIApplication.sharedApplication().openURL(request.URL!)
    } else {
        return true
    }
}
Carl Sharman
  • 4,435
  • 1
  • 30
  • 29