UIWebView öffnet Links in Safari

304

Ich habe eine sehr einfache UIWebView mit Inhalten aus meinem Anwendungspaket. Ich möchte, dass alle Links in der Webansicht in Safari anstatt in der Webansicht geöffnet werden. Ist das möglich?

David Beck
quelle
Die unten akzeptierte Antwort funktioniert nicht in allen Fällen.
IanS
Ich habe eine bessere Antwort hinzugefügt. Bitte markieren Sie meine Antwort als akzeptiert.
IanS

Antworten:

657

Fügen Sie dies dem UIWebView-Delegaten hinzu:

(bearbeitet, um nach dem Navigationstyp zu suchen. Sie können auch file://Anfragen weiterleiten, die relative Links sind.)

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    if (navigationType == UIWebViewNavigationTypeLinkClicked ) {
        [[UIApplication sharedApplication] openURL:[request URL]];
        return NO;
    }

    return YES;
}

Schnelle Version:

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
        if navigationType == UIWebViewNavigationType.LinkClicked {
            UIApplication.sharedApplication().openURL(request.URL!)
            return false
        }
        return true
    }

Swift 3 Version:

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool {
    if navigationType == UIWebViewNavigationType.linkClicked {
        UIApplication.shared.openURL(request.url!)
        return false
    }
    return true
}

Swift 4 Version:

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
    guard let url = request.url, navigationType == .linkClicked else { return true }
    UIApplication.shared.open(url, options: [:], completionHandler: nil)
    return false
}

Aktualisieren

Wie openURLin iOS 10 veraltet:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
        if (navigationType == UIWebViewNavigationTypeLinkClicked ) {
            UIApplication *application = [UIApplication sharedApplication];
            [application openURL:[request URL] options:@{} completionHandler:nil];
            return NO;
        }

        return YES;
}
nach vorne gezogen
quelle
Würde es Ihnen etwas ausmachen, Ihre Antwort unter Bezugnahme auf die Antwort und die Kommentare unten zu aktualisieren?
Toby Allen
Wie kann ich zur Anwendung zurückkehren, wenn der Benutzer den Browser schließt?
Johnny Everson
3
@ Jhonny Everson: Sie haben keine Kontrolle darüber, was passiert, nachdem eine externe App (einschließlich Safari) geschlossen wurde. Wenn Sie nach dem Surfen wieder zu Ihrer App zurückkehren möchten, öffnen Sie Safari nicht, sondern verwenden Sie einfach die UIWwbView und die Schaltfläche "Fertig".
Geon
1
Arbeitete wie ein Zauber mit lokaler HTML-Datei.
Necixy
1
Ich denke, in Swift ist a switchfür Aufzählungstypen vorzuziehen
SDJMcHattie
44

Wenn sich jemand wundert, würde Drawnonwards Lösung in Swift so aussehen :

func webView(webView: UIWebView!, shouldStartLoadWithRequest request: NSURLRequest!, navigationType: UIWebViewNavigationType) -> Bool {
    if navigationType == UIWebViewNavigationType.LinkClicked {
        UIApplication.sharedApplication().openURL(request.URL)
        return false
    }
    return true
}
DiegoFrings
quelle
Irgendeine Idee, wie man das NUR mit URLs macht, die https: // http: // oder mailto: haben? mit Swift? Frage hier braucht eine schnelle Antwort! stackoverflow.com/questions/2532453/…
Jed Grant
@JedGrant schnelle Version jetzt auf stackoverflow.com/questions/2532453/…
Carl Sharman
2
Stellen Sie sicher, dass SieUIWebViewDelegate
Jay Mayu
28

Ein kurzer Kommentar zur Antwort von user306253: Vorsicht, wenn Sie versuchen, etwas in die UIWebView selbst zu laden (dh sogar aus dem Code), verhindert diese Methode, dass dies geschieht.

Was Sie tun können, um dies zu verhindern (danke Wade), ist:

if (inType == UIWebViewNavigationTypeLinkClicked) {
    [[UIApplication sharedApplication] openURL:[inRequest URL]];
    return NO;
}

return YES;

Möglicherweise möchten Sie auch die Typen UIWebViewNavigationTypeFormSubmittedund behandeln UIWebViewNavigationTypeFormResubmitted.

MonsieurDart
quelle
8
+1 Ich hatte das gleiche Problem. Die Lösung bestand darin, nach UIWebViewNavigationTypeLinkClicked als Anforderungstyp zu suchen, dann die URL zu öffnen und NEIN zurückzugeben, andernfalls JA zurückzugeben.
Wade Mueller
Wade sollten Sie Ihren Kommentar als Antwort posten
Toby Allen
16

Die anderen Antworten haben ein Problem: Sie hängen von der Aktion ab, die Sie ausführen, und nicht vom Link selbst, um zu entscheiden, ob er in Safari oder in der Webansicht geladen werden soll.

Manchmal ist es genau das, was Sie wollen, was in Ordnung ist. In einigen anderen Fällen, insbesondere wenn Ihre Seite Ankerlinks enthält, möchten Sie in Safari wirklich nur externe und keine internen Links öffnen. In diesem Fall sollten Sie die URL.hostEigenschaft Ihrer Anfrage überprüfen .

