web-dev-qa-db-fra.com

Lancement des liens téléphone/email/carte dans WKWebView

KINWebBrowser est un module de navigateur Web à code source ouvert pour les applications iOS. J'ai récemment mis à niveau KINWebBrowser pour qu'il utilise WKWebView pour commencer à supprimer progressivement UIWebView. Cela apporte des améliorations significatives, mais:

Problème: WKWebView ne permet pas aux utilisateurs de lancer des liens contenant des URL pour les numéros de téléphone, adresses électroniques, cartes, etc.

Comment puis-je configurer un WKWebView pour lancer les comportements iOS standard pour ces autres URL lorsqu'il est lancé en tant que liens à partir de la page affichée?

Tout le code est disponible ici

Plus d'infos sur WKWebKit

Voir le numéro sur le KINWebBrowser GitHub ici

17
dfmuir

J'ai pu le faire fonctionner pour le lien Google Maps (qui semble être lié au target = "_ blank") et pour le schéma tel: en ajoutant cette fonction à votre KINWebBrowserViewController.m

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
    if(webView != self.wkWebView) {
        decisionHandler(WKNavigationActionPolicyAllow);
        return;
    }

    UIApplication *app = [UIApplication sharedApplication];
    NSURL         *url = navigationAction.request.URL;

    if (!navigationAction.targetFrame) {
        if ([app canOpenURL:url]) {
            [app openURL:url];
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    if ([url.scheme isEqualToString:@"tel"])
    {
        if ([app canOpenURL:url])
        {
            [app openURL:url];
            decisionHandler(WKNavigationActionPolicyCancel);
            return;
        }
    }
    decisionHandler(WKNavigationActionPolicyAllow);
}
24
Darren Ehlers

Fonctionne sur xcode 8.1, Swift 2.3.

Pour target = "_ blank", numéro de téléphone (tel :) et liens de courrier électronique (mailto :).

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {
    if webView != self.webview {
        decisionHandler(.Allow)
        return
    }

    let app = UIApplication.sharedApplication()
    if let url = navigationAction.request.URL {
        // Handle target="_blank"
        if navigationAction.targetFrame == nil {
            if app.canOpenURL(url) {
                app.openURL(url)
                decisionHandler(.Cancel)
                return
            }
        }

        // Handle phone and email links
        if url.scheme == "tel" || url.scheme == "mailto" {
            if app.canOpenURL(url) {
                app.openURL(url)
                decisionHandler(.Cancel)
                return
            }
        }

        decisionHandler(.Allow)
    }
}

Mise à jour pour Swift 4.0  

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

    if webView != self.webView {
        decisionHandler(.allow)
        return
    }

    let app = UIApplication.shared
    if let url = navigationAction.request.url {
        // Handle target="_blank"
        if navigationAction.targetFrame == nil {
            if app.canOpenURL(url) {
                app.open(url)
                decisionHandler(.cancel)
                return
            }
        }

        // Handle phone and email links
        if url.scheme == "tel" || url.scheme == "mailto" {
            if app.canOpenURL(url) {
                app.open(url)
            }

            decisionHandler(.cancel)
            return
        }

        decisionHandler(.allow)
    }

}
9
Victor Almeida

Vous devez implémenter un autre rappel pour obtenir ce résultat (Swift 3.1):

// Gets called if webView cant handle URL
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
  guard let failingUrlStr = (error as NSError).userInfo["NSErrorFailingURLStringKey"] as? String  else { return }
  let failingUrl = URL(string: failingUrlStr)!

  switch failingUrl {
    // Needed to open Facebook
    case _ where failingUrlStr.startsWith("fb:"):
    if #available(iOS 10.0, *) {
       UIApplication.shared.open(failingUrl, options: [:], completionHandler: nil)
       return
    } // Else: Do nothing, iOS 9 and earlier will handle this

  // Needed to open Mail-app
  case _ where failingUrlStr.startsWith("mailto:"):
    if UIApplication.shared.canOpenURL(failingUrl) {
      UIApplication.shared.openURL(failingUrl)
      return
    }

  // Needed to open Appstore-App
  case _ where failingUrlStr.startsWith("itmss://iTunes.Apple.com/"):
    if UIApplication.shared.canOpenURL(failingUrl) {
      UIApplication.shared.openURL(failingUrl)
      return
    }

  default: break
  }
}

Maintenant, Facebook, Mail, Appstore, .. se faire appeler directement depuis votre application sans avoir à ouvrir Safari

5
2h4u

Je suis arrivé ici en cherchant comment ouvrir des pièces jointes Gmail sur wkwebview.

Ma solution est simple:

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    if navigationAction.targetFrame == nil, let redirect = navigationAction.request.url {
        if UIApplication.shared.canOpenURL(redirect) {
            self.webViewMail?.load(navigationAction.request)
            decisionHandler(.cancel)
            return
        }
    }
    decisionHandler(.allow)
}
1
Luca Davanzo

Cela m'aide pour Xcode 8 WKWebview

func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
    if navigationAction.targetFrame == nil {
        let url = navigationAction.request.url
        if url?.description.range(of: "http://") != nil || url?.description.range(of: "https://") != nil || url?.description.range(of: "mailto:") != nil || url?.description.range(of: "tel:") != nil  {
            UIApplication.shared.openURL(url!)
        }
    }
    return nil
}

EDITED:

Dans le lien doit être l'attribut target="_blank".

1
Abduhafiz

MISE À JOUR POUR Swift 4.2

Désolé de creuser un ancien post, mais j'avais les mêmes problèmes et j'ai mis à jour la solution pour Swift 4.2. J'ai mis ma solution ici pour qu'elle puisse aider les autres et sinon j'espère la trouver la prochaine fois que je travaillerai avec WKWebView!

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {

    let url = navigationAction.request.url?.absoluteString
    let urlElements = url?.components(separatedBy: ":") ?? []

    switch urlElements[0] {

    case "tel":
        UIApplication.shared.openURL(navigationAction.request.url!)
        decisionHandler(.cancel)
    case "mailto":
        UIApplication.shared.openURL(navigationAction.request.url!)
        decisionHandler(.cancel)
    default:
        decisionHandler(.allow)
    }
}

J'ai utilisé le site suivant comme source d'inspiration:

SubzDesignz iOS Swift 4 WKWebview - Détectez tel, mailto, target = "_ blank" et CheckConnection

0
Iain Coleman

La réponse ci-dessus fonctionne pour moi, mais il me fallait réécrire pour Swift 2.3.

if navigationAction.targetFrame == nil {
    let url = navigationAction.request.mainDocumentURL
    if url?.description.rangeOfString("mailto:")?.startIndex != nil ||
        url?.description.rangeOfString("tel:")?.startIndex != nil
    {
        if #available(iOS 10, *) {
            UIApplication.sharedApplication().openURL(url!,options: [:], completionHandler: nil)
        } else {
            UIApplication.sharedApplication().openURL(url!)  // deprecated
        }
    }
}
0
Philipp Homann