Открыть цель = "_ пустые" ссылки вне UIWebView в Safari - PullRequest
20 голосов
/ 13 декабря 2011

Внутри моего iOS-приложения у меня есть UIWebView.

Теперь я хочу, чтобы все ссылки с атрибутом target = "_ blank" открывались не внутри моего WebView, а снаружи в Safari.

Как я могу это сделать?

Ответы [ 6 ]

37 голосов
/ 21 октября 2013

Мой ответ - ответ, который я нашел при переполнении стека для Android 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];
}

Это решает как проблему target = "_ blank", которая открывается в сафари, так и продолжает открывать стандартные ссылки в веб-просмотре.

4 голосов
/ 16 октября 2012

Проблема с решением wedo заключается в том, что все ваши ссылки будут открываться в Safari.

Два решения:

1 - обратный вызов JavaScript для Objective-Cкогда цель = "_ пусто" Чтобы решить вашу проблему, вам нужно добавить некоторые javascript во все ваши ссылки, проверить, имеют ли они атрибут _blank, затем перезвонить ваш код Objective-C из JavaScript и запустить:

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

Хороший (плохой?) Смысл этого решения заключается в том, что если ссылка на более глубоких уровнях все еще может открывать ссылки в браузере Safari

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

Всегда добавляйте протокол в URL (http, https ...)

3 голосов
/ 24 февраля 2013

Слава Мартину Магакяну!Вот модификация, основанная на предложении 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;
}
2 голосов
/ 18 июля 2019

На всякий случай, если кто-то ищет ответ в Swift4

Для внутренних загрузок убедитесь, что вы вызываете решение SolutionHandler () с помощью .cancel, чтобы загрузка прекратилась, а также вызываете 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)
}
0 голосов
/ 10 сентября 2017

У меня был тот же вопрос, и, к сожалению, эти ответы привлекли меня совершенно неправильно и очень сложно.На самом деле на этот вопрос отвечает так же просто, как «вам нужно использовать WebViewPolicyDelegateProtocol».

In -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

У меня естьиспользуется в моем проекте, где frameset используется в корневом HTML, загруженном в WebView.Все перекрестные ссылки, указывающие на другой существующий фрейм, не вызывают второй вызов сообщения, поэтому здесь обрабатываются только новые (внешние) цели.Это работает хорошо для меня.

0 голосов
/ 09 июля 2015

Я основал свой ответ на ответе Бенджамина Пиетта, но мне нужно было откорректировать сценарий, так как ссылки, которые должны быть скорректированы в моем случае, были сгенерированы асинхронно другим 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 /7963116/otkryt-tsel-pustye-ssylki-vne-uiwebview-v-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];
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...