Ich verwende diesen Code, um zu überprüfen, ob ich einen Hostnamen in der URL habe, die analysiert wird, oder ob er in HTML eingebettet ist:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    static NSString *regexp = @"^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9-]*[a-zA-Z0-9])[.])+([A-Za-z]|[A-Za-z][A-Za-z0-9-]*[A-Za-z0-9])$";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexp];

    if ([predicate evaluateWithObject:request.URL.host]) {
        [[UIApplication sharedApplication] openURL:request.URL];
        return NO; 
    } else {
        return YES; 
    }
}

Sie können den regulären Ausdruck natürlich an Ihre Bedürfnisse anpassen.

KPM
quelle
Hinweis: Der reguläre Ausdruck wird von stackoverflow.com/questions/106179/…
KPM
1
Ja zum Filtern eingehender Anforderungen, Nein zum Parsen des Hostnamens. Ein besserer Ansatz wäre, basierend auf dem URL-Schema zu filtern. Unter iOS 8.4 (Simulator) wurde "applewebdata" als Schema für Ankerlinks verwendet, dies kann jedoch je nach Zielversion variieren.
MandisaW
Gute Idee MandisaW. Um Ankerlinks zuzulassen, überprüfe ich das "Datei" -Schemaif (request.URL?.scheme != "file")
David Douglas
7

In Swift können Sie den folgenden Code verwenden:

extension YourViewController: UIWebViewDelegate {
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
        if let url = request.url, navigationType == UIWebView.NavigationType.linkClicked {
            UIApplication.shared.open(url, options: [:], completionHandler: nil)
            return false
        }
        return true
    }

}

Stellen Sie sicher, dass Sie nach dem URL-Wert und dem Navigationstyp suchen.

Antoine
quelle
1

Hier ist das Xamarin iOS-Äquivalent zu Drawonwards Antwort.

class WebviewDelegate : UIWebViewDelegate {
    public override bool ShouldStartLoad (UIWebView webView, NSUrlRequest request, UIWebViewNavigationType navigationType) {
        if (navigationType == UIWebViewNavigationType.LinkClicked) {
            UIApplication.SharedApplication.OpenUrl (request.Url);
            return false;
        }
        return true;
    }
}
Danfordham
quelle
1

Die akzeptierte Antwort funktioniert nicht.

Wenn Ihre Seite URLs über Javascript lädt, ist dies der navigationTypeFall UIWebViewNavigationTypeOther. Dies beinhaltet leider auch das Laden von Hintergrundseiten wie Analytics.

Zur Erkennung Seitennavigation, müssen Sie das vergleichen , [request URL]um die[request mainDocumentURL] .

Diese Lösung funktioniert in allen Fällen:

- (BOOL)webView:(UIWebView *)view shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)type
{
    if ([[request URL] isEqual:[request mainDocumentURL]])
    {
        [[UIApplication sharedApplication] openURL:[request URL]];
        return NO;
    }
    else
    {       
        return YES;
    }
}
IanS
quelle
1
Können Sie eine Swift 4-Version davon veröffentlichen?
Amjad
1

App-Ablehnung Hinweis:

Schließlich UIWbView ist es tot und Apple wird es nicht mehr akzeptieren.

Apple hat damit begonnen, E-Mails an alle App-Besitzer zu senden, die noch Folgendes verwenden UIWebView:

Veraltete API-Nutzung - Apple akzeptiert keine Einsendungen von Apps mehr, die UIWebViewAPIs verwenden.

Apple nimmt den Datenschutz der Benutzer sehr ernst und es ist offensichtlich, dass sie keine unsichere Webansicht zulassen .

Entfernen Sie UIWebView also so schnell wie möglich aus Ihrer App. Verwenden Sie nicht versuchen, UIWebViewin einer neu erstellten App zu verwenden, und ich bevorzuge die Verwendung, WKWebViewwenn möglich

ITMS-90809: Veraltete API-Nutzung - Apple akzeptiert keine Übermittlungen von Apps mehr, die UIWebView-APIs verwenden. Weitere Informationen finden Sie unter https://developer.apple.com/documentation/uikit/uiwebview .

Beispiel:

import UIKit
import WebKit

class WebInfoController: UIViewController,WKNavigationDelegate {

    var webView : WKWebView = {
        var webview = WKWebView()
        return webview
    }()

    var _fileName : String!

    override func viewDidLoad() {
        self.view.addSubview(webView)
        webView.fillSuperview()
        let url = Bundle.main.url(forResource: _fileName, withExtension: "html")!
        webView.loadFileURL(url, allowingReadAccessTo: url)
        let request = URLRequest(url: url)
        webView.load(request)
    }


    func webView(webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: NSError) {
        print(error.localizedDescription)
    }
    func webView(webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("Strat to load")
    }
    func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
        print("finish to load")
    }
}
Nazmul Hasan
quelle
0

In meinem Fall möchte ich sicherstellen, dass absolut alles in der Webansicht Safari außer dem anfänglichen Laden öffnet und ich verwende ...

- (BOOL)webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
     if(inType != UIWebViewNavigationTypeOther) {
        [[UIApplication sharedApplication] openURL:[inRequest URL]];
        return NO;
     }
     return YES;
}
Michael Platt
quelle