web-dev-qa-db-fra.com

Liens ouverts dans UIWebView dans Safari

J'ai un très simple UIWebView avec le contenu de mon paquet d'application. J'aimerais que tous les liens de la vue Web s'ouvrent dans Safari plutôt que dans la vue Web. Est-ce possible?

300
David Beck

Ajoutez ceci au délégué UIWebView:

(édité pour vérifier le type de navigation. vous pouvez également passer par les requêtes file:// qui seraient des liens relatifs)

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

    return YES;
}

Version rapide:

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
}

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

Mise à jour

Comme openURL est obsolète dans 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;
}
652
drawnonward

Si quelqu'un se le demande, la solution de Drawnonward ressemblera à ceci dans Swift :

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

Un commentaire rapide sur la réponse de user306253: attention, lorsque vous essayez de charger quelque chose dans UIWebView (c'est-à-dire même à partir du code), cette méthode l'empêche de se produire.

Ce que vous pouvez faire pour empêcher cela (merci Wade), c'est:

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

return YES;

Vous pouvez également vouloir gérer les types UIWebViewNavigationTypeFormSubmitted et UIWebViewNavigationTypeFormResubmitted.

28
MonsieurDart

Les autres réponses ont un problème: elles dépendent de l'action que vous faites et non du lien lui-même pour décider de le charger dans Safari ou dans la visualisation Web.

Maintenant, parfois c'est exactement ce que vous voulez, ce qui est bien; mais d'autres fois, surtout si vous avez des liens d'ancrage dans votre page, vous voulez vraiment ouvrir uniquement les liens externes dans Safari, et non les liens internes. Dans ce cas, vous devriez vérifier la propriété URL.Host de votre demande.

J'utilise cette partie de code pour vérifier si l'URL analysée contient un nom d'hôte ou s'il contient du code HTML incorporé:

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

Vous pouvez bien sûr adapter l’expression régulière à vos besoins.

16
KPM

Dans Swift, vous pouvez utiliser le code suivant:

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
    }

}

Assurez-vous de vérifier la valeur de l'URL et le type de navigation.

7
Antoine

Voici l'équivalent Xamarin iOS de la réponse de 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
danfordham

La réponse acceptée ne fonctionne pas.

Si votre page charge des URL via Javascript, la navigationType sera UIWebViewNavigationTypeOther. Ce qui, malheureusement, inclut également des chargements de page en arrière-plan tels que des analyses.

Pour détecter la navigation dans les pages, vous devez comparer le [request URL] au [request mainDocumentURL].

Cette solution fonctionnera dans tous les cas:

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

Dans mon cas, je veux m'assurer que tout dans la vue Web ouvre Safari sauf le chargement initial et que j'utilise donc ...

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

Note de rejet de l'application:

Enfin UIWbView est mort et Apple ne l'acceptera plus.

Apple a commencé à envoyer un courrier électronique à tous les propriétaires d'applications qui utilisent toujours UIWebView:

Utilisation obsolète des API - Apple cessera d'accepter les soumissions d'applications utilisant les API UIWebView.

Apple prend la confidentialité des utilisateurs très au sérieux et il est évident qu’ils ne permettent pas la visualisation Web non sécurisée .

Alors, supprimez UIWebView de votre application dès que possible. N'utilisez pas essayez d'utiliser UIWebView dans la nouvelle application créée et je préfère utiliser WKWebView si possible

0
Nazmul Hasan