在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,或使用其他技术共享已经过身份验证的会话。
如果有帮助:我已经可以访问网络视图的WKProcessPool
和WKWebViewConfiguration
。根据我的理解,cookie与WKProcessPool
有某种联系。但我不知道如何使用它来下载内容,例如使用NSURLSession
。
答案 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
}
}