Files can't be downloaded from WKWebView if the file is behind a login wall, as the cookies in WKWebView are unavailable.
Steps to Reproduce:
1. Create a WKWebView application.
2. Attempt to download a file which is protected by authentication into the application Documents directory.
File can be downloaded.
NOTE: _WKNavigationActionPolicyDownload is defined privately in WebKit2, but it is not exposed in the public WKNavigationDelegate.
Authentication to file fails.
iOS 9.3.2 (13F69)
"Attempt to download a file which is protected by authentication into the application Documents directory."
Could you give us more details on this?
How are you attempting to load the file?
How is it protected by auth?
I will create a sample project with this scenario.
You can reproduce this by logging into a cloud service (ex: GoogleDrive) in a WKWebView with the websiteDataStore configuration set to +nonPersistentDataStore.
Or attempt to download a file which is directly linked to from a webpage instead of displaying it inside of the WKWebView. This type of webpage may be protected by HTTP Basic Authentication for example. (I can provide such a sample site if desired.)
In order to download the file into the application, intercept the request in webView:decidePolicyForNavigationAction:decisionHandler:. I am attempting the file download using an NSURLSessionDownloadTask. Attempting to use this request to download the file outside of WKWebView fails.
(In reply to comment #3)
> You can reproduce this by logging into a cloud service (ex: GoogleDrive) in
> a WKWebView with the websiteDataStore configuration set to
> Or attempt to download a file which is directly linked to from a webpage
> instead of displaying it inside of the WKWebView. This type of webpage may
> be protected by HTTP Basic Authentication for example. (I can provide such a
> sample site if desired.)
> In order to download the file into the application, intercept the request in
> webView:decidePolicyForNavigationAction:decisionHandler:. I am attempting
> the file download using an NSURLSessionDownloadTask. Attempting to use this
> request to download the file outside of WKWebView fails.
So, to clarify:
- The user is browsing around in a WKWebView app.
- The user clicks on a link that the app would like to download instead of display in the WKWebView.
- The app denies the load in the policy handler, and then attempts to load the URL using an NSURLSessionDownloadTask inside the app process.
- That fails when the URL is protected by some sort of auth (cookie, http auth, ntlm, etc)
If my recounting of the above scenario is correct, then the reason it fails is because the browsing session (including cookies, credentials, etc) is held by the networking process, but since the app is trying the load inside the app process, the download doesn't go through.
Is my understanding correct?
Yes, your understanding of the issue is correct. Thanks for verifying!
iOS 11 now provides API for retrieving cookies. However it is still useful to have public API for WKWebView downloads, because some URLs (like bank statements) can be visited only one, so the only way to download those URLs would be using _WKNavigationActionPolicyDownload in decidePolicyForNavigationResponse.
> some URLs (like bank statements) can be visited only one, so the only way to download
> those URLs would be using _WKNavigationActionPolicyDownload
Brady's suggestion was to use WKNavigationActionPolicyCancel and then perform the download in the client app.
If the WebKit navigation is canceled, there's only one visit to the target URL -- the visit in the client app.
Can you clarify why a load-once download URL would fail?
Sorry for the confusion. I was thinking about _WKNavigationResponsePolicyBecomeDownload not about _WKNavigationActionPolicyDownload, my bad.
Here is the scenario where host app will have to visit the URL again:
1.) webView:decidePolicyForNavigationResponse:decisionHandler: gets called
2.) navigationResponse.canShowMIMEType returns NO
3.) navigationResponse.response.MIMEType is application/vnd.apple.pkpass
In this case a browser wants to start downloading PassKit file so it can be added into Wallet app. And the only way to do that is to fetch the URL again.
var b = URL.createObjectURL(new File(["content"],
lastModified: new Date()
document.getElementById("link").href = b;
document.getElementById("link").innerHTML = b;
This script will create the link, and tapping on the link will call decidePolicyForNavigationResponse:.
The URL for passed response will be a blob URL (something like blob:https://<hostname>/<id-of-blob-url>).
And there is no way for the browser to download that URL, because only WKWebView knows which data backs this URL up.
(In reply to michaeldo from comment #0)
Better link: <rdar://problem/26818508>