UIWebView apre i collegamenti in Safari


304

Ho un UIWebView molto semplice con contenuti dal mio pacchetto di applicazioni. Vorrei che qualsiasi collegamento nella vista Web si aprisse in Safari anziché nella vista Web. È possibile?


La risposta accettata di seguito non funzionerà in tutti i casi.
IanS,

Ho aggiunto una risposta migliore. Contrassegna la mia risposta come accettata.
IanS,

Risposte:


657

Aggiungi questo al delegato UIWebView:

(modificato per verificare il tipo di navigazione. Potresti anche passare attraverso le file://richieste che sarebbero collegamenti relativi)

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

    return YES;
}

Versione rapida:

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

Versione Swift 3:

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

Versione Swift 4:

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
}

Aggiornare

Come openURLè stato deprecato in iOS 10:

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

tra parentesi, ti dispiacerebbe aggiornare la tua risposta con riferimento alla risposta e ai commenti qui sotto.
Toby Allen,

Come tornare all'applicazione una volta che l'utente chiude il browser?
Johnny Everson,

3
@ Jhonny Everson: non hai alcun controllo su ciò che accade dopo la chiusura di un'app esterna (incluso Safari). Se vuoi tornare alla tua app quando l'utente ha terminato la navigazione, non aprire Safari, basta usare UIWwbView e un pulsante "Fine".
geon,

1
Ha funzionato come un fascino con il file HTML locale.
necixy,

1
Penso che, in Swift, switchsia preferibile un tipo di enum
SDJMcHattie,

44

Se qualcuno si chiede, la soluzione di Drawnonward sarebbe simile a questa in Swift :

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

qualche idea su come farlo SOLO con URL che hanno https: // http: // o mailto :? usando swift? La domanda qui ha bisogno di una risposta rapida! stackoverflow.com/questions/2532453/…
Jed Grant,

@JedGrant versione rapida ora su stackoverflow.com/questions/2532453/…
Carl Sharman

2
assicurati di usareUIWebViewDelegate
Jay Mayu il

28

Un breve commento alla risposta di user306253: attenzione a questo, quando provi a caricare qualcosa in UIWebView da solo (cioè anche dal codice), questo metodo impedirà che ciò accada.

Quello che puoi fare per evitare questo (grazie Wade) è:

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

return YES;

Potresti anche voler gestire i tipi UIWebViewNavigationTypeFormSubmittede UIWebViewNavigationTypeFormResubmitted.


8
+1 Ho avuto lo stesso problema. La soluzione consisteva nel controllare UIWebViewNavigationTypeLinkClicked come tipo di richiesta, POI aprire l'URL e restituire NO, altrimenti restituire SÌ.
Wade Mueller,

Wade dovresti pubblicare il tuo commento come risposta
Toby Allen

16

Le altre risposte hanno un problema: si basano sull'azione che fai e non sul link stesso per decidere se caricarlo in Safari o in visualizzazione Web.

Ora a volte questo è esattamente quello che vuoi, il che va bene; ma altre volte, specialmente se nella tua pagina sono presenti collegamenti di ancoraggio, vuoi davvero aprire solo i collegamenti esterni in Safari e non quelli interni. In tal caso è necessario controllare ilURL.host proprietà della richiesta.

Uso quel pezzo di codice per verificare se ho un nome host nell'URL che viene analizzato o se è HTML incorporato:

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

Ovviamente puoi adattare l'espressione regolare alle tue esigenze.


Nota: l'espressione regolare deriva da stackoverflow.com/questions/106179/…
KPM

1
Sì al punto di filtrare le richieste in arrivo, no al nome host che analizza. Un approccio migliore sarebbe filtrare in base allo schema URL. Su iOS 8.4 (simulatore), ho usato "applewebdata" come schema per i collegamenti di ancoraggio, ma ciò può variare con la versione di destinazione.
MandisaW,

Buona idea MandisaW. Per consentire i collegamenti di ancoraggio, controllo lo schema "file"if (request.URL?.scheme != "file")
David Douglas,

7

In Swift puoi usare il seguente codice:

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
    }

}

Assicurati di controllare il valore dell'URL e il navigationType.


1

Ecco l'equivalente Xamarin per iOS della risposta di drawonward.

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

1

La risposta accettata non funziona.

Se la tua pagina carica gli URL tramite Javascript, lo navigationTypesaràUIWebViewNavigationTypeOther . Che, sfortunatamente, include anche caricamenti di pagine di sfondo come l'analisi.

Per rilevare la navigazione della pagina, è necessario confrontare [request URL]il[request mainDocumentURL] .

Questa soluzione funzionerà in tutti i casi:

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

1
Puoi pubblicare una versione di Swift 4 di questo?
Amjad,

1

Nota sul rifiuto dell'app:

Finalmente UIWbViewè morto e Apple non lo accetterà più.

Apple ha iniziato a inviare e-mail a tutti i proprietari di app che stanno ancora utilizzando UIWebView:

Utilizzo dell'API obsoleto: Apple smetterà di accettare l'invio di app che utilizzano UIWebViewAPI.

Apple prende molto sul serio la privacy degli utenti ed è ovvio che non consentiranno una visualizzazione Web non sicura .

Quindi rimuovi UIWebView dalla tua app il prima possibile. non usare prova ad usare UIWebViewnella nuova app creata e preferisco usare WKWebViewse possibile

ITMS-90809: Utilizzo dell'API obsoleto: Apple smetterà di accettare l'invio di app che utilizzano API UIWebView. Vedi https://developer.apple.com/documentation/uikit/uiwebview per ulteriori informazioni.

Esempio:

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")
    }
}

0

Nel mio caso, voglio assicurarmi che assolutamente tutto nella vista Web apra Safari tranne il caricamento iniziale e quindi uso ...

- (BOOL)webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
     if(inType != UIWebViewNavigationTypeOther) {
        [[UIApplication sharedApplication] openURL:[inRequest URL]];
        return NO;
     }
     return YES;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.