代码之家  ›  专栏  ›  技术社区  ›  Cerbster

WKWebView问题与电话:链接

  •  6
  • Cerbster  · 技术社区  · 6 年前

    我已经看了很多关于这个问题的答案,但它们现在似乎已经过时了,没有一个解决方案对我有效,只会给出很多错误。

    我刚刚登录到xcode和应用程序,正在将本地html文件“index.html”加载到WKWebView中。这很好,加载很好,显示正常,但我在页面上有一些tel:链接不起作用,我点击了它们,什么都没有。我将fraework7用于html文件,并添加了“external”类,该类可在safari等中使用。

    更新:使用以下代码,我可以单击一个链接,它将尝试调用,但随后会出现致命错误

    import UIKit
    import WebKit
    class ViewController: UIViewController, WKNavigationDelegate{
    
        @IBOutlet weak var webview: WKWebView!
        override func viewDidLoad() {
            webview.navigationDelegate = self
            super.viewDidLoad()
            let htmlpath = Bundle.main.path(forResource: "index", ofType: "html")
            let url = URL(fileURLWithPath: htmlpath!)
            let request = URLRequest(url: url)
            webview.load(request)
            webview.scrollView.bounces = false
            webview.configuration.dataDetectorTypes = .phoneNumber
            // Do any additional setup after loading the view, typically from a nib.
        }
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
            if navigationAction.request.url?.scheme == "tel" {
                UIApplication.shared.openURL(navigationAction.request.url!)
                decisionHandler(.cancel)
            }
            decisionHandler(.allow)
        }
    
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    
    
    }
    

    html如下所示:

              <tr>
    
                <td>Police / Fire / Ambulance</td>
    
                <td>Emergency Services</td>
    
                <td><a href = "tel:999" class = "external">999</a></td>
    
              </tr>
    

    显然是较大表的一部分,但这就是示例。

    任何指点都将不胜感激,因为我已经绕圈多年了。

    4 回复  |  直到 6 年前
        1
  •  12
  •   wjl    6 年前

    最终设法找到解决方案:

    import UIKit
    import WebKit
    
    class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate{
    
      @IBOutlet weak var webView: WKWebView!
    
      override func viewDidLoad() {
        webView.navigationDelegate = self
        webView.uiDelegate = self
        super.viewDidLoad()
        let htmlpath = Bundle.main.path(forResource: "index", ofType: "html")
        let url2 = URL(fileURLWithPath: htmlpath!)
        let request = URLRequest(url: url2)
        webView.load(request)
        webView.scrollView.bounces = false
        //webview.configuration.dataDetectorTypes = .phoneNumber
      }
    
      func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        if navigationAction.request.url?.scheme == "tel" {
            UIApplication.shared.openURL(navigationAction.request.url!)
            decisionHandler(.cancel)
        } else {
            decisionHandler(.allow)
        }
    }
    

    使用此选项似乎可以解决tel:links问题,之前我在这里找到的一个答案没有else语句,因此多次触发了decisionHandler,这导致了错误,else语句修复了这个问题,现在看起来很好。

        2
  •  6
  •   Senseful    6 年前

    这不仅仅是 tel: WKWebView未即时处理的链接。其他链接,如 mailto: facetime: 也没有处理。有关这些特殊链接的完整列表,请参阅 Apple's documentation

    您应该决定要处理哪些Apple的特殊链接(请参见上面的链接),并以类似于以下的方式覆盖导航处理程序:

    webView.navigationDelegate = self
    
    ...
    
    extension ViewController: WKNavigationDelegate {
    
      func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        guard let url = navigationAction.request.url else {
          decisionHandler(.allow)
          return
        }
    
        if ["tel", "sms", "facetime"].contains(url.scheme) && UIApplication.shared.canOpenURL(url) {
          UIApplication.shared.open(url, options: [:], completionHandler: nil)
          decisionHandler(.cancel)
        } else {
          decisionHandler(.allow)
        }
      }
    }
    

    我所能想到的苹果为什么没有将其包含在第一位的唯一原因是,当您尝试在Mobile Safari中启动其中一个链接时,它会显示一个如下对话框:

    此网站已被阻止自动启动呼叫。
    [忽略][ 允许通话 ]

    因此,他们可能希望您在应用程序中实现类似的功能,而不仅仅是启动呼叫。

    但是,请注意,每种类型的链接的行为不同:

    • 电话: 对话框,显示带有呼叫/取消按钮的电话号码。
    • sms: 启动消息应用程序。
    • 邮寄地址: 启动邮件应用程序。

    因此,如果您确实希望有某种模式,允许用户在无意执行操作时取消,这取决于您支持的操作,它可能已经有类似的行为(例如。 电话: )。

        3
  •  0
  •   birdy    6 年前

    仅使用 WKNavigationDelegate dataDetectorTypes 对于 WKWebView 配置如下:

    webView.navigationDelegate = self
    webView.configuration.dataDetectorTypes = [.link, .phoneNumber]
    
    extension PDFWebViewController: WKNavigationDelegate {
    
        func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
            if let requestUrl = navigationAction.request.url, requestUrl.scheme == "tel" {
                UIApplication.shared.open(requestUrl, options: [:], completionHandler: nil)
                decisionHandler(.cancel)
    
            } else {
                decisionHandler(.allow)
            }
        }
    
    }
    
        4
  •  0
  •   Alexander Kulabukhov    3 年前

    虽然建议的答案很好用,但我建议使用白名单而不是黑名单。我们知道WKWebView只能处理http/https链接,因此我们可以优雅地处理打开任何其他类型链接的错误。

    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        self.handleNavigationError(error)
    }
    
    func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
        self.handleNavigationError(error)
    }
    
    private func handleNavigationError(_ error: Error) {
        if let failedUrl = (error as NSError).userInfo[NSURLErrorFailingURLErrorKey] as? URL, failedUrlScheme = failedUrl.scheme?.lowercased(), !["http", "https"].contains(failedUrlScheme) {
            UIApplication.shared.open(failedUrl, completionHandler: nil)
        } else {
            // handle other errors if needed
        }
    }
    

    在这种情况下,您将支持所有类型的外部应用程序链接,如 tel: , sms: , faceTime: , itms-services: