Подтвердить что ты не робот

Открытые целевые = "_ пустые" ссылки за пределами UIWebView в Safari

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

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

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

4b9b3361

Ответ 1

Мой ответ, который является ответом, который я обнаружил при переполнении стека для 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 "для открытия в сафари, и продолжает открывать стандартные ссылки в веб-просмотре.

Ответ 2

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

Два решения:

1 - обратный вызов JavaScript на Objective-C, когда target = "_ blank"
Чтобы решить проблему, вам нужно добавить 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;
}

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

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


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

Ответ 3

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

Ответ 4

Я основал свой ответ на одном из Benjamin Piette, но мне нужно было настроить script, поскольку ссылки, которые нужно отрегулировать в моем случае, были сгенерированы асинхронно другим 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];
}

Ответ 5

У меня был тот же вопрос, и, к сожалению, эти ответы привели меня к совершенно неправильному и очень сложному пути. На самом деле вопрос отвечает так же просто, как "вам нужно использовать 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 docs

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

Ответ 6

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

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