wake-up-neo.com

Öffnen Sie target = "_ blank" -Links außerhalb von UIWebView in Safari

In meiner iOS-Anwendung habe ich eine UIWebView. 

Nun möchte ich, dass alle Links, die das Attribut target = "_ blank" haben, nicht in meinem WebView, sondern extern in Safari geöffnet werden. 

Wie kann ich das machen?

19
Norwald2

Meine Antwort, eine Antwort, die ich im Stack-Überlauf für Android WebView gefunden habe. Aber eigentlich haben beide Webview das gleiche Problem und die gleiche (schmutzige) Korrektur:

- (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];
}

Dadurch wird sowohl das Problem target = "_ blank" gelöst, als auch in Safari geöffnet, UND es werden weiterhin Standardlinks in der Webansicht geöffnet.

35
Benjamin Piette

Das Problem mit der Lösung von wedo ist, dass alle Ihre Links in Safari geöffnet werden.

Zwei Lösungen:

1 - JavaScript-Rückruf an Objective-C, wenn target = "_ blank"
Um Ihr Problem zu lösen, müssen Sie Javascript für alle Ihre Links hinzufügen. Überprüfen Sie, ob sie das Attribut _blank haben. Rufen Sie dann Ihren Objective-C-Code aus JavaScript ab und führen Sie Folgendes aus:

[[UIApplication sharedApplication] openURL:myUrl];

Ich persönlich mag diese Lösung nicht, weil sie viel Code, Callback, Komplexität und ein bisschen knifflig ist ...

2 - URL-Parameter überprüfen
Wenn Sie Zugriff auf den HTML-Code haben (beachten Sie, dass Sie in beiden Lösungen Zugriff auf HTML benötigen), empfehle ich, dass Sie das target = "_ blank" entfernen und den Parameter? OpenInSafari = true hinzufügen

Fügen Sie im UIWebViewDelegate den folgenden Code hinzu:

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

Ein netter (schlechter?) Punkt bei dieser Lösung ist, dass bei tieferen Linkebenen noch Links in den Safari-Browser geöffnet werden können 

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


Fügen Sie das Protokoll immer in die URL ein (http, https ...)

4
Martin Magakian

Kudos an Martin Magakian! Hier ist die Modifikation basierend auf dem Vorschlag von 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
mpemburn

Nur für den Fall, dass jemand in Swift4 nach einer Antwort sucht

Stellen Sie bei internen Ladevorgängen sicher, dass Sie den Closure-Befehl decisionHandler () mit .cancel aufrufen, damit der Ladevorgang angehalten wird, und rufen Sie UIApplication.shared.open () auf, um die URL im externen Browser zu öffnen.

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)
}
2
Sujay Patil

Ich hatte die gleiche Frage und leider haben mich diese Antworten völlig falsch und sehr komplex gezeichnet. Die Frage wird wirklich so einfach wie "Sie müssen WebViewPolicyDelegateProtocol verwenden" beantwortet.

In -viewDidLoad der View Controller-Implementierung, die Sie schreiben:

[myWebView setPolicyDelegate:self];

In Ihrer View Controller-Klassenschnittstelle müssen Sie zwei Elemente hinzufügen:

- (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;

Und implementiere sie so einfach wie:

- (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];
    }
}

Siehe auch die Apple-Dokumente

Ich habe diese Methode in meinem Projekt verwendet, bei dem Frameset im Stamm-HTML verwendet und in die WebView geladen wird. Alle Querverweise, die auf einen anderen vorhandenen Frame verweisen, verursachen nicht den zweiten Nachrichtenaufruf, daher werden hier nur neue (externe) Ziele verarbeitet. Es funktioniert OK für mich. 

0
DeadlineX

Ich habe meine Antwort auf die von Benjamin Piette gestützt, musste aber das Skript anpassen, da die in meinem Fall einzustellenden Links asynchron von einem anderen Javascript generiert wurden.

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];
}
0
clauswey