[英]Open target=“_blank” links outside of UIWebView in Safari
在我的 iOS 應用程序中,我有一個 UIWebView。
現在我希望所有具有屬性 target="_blank" 的鏈接不要在我的 WebView 內部打開,而是在 Safari 外部打開。
我怎樣才能做到這一點?
我的答案來自我在 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 中打開標准鏈接的問題。
wedo 解決方案的問題是您的所有鏈接都將在 Safari 中打開。
兩種解決方案:
1 - 當 target="_blank" 時 JavaScript 回調到 Objective-C
要解決您的問題,您需要在所有鏈接上添加一些 javascript,檢查它們是否具有 _blank 屬性,然后從 JavaScript 回調您的 Objective-C 代碼並運行:
[[UIApplication sharedApplication] openURL:myUrl];
我個人不喜歡這個解決方案,因為它有很多代碼、回調、復雜性和有點棘手......
2 - 檢查 url 參數
如果您有權訪問 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>
始終在 URL 中添加協議(http、https...)
向馬丁·馬加基安致敬! 這是基於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;
}
以防萬一有人在 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)
}
試試這個。
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);
我的答案基於 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];
}
我有同樣的問題,不幸的是,這些答案以一種完全錯誤且非常復雜的方式吸引了我。 實際上,這個問題的回答就像“您需要使用 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 中使用,加載到 WebView 中。 指向另一個現有框架的所有交叉鏈接不會導致第二個消息調用,因此這里只處理新的(外部)目標。 它對我有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.