Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Open target="_blank" links outside of UIWebView in Safari

Inside my iOS Application I have an UIWebView.

Now I want all links that have the attribute target="_blank" not to open inside my WebView but externally in Safari.

How can I do this?

like image 396
Norwald2 Avatar asked Dec 13 '11 13:12

Norwald2


People also ask

Why is WKWebView not opening links with target _blank?

The culprit is HTML attribute target set to value _blank which is used to signal links that should be opened in new tab instead of the current one. This target setting is meant to tell the browser (which is WKWebView in this case) that this link should be open in new tab by default. Which is the root of the problem.

How do you write a target blank in Javascript?

The HTML target attribute defines where the linked document will open when the user clicked on the link. If target=”_blank” is set with anchor element, then the linked document will open in a new tab otherwise document is open in the same tab.


5 Answers

My answer, which is a from an answer I found on stack overflow for the Android WebView. But actually, both webview have the same problem and same (dirty) fix:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request     navigationType:(UIWebViewNavigationType)navigationType
{
    if ([request.URL.absoluteString hasPrefix:@"newtab:"])
    {
        // JS-hacked URl is a target=_blank url - manually open the browser.
        NSURL *url = [NSURL URLWithString:[request.URL.absoluteString substringFromIndex:7]];
        [[UIApplication sharedApplication] openURL:url];

        return true;
    }

    return true;
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    // JS Injection hack to solve the target="_blank" issue and open a real browser in such case.
    NSString *JSInjection = @"javascript: var allLinks = document.getElementsByTagName('a'); if (allLinks) {var i;for (i=0; i<allLinks.length; i++) {var link = allLinks[i];var target = link.getAttribute('target'); if (target && target == '_blank') {link.setAttribute('target','_self');link.href = 'newtab:'+link.href;}}}";
    [webView stringByEvaluatingJavaScriptFromString:JSInjection];
}

This solves both the target="_blank" issue to open in safari, AND keeps opening standard links within the webview.

like image 51
Benjamin Piette Avatar answered Oct 21 '22 00:10

Benjamin Piette


The problem with wedo's solution is that all your links will open in Safari.

Two solutions:

1 - JavaScript callback to Objective-C when target="_blank"
To achieve your problem you need to add some javascript on all your links, check if they have the attribute _blank, then call back your objective-C code from JavaScript and run:

[[UIApplication sharedApplication] openURL:myUrl];

I personally don't like this solution because it's a lot of code, callback, complexity and a bit tricky...

2 - Checking url parameter
If you have access to the HTML code (note in both solution you need access to HTML) I recommend you remove the target="_blank" and add the parameter ?openInSafari=true

In the UIWebViewDelegate add the following code:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
        NSURL *url = [request URL];
        NSDictionary *param = [url queryParameters];
        NSString *openIsSafari = [param objectForKey:@"openInSafari"];

        if ( openIsSafari!= nil && ([openIsSafari isEqualToString:@"true"] ||  [openIsSafari isEqualToString:@"1"])){
            [[UIApplication sharedApplication] openURL:url];
            return NO;
        }
    }
    return YES;
}

A nice (bad?) point with this solution is that if the link x levels deeper can still open links into safari browser

<a href="http://www.google.com?openInSafari=true">Google in Safari</a>


Always add the protocol in the URL (http, https...)

like image 35
Martin Magakian Avatar answered Oct 21 '22 00:10

Martin Magakian


Kudos to Martin Magakian! Here is the modification based on spankmaster79's suggestion:

- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest: (NSURLRequest *)request navigationType: (UIWebViewNavigationType)navigationType {
    if (navigationType == UIWebViewNavigationTypeLinkClicked) {
        NSURL *url = [request URL];
        NSString *param = [url query];

        if ([param rangeOfString: @"openInSafari=true"].location != NSNotFound){
            [[UIApplication sharedApplication] openURL: url];
            return NO;
        }
    }
    return YES;
}
like image 36
mpemburn Avatar answered Oct 21 '22 00:10

mpemburn


Just in case if some one is looking for answer in Swift4

For internal loads make sure you call the decisionHandler() closure with .cancel so the load halts, while also calling UIApplication.shared.open() to have the URL open in the external browser.

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    if let url = navigationAction.request.url {
        if url.host == "your url.com" {
            UIApplication.shared.open(url)
            decisionHandler(.cancel)
            return
        }
    }

    decisionHandler(.allow)
}
like image 2
Sujay Patil Avatar answered Oct 21 '22 02:10

Sujay Patil


Try this.

UIApplication *app = [UIApplication sharedApplication];
NSURL         *url = navigationAction.request.URL;

if (!navigationAction.targetFrame) {
    if ([app canOpenURL:url]) {
        [app openURL:url];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
}
if ([url.scheme isEqualToString:@"mailto"])
{
    if ([app canOpenURL:url])
    {
        [app openURL:url];
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
}

decisionHandler(WKNavigationActionPolicyAllow);
like image 1
Sujith Sreedhar Avatar answered Oct 21 '22 02:10

Sujith Sreedhar