Запуск телефона/электронной почты/ссылок на карту в WKWebView

KINWebBrowser - это модуль веб-браузера с открытым исходным кодом для приложений iOS. Недавно я обновил KINWebBrowser, чтобы использовать WKWebView, чтобы начать отмену UIWebView. Это дает значительные улучшения, но:

Проблема: WKWebView не позволяет пользователям запускать ссылки, содержащие URL-адреса для телефонных номеров, адресов электронной почты, карт и т.д.

Как настроить WKWebView для запуска стандартного поведения iOS для этих альтернативных URL-адресов при запуске в качестве ссылок с отображаемой страницы?

Все код доступен здесь

Дополнительная информация о WKWebKit

См. вопрос о KINWebBrowser GitHub здесь

Ответ 1

Мне удалось заставить его работать на ссылку Google Maps (которая, как представляется, связана с целевым = "_ blank" ), и для схемы tel: добавив эту функцию в свой 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);
}

Ответ 2

Работает на xcode 8.1, Swift 2.3.

Для target = "_ blank", номер телефона (tel :) и адрес электронной почты (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)
    }
}

Обновлено для 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)
    }

}

Ответ 3

Вам нужно реализовать другой обратный вызов, чтобы получить это право (Swift 5.0):

// 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.open(failingUrl, options: [:], completionHandler: nil)
      return
    }

  // Needed to open Appstore-App
  case _ where failingUrlStr.startsWith("itmss://itunes.apple.com/"):
    if UIApplication.shared.canOpenURL(failingUrl) {
      UIApplication.shared.open(failingUrl, options: [:], completionHandler: nil)
      return
    }

  default: break
  }
}

Теперь Facebook, Mail, Appstore,... звонят прямо из вашего приложения без необходимости открывать Safari

Ответ 4

Это помогает мне для 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
}

Редакция:

В ссылке должен быть атрибут target="_blank".

Ответ 5

Я попал сюда в поисках того, как открыть вложения в gmail на wkwebview.

Мое решение простое:

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

Ответ 6

ОБНОВЛЕНИЕ ДЛЯ SWIFT 4.2

Извините, что выкопал старый пост, но у меня возникли те же проблемы, и я обновил решение для Swift 4.2. Я поместил свое решение здесь, чтобы оно могло помочь другим, и если нет, надеюсь, я найду его в следующий раз, когда буду работать с 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)
    }
}

Я использовал следующий сайт для вдохновения:

SubzDesignz iOS Swift 4 WKWebview - обнаружение тел, mailto, target = "_ blank" и CheckConnection

Ответ 7

Над ответами для меня, но мне нужно было переписать для 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
        }
    }
}