iOS中的WKWebView:如何拦截点击并检索链接的内容?

时间:2016-08-19 22:56:30

标签: ios swift wkwebview

WKWebView中,当用户点击引用某些文件类型的链接时(例如,联系人的VCF文件或日历事件的ICS文件),我想拦截链接,即取消导航,而是使用专门的视图控制器显示内容。

例如,CNContactViewController可用于显示联系人,EKEventViewController可用于显示日历事件。

我可以通过分配WKNavigationDelegate并使用decidePolicyForNavigationAction拦截点击:

// Swift 2
extension MyController: WKNavigationDelegate {
  func webView(webView: WKWebView, decidePolicyForNavigationAction 
      navigationAction: WKNavigationAction, 
      decisionHandler: (WKNavigationActionPolicy) -> ()) {

    let url = navigationAction.request.URL!

    if url.pathExtension == "ics" {
      decisionHandler(WKNavigationActionPolicy.Cancel)
      // TODO: download data
      // TODO: display with EKEventViewController
    } else if url.pathExtension == "vcf" {
      decisionHandler(WKNavigationActionPolicy.Cancel)
      // TODO: download data
      // TODO: display with CNContactViewController
    } else {
      decisionHandler(WKNavigationActionPolicy.Allow)
    }

  }
}

但是为了显示专用控制器的文件,我需要先从给定的url下载数据。

我该怎么做?

由于下载需要身份验证,下载需要与WKWebView共享Cookie,或使用其他技术共享已经过身份验证的会话。

如果有帮助:我已经可以访问网络视图的WKProcessPoolWKWebViewConfiguration。根据我的理解,cookie与WKProcessPool有某种联系。但我不知道如何使用它来下载内容,例如使用NSURLSession

1 个答案:

答案 0 :(得分:1)

感觉很乱,但我通过让WKWebView执行一些通过ajax检索内容的javascript并将其返回到swift中的completionHandler来解决这个问题。

背景

WKWebView支持调用evaluateJavaScript,它会将javascript的结果传递给completionHandler

func evaluateJavaScript(_ javaScriptString: String,
    completionHandler completionHandler: ((AnyObject?, NSError?) -> Void)?)

由于服务器端有jQuery,我用它来发送ajax请求,如下所示。但是,当然,这也是can be done with vanilla javascript

(function(url) {
  var result = '';
  $.ajax({
    type: 'GET',
    url: url, 
    success: function(r) {result = r}, 
    failure: function() {result = null}, 
    async: false
  }); 
  return result 
})(url)

url可以使用swift的string interpolation传递给javascript。

扩展WKWebView

为了方便使用,我扩展了WKWebView类。

// Views/WKWebView.swift
import WebKit

extension WKWebView {
  func readUrlContent(url: NSURL, completionHandler: (result: String) -> Void) {

    self.evaluateJavaScript("(function() { var result = ''; $.ajax({type: 'GET', url: '\(url)', success: function(r) {result = r}, failure: function() {result = null}, async: false }); return result })()", completionHandler: { (response, error) -> Void in

      let result = response as! String
      completionHandler(result: result)

    })

  }
}

用法

从问题的例子中,可以这样调用:

let url = navigationAction.request.URL!
if url.pathExtension == "ics" {
  decisionHandler(WKNavigationActionPolicy.Cancel)
  webView.readUrlContent(url) { (result: String) in
    print(result)
    // TODO: display with EKEventViewController
  }
}