在 WKWebView 中启动电话/电子邮件/地图链接

Posted

技术标签:

【中文标题】在 WKWebView 中启动电话/电子邮件/地图链接【英文标题】:Launching phone/email/map links in WKWebView 【发布时间】:2014-10-22 06:01:29 【问题描述】:

KINWebBrowser 是一个用于 ios 应用的开源网络浏览器模块。我最近升级了 KINWebBrowser 以使用 WKWebView 开始逐步淘汰 UIWebView。这产生了显着的改进,但是:

问题:WKWebView 不允许用户启动包含电话号码、电子邮件地址、地图等 URL 的链接。

如何配置 WKWebView 以在从显示的页面作为链接启动时启动这些备用 URL 的标准 iOS 行为?

所有code is available here

更多信息WKWebKit

见issue on the KINWebBrowser GitHub here

【问题讨论】:

你做不到。如果此功能对您很重要,那将是目前坚持使用 UIWebView 的原因 - 并向 Apple 提交增强请求。 UIWebView 可以做很多事情而 WKWebView 做不到。 【参考方案1】:

通过将此函数添加到您的 KINWebBrowserViewController.m 中,我能够使其适用于 Google 地图链接(似乎与 target="_blank" 相关)和 tel: 方案

- (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);

【讨论】:

这段代码有点冗长,不保证会调用decisionHandler 好点!谢谢。这是一个深夜,最后一分钟的补丁,来自 2 个不同的来源,旨在快速解决问题。虽然它确实有效,但不是最干净的,而且肯定存在没有调用 decisionHandler 的情况。我已经编辑了代码。谢谢! 这段代码绝对是在正确的道路上,但它引入了一个安全漏洞,可能允许不情愿地发起呼叫和 FaceTime 呼叫。在这里查看我的解释:github.com/dfmuir/KINWebBrowser/issues/10 这个解决方案对我公司的我们帮助很大。谢谢达伦。我们可以稍微修改它,也可以通过我们网页的链接打开应用商店,并通过点击我们网页中的链接打开电子邮件应用程序。干杯! 为避免@dfmuir 指出的安全漏洞问题,请将url 更改为“telprompt”而不是默认的“tel”。例如,如果原始自定义 URL 是“tel:(212)%20555-6666”,则等效的 telprompt 是“telprompt:(212)%20555-6666”。这样用户在拨打电话前会得到提示【参考方案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)
    


【讨论】:

不要忘记添加委托:WKUIDelegate 和 var webView = WKWebView() 到属性【参考方案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.hasPrefix("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.hasPrefix("mailto:"):
    if UIApplication.shared.canOpenURL(failingUrl) 
      UIApplication.shared.open(failingUrl, options: [:], completionHandler: nil)
      return
    

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

  default: break
  

现在可以直接从您的应用调用 Facebook、Mail、Appstore 等,而无需打开 Safari

编辑:用标准的 hasPrefix() 方法替换了自定义的 startsWith() 方法。

【讨论】:

什么是startsWith? 同hasPrefix() 但是为什么tel方案加载失败?【参考方案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

已编辑:

in 链接必须是属性target="_blank"

【讨论】:

【参考方案5】:

我来到这里搜索如何在 wkwebview 上打开 gmail 附件。

我的解决方案很简单:

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 – Detect tel, mailto, target=”_blank” and 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
        
    

【讨论】:

以上是关于在 WKWebView 中启动电话/电子邮件/地图链接的主要内容,如果未能解决你的问题,请参考以下文章

iOS调用系统电话浏览器地图邮件等

在科尔多瓦允许通话(以及地图和邮件)

如何用一根手指而不是两根手指移动地图(在 WKWebView 内)

Google地图自动填充功能在Cordova iOS上使用WKWebView失败

android 通用 Intent

利用谷歌地图采集外贸客户的电话和手机号码