在Safari中的UIWebView之外打开target =“_ blank”链接

在我的iOS应用程序里面我有一个UIWebView。

现在我想要所有具有属性target =“_ blank”的链接不在我的WebView内部打开,而是在Safari外部打开。

我怎样才能做到这一点?

我的答案,这是从Android WebView的堆栈溢出中find的答案。 但实际上,两个webview都有相同的问题和相同的(脏)修复:

- (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]; } 

这解决了在Safari浏览器中打开的target =“_ blank”问题,并且不断在web视图中打开标准链接。

wedo的解决scheme的问题是, 所有的链接将在Safari中打开。

两种解决scheme

1 – 当target =“_ blank”时,JavaScriptcallback到Objective-C
为了实现你的问题,你需要在你的所有链接上添加一些javascript,检查它们是否具有属性_blank,然后从JavaScriptcallback你的Objective-C代码并运行:

 [[UIApplication sharedApplication] openURL:myUrl]; 

我个人不喜欢这个解决scheme,因为它有很多的代码,callback,复杂性和有点棘手…

2 – 检查url参数
如果您有权访问HTML代码(注意在这两种解决scheme中都需要访问HTML),我build议您删除target =“_ blank”并添加参数?openInSafari = true

在UIWebViewDelegate中添加下面的代码:

 -(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; } 

这个解决scheme的一个不错的(坏的)点是,如果更深的链接x级别仍然可以打开链接到Safari浏览器

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

始终在URL中添加协议(http,https …)

荣誉马丁马加基安! 这是基于spankmaster79的build议的修改:

 - (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; } 

我根据我本人的答案来自本杰明皮耶特,但需要调整脚本,因为在我的情况下调整的链接是由其他JavaScriptasynchronous生成的。

 NSString* const kOpenInNewTabPrefix = @"myOpenInNewTabPrefix:";//This NEEDS to end with ':' - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { if ([[request.URL.absoluteString lowercaseString] hasPrefix:[kOpenInNewTabPrefix lowercaseString]]) { // JS-hacked URl is a target=_blank url - manually open the browser. NSURL *url = [NSURL URLWithString:[request.URL.absoluteString substringFromIndex:[kOpenInNewTabPrefix length]]]; [[UIApplication sharedApplication] openURL:url]; return YES; } return YES; } - (void)webViewDidFinishLoad:(UIWebView *)webView { //based on http://stackoverflow.com/questions/8490038/open-target-blank-links-outside-of-uiwebview-in-safari // JS Injection hack to solve the target="_blank" issue and open a real browser in such case. NSString *JSInjection = [NSString stringWithFormat:@"javascript: " "document.getElementsByTagName('body')[0].addEventListener('click', function(e){" " var a = e.target;" " if(a.nodeName != 'A'){" " return;" " }" " var target = a.target;" " var href = a.href;" " var prefix = '%@';" " if(href.substring(0, %lu) != '%@' && target == '_blank'){" " a.href = prefix + href;" " }" "})" , [kOpenInNewTabPrefix lowercaseString] , (unsigned long)[kOpenInNewTabPrefix length] , [kOpenInNewTabPrefix lowercaseString]]; [webView stringByEvaluatingJavaScriptFromString:JSInjection]; } 

我有同样的问题,不幸的是,这些答案使我完全错误和非常复杂的方式。 真的这个问题的答案就像“你需要使用WebViewPolicyDelegateProtocol”。

在您编写的视图控制器实现的-viewDidLoad中:

 [myWebView setPolicyDelegate:self]; 

在你的视图控制器类的界面你必须添加两个项目:

 - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener; - (void)webView:(WebView *)webView decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id<WebPolicyDecisionListener>)listener; 

并且实现它们像下面这样简单:

 - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener { // just the default behavior, though you're free to add any url filtering you like... [listener use]; } - (void)webView:(WebView *)webView decidePolicyForNewWindowAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request newFrameName:(NSString *)frameName decisionListener:(id<WebPolicyDecisionListener>)listener { // frameName is your "target" parameter value if([frameName isEqualToString:@"_blank"]) { [[NSWorkSpace sharedWorkSpace] loadURL:[request URL]]; } else { [listener use]; } } 

另请参阅Apple文档

我在我的项目中使用了这种方式,在根HTML中使用frameset,并将其加载到WebView中。 指向另一个现有帧的所有交叉链接不会导致第二个消息调用,因此这里只处理新的(外部)目标。 它对我来说工作正常。