Links abertos do UIWebView no Safari

304

Eu tenho um UIWebView muito simples com conteúdo do meu pacote de aplicativos. Gostaria que todos os links na visualização da Web fossem abertos no Safari em vez de na visualização da Web. Isso é possível?

David Beck
fonte
A resposta aceita abaixo não funcionará em todos os casos.
31916 IanSão Paulo
Eu adicionei uma resposta melhor. Por favor, marque minha resposta como a aceita.
IANS

Respostas:

657

Adicione isso ao delegado UIWebView:

(editado para verificar o tipo de navegação. você também pode passar por file://solicitações que seriam links relativos)

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

    return YES;
}

Versão rápida:

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

Versão 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
}

Versão 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
}

Atualizar

Como openURLfoi preterido no 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;
}
desenhado
fonte
daqui para frente, você se importaria de atualizar sua resposta com referência à resposta e aos comentários abaixo.
Toby Allen
Como voltar ao aplicativo depois que o usuário fecha o navegador?
Johnny Everson 28/05
3
@ Jhonny Everson: Você não tem controle sobre o que acontece depois que qualquer aplicativo externo (incluindo o Safari) é fechado. Se você quiser voltar ao seu aplicativo quando o usuário terminar de navegar, não abra o Safari, basta usar o UIWwbView e o botão "Concluído".
geon
1
Funcionou como um encanto com arquivo HTML local.
Necixy 20/03/12
1
Eu acho que, no Swift, um switché preferível para tipos de enum
SDJMcHattie
44

Se alguém se perguntar, a solução de Drawnonward seria assim em Swift :

func webView(webView: UIWebView!, shouldStartLoadWithRequest request: NSURLRequest!, navigationType: UIWebViewNavigationType) -> Bool {
    if navigationType == UIWebViewNavigationType.LinkClicked {
        UIApplication.sharedApplication().openURL(request.URL)
        return false
    }
    return true
}
DiegoFrings
fonte
alguma idéia de como fazer isso SOMENTE com URLS com https: // http: // ou mailto :? usando rápido? A pergunta aqui precisa de uma resposta rápida! stackoverflow.com/questions/2532453/…
Jed Grant
Versão @JedGrant rápida agora stackoverflow.com/questions/2532453/...
Carl Sharman
2
Certifique-se de usarUIWebViewDelegate
Jay Mayu
28

Um comentário rápido à resposta do usuário306253: cuidado com isso, quando você tenta carregar algo no UIWebView por conta própria (ou seja, mesmo a partir do código), esse método impedirá que isso aconteça.

O que você pode fazer para evitar isso (obrigado Wade) é:

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

return YES;

Você também pode querer lidar com os tipos UIWebViewNavigationTypeFormSubmittede UIWebViewNavigationTypeFormResubmitted.

MonsieurDart
fonte
8
+1 Eu tive o mesmo problema. A solução foi verificar UIWebViewNavigationTypeLinkClicked como o tipo de solicitação, depois abra a URL e retorne NO, caso contrário, retorne YES.
Wade Mueller #
Wade você deve enviar seu comentário como uma resposta
Toby Allen
16

As outras respostas têm um problema: elas dependem da ação que você executa e não no próprio link para decidir se o carregam no Safari ou na visualização na web.

Agora, às vezes, é exatamente isso que você deseja, o que é bom; mas outras vezes, especialmente se você tiver links âncora em sua página, você deseja realmente abrir apenas links externos no Safari, e não internos. Nesse caso, você deve verificar a URL.hostpropriedade da sua solicitação.

Eu uso esse trecho de código para verificar se tenho um nome de host na URL que está sendo analisada ou se ele está incorporado em html:

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

Obviamente, você pode adaptar a expressão regular para atender às suas necessidades.

KPM
fonte
Nota: a expressão regular é derivada de stackoverflow.com/questions/106179/…
KPM 2/12
1
Sim ao ponto de filtrar solicitações recebidas, não à análise do nome do host. Uma abordagem melhor seria filtrar com base no esquema de URL. No iOS 8.4 (simulador), obtive "applewebdata" usado como o esquema para links âncora, mas isso pode variar com a versão de destino.
MandisaW
Boa ideia MandisaW. Para permitir links de âncora, eu verifico o esquema "file"if (request.URL?.scheme != "file")
David Douglas
7

No Swift, você pode usar o seguinte código:

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
    }

}

Verifique o valor da URL e o navigationType.

Antoine
fonte
1

Aqui está o equivalente do Xamarin iOS à resposta do 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;
    }
}
Danfordham
fonte
1

A resposta aceita não funciona.

Se sua página carregar URLs via Javascript, navigationTypeserá UIWebViewNavigationTypeOther. Que, infelizmente, também inclui carregamentos de páginas em segundo plano, como análises.

Para detectar a navegação da página, você precisa comparar [request URL]com o [request mainDocumentURL].

Esta solução funcionará em todos os casos:

- (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
fonte
1
Você pode postar uma versão Swift 4 disso?
Amjad
1

Rejeição de aplicativo Nota:

Finalmente UIWbViewestá morto e a Apple não aceitará mais.

A Apple começou a enviar e-mails para todo o proprietário do aplicativo que ainda está usando UIWebView:

Uso preterido da API - a Apple deixará de aceitar envios de aplicativos que usam UIWebViewAPIs.

A Apple leva a privacidade do usuário muito a sério e é óbvio que eles não permitirão visualizações inseguras da web .

Portanto, remova o UIWebView do seu aplicativo o mais rápido possível. não use tente usar UIWebViewno novo aplicativo criado e eu prefiro usar WKWebViewse possível

ITMS-90809: Uso preterido da API - a Apple deixará de aceitar envios de aplicativos que usam APIs UIWebView. Consulte https://developer.apple.com/documentation/uikit/uiwebview para obter mais informações.

Exemplo:

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
fonte
0

No meu caso, quero garantir que absolutamente tudo na visualização da Web abra o Safari, exceto o carregamento inicial e, portanto, uso ...

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