There is a file (CSV) that I want to download. It is behind a login screen on a website. I wanted to show a WKWebView
to allow the user to log in and then have the app download the file after they had logged in.
我想下载一个文件(CSV)。它位于网站的登录屏幕后面。我想显示一个WKWebView,允许用户登录,然后让应用程序在登录后下载文件。
I've tried downloading the file outside of WKWebView
after the user has logged in to the website, but the session data seems to be sandboxed because it downloads an html document with the login form instead of the desired file.
我已经尝试在用户登录网站后在WKWebView之外下载文件,但会话数据似乎是沙箱,因为它下载了一个带有登录表单而不是所需文件的html文档。
I've also tried adding a WKUserScript
to the WKUserContentController
object, but the script doesn't get run when a non-HTML file is loaded.
我还尝试将WKUserScript添加到WKUserContentController对象,但是当加载非HTML文件时,脚本不会运行。
Is there a way for me to access this file while allowing users to log in via the WKWebView
?
我是否有办法访问此文件,同时允许用户通过WKWebView登录?
5 个解决方案
#1
91
Right now, WKWebView instances will ignore any of the default networking storages (NSURLCache, NSHTTPCookieStorage, NSCredentialStorage) and also the standard networking classes you can use to customize the network requests (NSURLProtocol, etc.).
目前,WKWebView实例将忽略任何默认网络存储(NSURLCache,NSHTTPCookieStorage,NSCredentialStorage)以及可用于自定义网络请求的标准网络类(NSURLProtocol等)。
So the cookies of the WKWebView instance are not stored in the standard Cookie storage of your App, and so NSURLSession/NSURLConnection which only uses the standard Cookie storage has no access to the cookies of WKWebView (and exactly this is probably the problem you have: the „login status“ is most likely stored in a cookie, but NSURLSession/NSURLConnection won’t see the cookie).
因此,WKWebView实例的cookie不存储在应用程序的标准Cookie存储中,因此仅使用标准Cookie存储的NSURLSession / NSURLConnection无法访问WKWebView的cookie(确切地说,这可能是您遇到的问题: “登录状态”很可能存储在cookie中,但NSURLSession / NSURLConnection将不会看到cookie)。
The same is the case for the cache, for the credentials etc. WKWebView has its own private storages and therefore does not play well with the standard Cocoa networking classes.
对于缓存,凭证等也是如此.WKWebView有自己的私有存储,因此不能很好地使用标准的Cocoa网络类。
You also can’t customize the requests (add your own custom HTTP headers, modify existing headers, etc), use your own custom URL schemes etc, because also NSURLProtocol is not supported by WKWebView.
您也无法自定义请求(添加自己的自定义HTTP标头,修改现有标头等),使用您自己的自定义URL方案等,因为WKWebView也不支持NSURLProtocol。
So right now WKWebView is pretty useless for many Apps, because it does not participate with the standard networking APIs of Cocoa.
所以现在WKWebView对许多应用程序来说都没用,因为它不参与Cocoa的标准网络API。
I still hope that Apple will change this until iOS 8 gets released, because otherwise WKWebView will be useless for many Apps, and we are probably stick with UIWebView a little bit longer.
我仍然希望Apple能够在iOS 8发布之前对其进行更改,因为否则WKWebView对于许多应用程序来说都是无用的,而且我们可能会更长时间地使用UIWebView。
So send bug reports to Apple, so Apple gets to know that these issues are serious and needs to be fixed.
因此,向Apple发送错误报告,以便Apple了解这些问题是严重的,需要修复。
#2
15
Have you checked the response cookies coming back from the request. You could use a delegate method like this.
您是否检查了从请求中返回的响应cookie。您可以使用这样的委托方法。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
for (NSHTTPCookie *cookie in cookies) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
decisionHandler(WKNavigationResponsePolicyAllow);
}
#3
1
I've accomplished something similar to what you're trying to do:
我已经完成了类似于你想要做的事情:
- use the web view to login as you're already doing
- 使用Web视图登录,就像您已经在做的那样
- set a
navigationDelegate
on your webview - 在webview上设置navigationDelegate
- implement
-webView:decidePolicyForNavigationResponse:decisionHandler
in your delegate - 在你的委托中实现-webView:decisionPolicyForNavigationResponse:decisionHandler
- when that delegate method is called (after the user logs in), you can inspect
navigationResponse.response
(cast it toNSHTTPURLResponse*
) and look for aSet-Cookie
header that contains the session info you'll need for authenticated sessions. - 当调用该委托方法时(在用户登录后),您可以检查navigationResponse.response(将其强制转换为NSHTTPURLResponse *)并查找包含经过身份验证的会话所需的会话信息的Set-Cookie标头。
- you can then download the CSV by manually specifying the
Cookie
header in your request with the cookies specified in the response. - 然后,您可以通过在请求中使用响应中指定的Cookie手动指定Cookie标头来下载CSV。
Note that the delegate methods are only called for "main frame" requests. Which means that AJAX requests or inner frames will not trigger it. The whole page must refresh for this to work.
请注意,委托方法仅针对“主框架”请求进行调用。这意味着AJAX请求或内部框架不会触发它。整个页面必须刷新才能正常工作。
If you need to trigger behavior for AJAX requests, iframes etc you'll need to inject some javascript.
如果你需要触发AJAX请求,iframe等行为,你需要注入一些javascript。
#4
1
You can obtain the cookie via Javascript:
您可以通过Javascript获取cookie:
You could then use the obtained cookie to download the file manually:
然后,您可以使用获取的cookie手动下载文件:
webView.evaluateJavaScript("(function() { return document.cookie })()", completionHandler: { (response, error) -> Void in
let cookie = response as! String
let request = NSMutableURLRequest(URL: docURL)
request.setValue(cookie, forHTTPHeaderField: "Cookie")
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
// Your CSV file will be in the response object
}).resume()
})
#5
0
I do not seem to have the session cookie when I try a request from userContentController didReceiveScriptMessage.
当我尝试来自userContentController didReceiveScriptMessage的请求时,我似乎没有会话cookie。
However, when called from decidePolicyForNavigationAction, the following code detects that I'm logged in.
但是,从decisionPolicyForNavigationAction调用时,以下代码检测到我已登录。
let urlPath: String = "<api endpoint at url at which you are logged in>"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
let string1 = NSString(data: data, encoding: NSUTF8StringEncoding)
println(string1)
println(data)
if(error != nil) {
println("Error sending token to server")
// Print any error to the console
println(error.localizedDescription)
}
var err: NSError?
})
task.resume()
#1
91
Right now, WKWebView instances will ignore any of the default networking storages (NSURLCache, NSHTTPCookieStorage, NSCredentialStorage) and also the standard networking classes you can use to customize the network requests (NSURLProtocol, etc.).
目前,WKWebView实例将忽略任何默认网络存储(NSURLCache,NSHTTPCookieStorage,NSCredentialStorage)以及可用于自定义网络请求的标准网络类(NSURLProtocol等)。
So the cookies of the WKWebView instance are not stored in the standard Cookie storage of your App, and so NSURLSession/NSURLConnection which only uses the standard Cookie storage has no access to the cookies of WKWebView (and exactly this is probably the problem you have: the „login status“ is most likely stored in a cookie, but NSURLSession/NSURLConnection won’t see the cookie).
因此,WKWebView实例的cookie不存储在应用程序的标准Cookie存储中,因此仅使用标准Cookie存储的NSURLSession / NSURLConnection无法访问WKWebView的cookie(确切地说,这可能是您遇到的问题: “登录状态”很可能存储在cookie中,但NSURLSession / NSURLConnection将不会看到cookie)。
The same is the case for the cache, for the credentials etc. WKWebView has its own private storages and therefore does not play well with the standard Cocoa networking classes.
对于缓存,凭证等也是如此.WKWebView有自己的私有存储,因此不能很好地使用标准的Cocoa网络类。
You also can’t customize the requests (add your own custom HTTP headers, modify existing headers, etc), use your own custom URL schemes etc, because also NSURLProtocol is not supported by WKWebView.
您也无法自定义请求(添加自己的自定义HTTP标头,修改现有标头等),使用您自己的自定义URL方案等,因为WKWebView也不支持NSURLProtocol。
So right now WKWebView is pretty useless for many Apps, because it does not participate with the standard networking APIs of Cocoa.
所以现在WKWebView对许多应用程序来说都没用,因为它不参与Cocoa的标准网络API。
I still hope that Apple will change this until iOS 8 gets released, because otherwise WKWebView will be useless for many Apps, and we are probably stick with UIWebView a little bit longer.
我仍然希望Apple能够在iOS 8发布之前对其进行更改,因为否则WKWebView对于许多应用程序来说都是无用的,而且我们可能会更长时间地使用UIWebView。
So send bug reports to Apple, so Apple gets to know that these issues are serious and needs to be fixed.
因此,向Apple发送错误报告,以便Apple了解这些问题是严重的,需要修复。
#2
15
Have you checked the response cookies coming back from the request. You could use a delegate method like this.
您是否检查了从请求中返回的响应cookie。您可以使用这样的委托方法。
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler{
NSHTTPURLResponse *response = (NSHTTPURLResponse *)navigationResponse.response;
NSArray *cookies =[NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:response.URL];
for (NSHTTPCookie *cookie in cookies) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
}
decisionHandler(WKNavigationResponsePolicyAllow);
}
#3
1
I've accomplished something similar to what you're trying to do:
我已经完成了类似于你想要做的事情:
- use the web view to login as you're already doing
- 使用Web视图登录,就像您已经在做的那样
- set a
navigationDelegate
on your webview - 在webview上设置navigationDelegate
- implement
-webView:decidePolicyForNavigationResponse:decisionHandler
in your delegate - 在你的委托中实现-webView:decisionPolicyForNavigationResponse:decisionHandler
- when that delegate method is called (after the user logs in), you can inspect
navigationResponse.response
(cast it toNSHTTPURLResponse*
) and look for aSet-Cookie
header that contains the session info you'll need for authenticated sessions. - 当调用该委托方法时(在用户登录后),您可以检查navigationResponse.response(将其强制转换为NSHTTPURLResponse *)并查找包含经过身份验证的会话所需的会话信息的Set-Cookie标头。
- you can then download the CSV by manually specifying the
Cookie
header in your request with the cookies specified in the response. - 然后,您可以通过在请求中使用响应中指定的Cookie手动指定Cookie标头来下载CSV。
Note that the delegate methods are only called for "main frame" requests. Which means that AJAX requests or inner frames will not trigger it. The whole page must refresh for this to work.
请注意,委托方法仅针对“主框架”请求进行调用。这意味着AJAX请求或内部框架不会触发它。整个页面必须刷新才能正常工作。
If you need to trigger behavior for AJAX requests, iframes etc you'll need to inject some javascript.
如果你需要触发AJAX请求,iframe等行为,你需要注入一些javascript。
#4
1
You can obtain the cookie via Javascript:
您可以通过Javascript获取cookie:
You could then use the obtained cookie to download the file manually:
然后,您可以使用获取的cookie手动下载文件:
webView.evaluateJavaScript("(function() { return document.cookie })()", completionHandler: { (response, error) -> Void in
let cookie = response as! String
let request = NSMutableURLRequest(URL: docURL)
request.setValue(cookie, forHTTPHeaderField: "Cookie")
NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
// Your CSV file will be in the response object
}).resume()
})
#5
0
I do not seem to have the session cookie when I try a request from userContentController didReceiveScriptMessage.
当我尝试来自userContentController didReceiveScriptMessage的请求时,我似乎没有会话cookie。
However, when called from decidePolicyForNavigationAction, the following code detects that I'm logged in.
但是,从decisionPolicyForNavigationAction调用时,以下代码检测到我已登录。
let urlPath: String = "<api endpoint at url at which you are logged in>"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
let string1 = NSString(data: data, encoding: NSUTF8StringEncoding)
println(string1)
println(data)
if(error != nil) {
println("Error sending token to server")
// Print any error to the console
println(error.localizedDescription)
}
var err: NSError?
})
task.resume()