tel 的 WKWebView 问题:链接

Posted

技术标签:

【中文标题】tel 的 WKWebView 问题:链接【英文标题】:WKWebView issues with tel: links 【发布时间】:2018-03-05 12:56:02 【问题描述】:

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

我刚刚进入 xcode 和应用程序,并将本地 html 文件“index.html”加载到 WKWebView 中。这很好,加载很好,按原样显示,但是我有一些 tel: 页面上的链接不起作用,我点击它们却什么也没有。我正在为我的 html 文件使用 fraework7,并添加了“外部”类,它可以在 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>

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

任何指针都将不胜感激,因为我多年来一直在兜圈子。

【问题讨论】:

更新:我已经尝试了以下代码并且它有效...一旦单击链接时出现“线程 1:信号 SIGABRT”错误。 Launching phone/email/map links in WKWebView的可能重复 【参考方案1】:

终于找到了解决办法:

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)
    

使用这个似乎可以接电话:链接很好,我之前在这里找到的答案没有 else 语句,所以多次触发了导致错误的决策处理程序,else 语句修复了这个问题,现在看起来很好。

【讨论】:

【参考方案2】:

WKWebView 不只是开箱即用地处理 tel: 链接。 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)
    
  

我能想到 Apple 没有首先包含此链接的唯一原因是,当您尝试在 Mobile Safari 中启动其中一个链接时,它会显示如下对话框:

此网站已被阻止自动拨打电话。 [忽略] [允许来电]

因此,他们可能希望您希望在您的应用中实现类似的东西,而不是仅仅启动调用。

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

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

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

【讨论】:

【参考方案3】:

只需将WKNavigationDelegatedataDetectorTypes 用于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】:

虽然建议的答案可以正常工作 - 我建议使用白名单方法而不是黑名单。我们知道 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: 等。

【讨论】:

以上是关于tel 的 WKWebView 问题:链接的主要内容,如果未能解决你的问题,请参考以下文章

WKWebView:应用程序因“NSInternalInconsistencyException”异常而崩溃,因为“未调用传递给 X 的完成处理程序”

使用 Javascript 处理 HTML 和 Swift 之间的交互

iOS WkWebView - 这种情况有啥区别?

为啥在清理中删除“tel:”链接,以及如何允许它们

显示带有评论的文章,​​例如 Medium 应用程序

无法使用 WKWebView 在 Safari 中打开外部链接