Closed peschee closed 2 years ago
Hi,
you mean you always receive this error inside download(_ download: WKDownload, didFailWithError error: Error, resumeData: Data?)? Do you get it on a device or the simulator?
Hi
Thanks for getting back to me. Yes, I am getting this error inside func download(_ download: WKDownload, didFailWithError error: Error, resumeData: Data?)
, I never get into the successful callback func downloadDidFinish(_ download: WKDownload)
.
I have only tested inside the Simulator, and to be fair, my "mock server" is running locally using http://
(no SSL). I will re-test in a device and using SSL as well.
I just tried on a 15.2 simulator and it worked, I opened google on the WKWebView, looked for an xls file and downloaded it from a server. I don't think I ever tried with a local server. What happens if you navigate to a page on your http server inside a WKWebView?
Could you try something on your end: can you try to download the same file twice?
I'm currently testing on a device over SSL, and it works each time a file is downloaded for the first time. As soon as I try to do it again for the same file (even after restarting the app), it fails with:
Error Domain=NSURLErrorDomain Code=-3000 "(null)"
When I prepend a filestamp to the suggested filename, it works each time as well…
Something like this:
public func download(_ download: WKDownload, decideDestinationUsing response: URLResponse, suggestedFilename: String, completionHandler: @escaping (URL?) -> Void) {
let temporaryDir = NSTemporaryDirectory()
let date = Date()
let format = DateFormatter()
format.dateFormat = "yyyy-MM-dd-HH-mm-ss"
let timestamp = format.string(from: date)
let fileName = temporaryDir + "/" + timestamp + suggestedFilename
let url = URL(fileURLWithPath: fileName)
fileDestinationURL = url
completionHandler(url)
}
What happens if you navigate to a page on your http server inside a WKWebView?
This works, so I'm unsure whether it really is about HTTP vs HTTPS.
EDIT: Ok, downloading from the local server works as well… The (permission?) issue really seems to be related to the filename being reused…
Oh sure it is the same file downloaded twice I think I always tested different files. I'll update a fix later, I may prepend a timestamp as you suggest or have a way to delete the file once it's been copied elsewhere, to avoid having too much stuff in the temporary directory.
I just checked with your example project, and it is the same issue there.
Prepending the timestamp is not really nice, since it changes the filename. I'm also not sure whether it is about the file already being in the temporary directory. The error message also really doesn't give you much, thanks 🍎 :)
What I am using in my implementation (I had to implement myself because I have other navigationDelegate logic I need to handle and I wasn't able to subclass your library) to fix issues with double slashes inside filenames //
is
let fileName = NSString.path(withComponents: [temporaryDir, suggestedFilename])
instead of
let fileName = temporaryDir + "/" + suggestedFilename
If I add this:
do {
if (FileManager.default.isDeletableFile(atPath: fileName)) {
try FileManager.default.removeItem(atPath: fileName)
}
} catch {
print("Cannot delete temporary file ", fileName)
}
it works! So removing the temporary file with the same name seems to fix the issue.
I just released a new tag. Every time a new file is downloaded a new random directory is created and the file is put inside it. This way even if you try to download two files with the same name using two instances of the class, you should be able to to it. Maybe it is overkill, and your proposal is working as well. I'll think about something better, like deleting the file after is being shared, but in the meantime my solution and yours are an acceptable workaround.
Thanks, that's wonderful!
I had to implement it with a custom delegate anyway, since I needed additional logic inside
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void)
So I'm only able to re-use parts of your library, but your article and the library helped me a long way implementing the downloads!
It's a shame Apple did not provide something like this (their implementation on iOS Safari)
for the WKWebView as well :)
To improve my library I can add another function to WKDownloadHelperDelegate where I ask for the path of the file given the suggested name, so whoever uses my package can implement the logic to remove an existing file, appending or prepending the timestamp as you initially suggested, or move the new file to a different directory etc. The default implementation could use the temporary directory. Will work on that tomorrow it should be quick to add.
Tag 0.3.0 introduces a new function in the delegate that allows you to specify the URL of the file, the default implementation puts it into a random directory in tmp.
Hi
I found your article about downloads in a WKWebView to be very valuable. I have followed your example and am unable to download files. I'm testing with the latest 15.x iOS. The error I always get in the
download
method ofWKDownloadDelegate
isError Domain=NSURLErrorDomain Code=-3000 "(null)"
The error code
-3000
seems to beNSURLErrorCannotCreateFile
(https://developer.apple.com/documentation/foundation/1508628-url_loading_system_error_codes/nsurlerrorcannotcreatefile/) which in turns suggests that there's an issue with creating the file. From what I can tell, this is all handled inside the "new"WKWebView
.Did you ever run into such an issue? Is there a permission that needs to be enabled in
Info.plist
for this to work?Documentation seems to be pretty scarce :/