在我的iOS应用程序中,我有一个UIWebView。
现在我希望所有具有属性target =“_ blank”的链接不在我的WebView中打开,而是在Safari中外部打开。
我该怎么做?
答案 0 :(得分:36)
我的回答,这是我在Android WebView的堆栈溢出中找到的答案。但实际上,两个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”问题,并且在webview中保持打开标准链接。
答案 1 :(得分:4)
wedo解决方案的问题是,所有链接将在Safari中打开。
两种解决方案:
1 - 当target =“_ blank”时,JavaScript回调到Objective-C 要解决您的问题,您需要在所有链接上添加一些javascript,检查它们是否具有_blank属性,然后从JavaScript回调您的Objective-C代码并运行:
[[UIApplication sharedApplication] openURL:myUrl];
我个人不喜欢这个解决方案,因为它有很多代码,回调,复杂性和有点棘手......
2 - 检查网址参数
如果您有权访问HTML代码(在两个解决方案中都需要访问HTML),我建议您删除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;
}
这个解决方案的好处(不好?)点是,如果链接x级别更深,仍然可以打开到safari浏览器的链接
<a href="http://www.google.com?openInSafari=true">Google in Safari</a>
始终在网址(http,https ...)
答案 2 :(得分:3)
感谢Martin Magakian!以下是基于spankmaster79建议的修改:
- (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;
}
答案 3 :(得分:2)
以防万一有人在Swift4中寻找答案
对于内部加载,请确保使用.cancel调用DecisionHandler()关闭,以便加载停止,同时还要调用UIApplication.shared.open()以在外部浏览器中打开URL。
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)
}
答案 4 :(得分:1)
尝试一下。
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);
答案 5 :(得分:0)
我的答案基于Benjamin Piette的答案,但需要调整脚本,因为在我的情况下要调整的链接是由其他javascript异步生成的。
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];
}
答案 6 :(得分:0)
我有同样的问题,不幸的是这些答案让我感到非常错误和非常复杂。实际上这个问题的回答简直就是&#34;你需要使用WebViewPolicyDelegateProtocol&#34;。
在您编写的视图控制器实现的-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 docs
我在我的项目中使用过这种方式,其中frameset在根HTML中使用,加载到WebView中。指向另一个现有帧的所有交叉链接都不会导致第二个消息调用,因此此处仅处理新的(外部)目标。它适用于我。