在 Safari 中打开 WKWebview target="_blank" link

Open a WKWebview target="_blank" link in Safari

我正在尝试让我的混合 IOS 应用程序使用 Swift 和 WKWebviews 打开具有 target="_blank" 的 link 或者 URL在 Mobile Safari 中包含 http://https://mailto:

this answer 我得到这个代码。

func webView(webView: WKWebView!, createWebViewWithConfiguration     configuration: WKWebViewConfiguration!, forNavigationAction navigationAction:     WKNavigationAction!, windowFeatures: WKWindowFeatures!) -> WKWebView! {
    if navigationAction.targetFrame == nil {
        webView.loadRequest(navigationAction.request)
    }
    return nil
}

首先,这对我没有任何作用。其次,我希望它在新 window 中打开。我发现这段代码应该做类似的事情...

if let requestUrl = NSURL(string: "http://www.iSecurityPlus.com") {
     UIApplication.sharedApplication().openURL(requestUrl)
}

我如何将这两个放在一起并让它们工作?我需要在 ViewController 声明中添加什么才能使其生效?

在 (from here)

 override func loadView() {
    super.loadView()
    self.webView.navigationDelegate = self 
    self.webView.UIDelegate = self  //must have this
 }

然后添加函数(from here, with additions)...

func webView(webView: WKWebView,
    createWebViewWithConfiguration configuration: WKWebViewConfiguration,
    forNavigationAction navigationAction: WKNavigationAction,
    windowFeatures: WKWindowFeatures) -> WKWebView? {
        if navigationAction.targetFrame == nil {
            var url = navigationAction.request.URL
            if url.description.lowercaseString.rangeOfString("http://") != nil || url.description.lowercaseString.rangeOfString("https://") != nil || url.description.lowercaseString.rangeOfString("mailto:") != nil  {
                UIApplication.sharedApplication().openURL(url)
            }
        }
        return nil
}

先加上WKNavigationDelegatewebviewWk.navigationDelegate = self

func webView(webView: WKWebView, decidePolicyForNavigationAction navigationAction: WKNavigationAction, decisionHandler: (WKNavigationActionPolicy) -> Void) {

        //this is a 'new window action' (aka target="_blank") > open this URL externally. If we´re doing nothing here, WKWebView will also just do nothing. Maybe this will change in a later stage of the iOS 8 Beta
        if navigationAction.navigationType == WKNavigationType.LinkActivated {
            println("here link Activated!!!")
            let url = navigationAction.request.URL
            let shared = UIApplication.sharedApplication()

            let urlString = url!.absoluteString

            if shared.canOpenURL(url!) {
                shared.openURL(url!)
            }

            decisionHandler(WKNavigationActionPolicy.Cancel)
        }

        decisionHandler(WKNavigationActionPolicy.Allow)
    }

代码已更新 iOS 10 Swift 3:

override func loadView() {
    super.loadView()
    self.webView.navigationDelegate = self 
    self.webView.uiDelegate = self  //must have this
}

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.lowercased().range(of: "http://") != nil ||
        url.description.lowercased().range(of: "https://") != nil ||
        url.description.lowercased().range(of: "mailto:") != nil {
        UIApplication.shared.openURL(url)
      }
    }
  return nil
}
func webView(_ webView: WKWebView,
           createWebViewWith configuration: WKWebViewConfiguration,
           for navigationAction: WKNavigationAction,
           windowFeatures: WKWindowFeatures) -> WKWebView? {
  if navigationAction.targetFrame == nil, let url = navigationAction.request.url, let scheme = url.scheme {
    if ["http", "https", "mailto"].contains(where: { [=10=].caseInsensitiveCompare(scheme) == .orderedSame }) {
      UIApplication.shared.openURL(url)
    }
  }
  return nil
}

Swift 4.2

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Swift.Void) {
    if navigationAction.navigationType == WKNavigationType.linkActivated {
        print("here link Activated!!!")
        if let url = navigationAction.request.url {
            let shared = UIApplication.shared
            if shared.canOpenURL(url) {
                shared.open(url, options: [:], completionHandler: nil)
            }
        }
        decisionHandler(.cancel)
    }
    else {
        decisionHandler(.allow)
    }
}

虽然上述某些解决方案在一定程度上起作用,但问题是所有 link 都开始在外部打开,而不仅仅是那些没有像 mailto 那样遵循 HTTPs url 方案的那些, 空白, 深links 等

我实现了这些 WKNavigationDelegate 功能

  1. decidePolicyFor navigationAction (documentation link) 甚至允许 url 不遵循 HTTPs 方案的被允许处理

  2. this navigation fail delegate function webView didFailProvisionalNavigation 并检查 iOS 是否可以处理在新选项卡中打开、邮件、深度 link 等万一它会打开应用程序商店

  3. 您也可以实现与本文中第 2 点相同的逻辑 WKNavigationDelegate function以防万一

代码如下:

class ViewController: UIViewController, WKNavigationDelegate
{
    // Initialize the webview anywhere you wish
    override func viewDidAppear(_ animated: Bool)
    {
        super.viewDidAppear(animated)
        
        let html = """
        <a href="https://apps.apple.com/us/app/directorio-notarios-cdmx/id1544000342"> App store Deep link usually doesn't open </a></span></span><br />

        <a href="https://landercorp.mx" rel="noopener"> Normal link </a></span></span><br />
        """
        
        let webview = WKWebView()
        webview.frame = view.bounds
        webview.navigationDelegate = self
        view.addSubview(webview)
        webview.loadHTMLString(html, baseURL: nil)
    }
    
    // MARK: WKNavigationDelegates
    func webView(_ webView: WKWebView,
                 decidePolicyFor navigationAction: WKNavigationAction,
                 decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
    {
        decisionHandler(.allow)
    }
    
    
    func webView(_ webView: WKWebView,
                 didFailProvisionalNavigation navigation: WKNavigation!,
                 withError error: Error)
    {
        manageFailedNavigation(webView,
                               didFail: navigation,
                               withError: error)
    }

    func webView(_ webView: WKWebView,
                 didFail navigation: WKNavigation!,
                 withError error: Error)
    {
        manageFailedNavigation(webView,
                               didFail: navigation,
                               withError: error)
    }

    private func manageFailedNavigation(_ webView: WKWebView,
                                        didFail navigation: WKNavigation!,
                                        withError error: Error)
    {
        // Check if this failed because of mailto, _blank, deep links etc
        // I have commented out how to check for a specific case like open in a new tab,
        // you can try to handle each case as you wish
        if error.localizedDescription
            == "Redirection to URL with a scheme that is not HTTP(S)"
           //let url = webView.url, url.description.lowercased().range(of: "blank") != nil
        {
            // Convert error to NSError so we can access the url
            let nsError = error as NSError
            
            // Get the url from the error
            // This key could change in future iOS releases
            if let failedURL = nsError.userInfo["NSErrorFailingURLKey"] as? URL
            {
                // Check if the action can be handled by iOS
                if UIApplication.shared.canOpenURL(failedURL)
                {
                    // Request iOS to open handle the link
                    UIApplication.shared.open(failedURL, options: [:],
                                              completionHandler: nil)
                }
            }
        }
    }
}

这样,两种情况都得到处理,其中遵循 HTTPs url 方案而不是