'How to get partially downloaded data in Alamofire when network connection was lost

I am trying to download mp3 file from server. When the network connection was lost (I turn off my wifi connection explicitly) on device, the download request is failed which is fine but i can't get the partially downloaded data.

I have found there is a property called resumeData in responseData but it always returns nil.

I am using Alamofire 5.2.0. Here is my code.

func startTask(urlString: String) {
    guard let url = URL(string: urlString) else { return }

    let requestDestination: DownloadRequest.Destination = { _, _ in
        let documentsURL = self.localFilePathForUser(url: url)!
        return (documentsURL, [.removePreviousFile])
    }

    AF.download(url, to: requestDestination)
        .validate()
        .downloadProgress { [weak self] progress in
            print("Progress: \(progress.fractionCompleted)")
        }
        .response { [weak self] responseData in

            switch responseData.result {

            case .success(_):
                print("Download success")

            case .failure(let error):

                print("Download failed: ", error.localizedDescription)
                print("Downloaded data: ", responseData.resumeData?.count.byteSize) // always get nil
            }
        }
}

func localFilePathForUser(url: URL) -> URL? {
    guard let userId = UserManager.shared.currentUser?.id else { return nil }
    guard let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil }
    
    let newUrl = documentsPath.appendingPathComponent("\(userId)").appendingPathComponent(url.lastPathComponent).deletingPathExtension().appendingPathExtension("mp3")
    return newUrl
}


Solution 1:[1]

Found the solution. I just cast the AFError to NSError and retrieve the resumableData from userInfo using the key named NSURLSessionDownloadTaskResumeData. You can also find this useful. Here is the working code

func startTask(urlString: String) {
    guard let url = URL(string: urlString) else { return }
    
    let requestDestination: DownloadRequest.Destination = { _, _ in
        let documentsURL = self.localFilePathForUser(url: url)!
        return (documentsURL, [.removePreviousFile])
    }
    
    AF.download(url, to: requestDestination)
        .validate()
        .downloadProgress { [weak self] progress in
            print("Progress: \(progress.fractionCompleted)")
        }
        .response { [weak self] responseData in
            
            switch responseData.result {
                
            case .success(_):
                print("Download success")
                
            case .failure(let error):
                
                print("Download failed: ", error.localizedDescription)
                
                if let resumabledata = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
                    print("Resumable Data found: ", resumabledata.count)
                } else {
                    print("No resumable Data")
                }
            }
        }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MBT