iOS WebView技术问题:target="_blank"链接需在Safari打开,现有代码异常
问题分析与解决方案
首先,咱们来拆解下你遇到的核心问题:原本想让带?openInSafari=true的链接和target="_blank"的链接跳去Safari,结果普通链接全跑去Safari了,反而PDF下载链接留在WebView里——这明显是代码逻辑的判断范围和条件搞反/不全导致的。
你的代码为什么失效?
先看你贴的代码逻辑:
- (BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest: (NSURLRequest *)request navigationType: (UIWebViewNavigationType)navigationType { if (navigationType == UIWebViewNavigationTypeLinkClicked) { NSURL *url = [request URL]; NSString *string = [url query]; if ([string rangeOfString: @"openInSafari=true"].location != NSNotFound){ [[UIApplication sharedApplication] openURL: url]; NSLog(@"Open in Safari"); return NO; } } NSLog(@"Open in WebView"); return YES; }
这里有三个致命问题:
- NavigationType判断太窄:
UIWebViewNavigationTypeLinkClicked只覆盖了用户直接点击普通链接的场景,target="_blank"的链接触发的是UIWebViewNavigationTypeOther(因为WebView要开新窗口),所以你的代码根本没拦截到这类链接,这也是你最初找的方案失效的原因。 - PDF等下载链接没处理:你的代码只判断了
openInSafari=true参数,完全没考虑文件类型,所以带下载参数的PDF链接会直接在WebView里打开。 - 测试日志暴露逻辑矛盾:从你给出的日志来看,普通链接显示
Open in Safari (null),说明你的代码实际可能把条件写反了(比如写成了== NSNotFound),导致没有openInSafari=true参数的链接反而跳去Safari,完全违背了你的需求。
修正后的完整代码
下面的代码会同时处理target="_blank"链接、openInSafari=true参数链接,以及PDF等可下载文件,完全贴合你的需求:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSURL *url = request.URL; NSString *urlString = url.absoluteString; NSString *query = url.query; // 标记是否需要在Safari打开 BOOL shouldOpenInSafari = NO; // 条件1:带有openInSafari=true参数的链接 if (query && [query rangeOfString:@"openInSafari=true"].location != NSNotFound) { shouldOpenInSafari = YES; } // 条件2:处理target="_blank"的链接(WebView点击这类链接会触发Other类型导航) if (navigationType == UIWebViewNavigationTypeOther && ![webView.request.URL.absoluteString isEqualToString:urlString]) { shouldOpenInSafari = YES; } // 条件3:PDF等可下载文件(可根据需求扩展后缀) NSArray *downloadableExtensions = @[@"pdf", @"zip", @"doc", @"docx", @"xls", @"xlsx"]; NSString *fileExtension = url.pathExtension.lowercaseString; if ([downloadableExtensions containsObject:fileExtension]) { shouldOpenInSafari = YES; } if (shouldOpenInSafari) { [[UIApplication sharedApplication] openURL:url]; NSLog(@"Open in Safari: %@", urlString); return NO; // 阻止WebView加载,交给Safari处理 } // 其他所有情况都在WebView内打开 NSLog(@"Open in WebView: %@", urlString); return YES; }
额外优化:精准拦截target="_blank"链接
如果想更精准地捕获target="_blank"的链接(避免误判Other类型导航),可以在WebView加载完成后注入JavaScript来拦截点击事件:
- (void)webViewDidFinishLoad:(UIWebView *)webView { // 注入JS拦截所有_blank链接的点击 NSString *interceptBlankLinkJS = @"document.addEventListener('click', function(e) { \ var target = e.target; \ while (target && target.tagName !== 'A') { target = target.parentNode; } \ if (target && target.target === '_blank') { \ e.preventDefault(); \ window.location.href = 'safari://' + target.href; \ } \ }, false);"; [webView stringByEvaluatingJavaScriptFromString:interceptBlankLinkJS]; }
然后在shouldStartLoadWithRequest里添加拦截逻辑:
// 拦截我们自定义的safari://协议 if ([urlString hasPrefix:@"safari://"]) { NSString *actualURL = [urlString substringFromIndex:8]; [[UIApplication sharedApplication] openURL:[NSURL URLWithString:actualURL]]; return NO; }
这样就能100%精准捕获所有target="_blank"的链接了。
内容的提问来源于stack exchange,提问作者Zilant
相关产品推荐
相关产品推荐

