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?
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.
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.
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.
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...)
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;
}
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)
}
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With