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