I'm trying to use Alamofire4
for Swift3
. I need to download .mp3
files and save them to the Documents
directory. Current code is like so:
func downloadAudioFromURL(url: String, completion: ((_ status: ResponseStatus, _ audioLocalURL: URL?) -> Void)?) {
let fileManager = FileManager.default
let directoryURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let audioFullURL = String.ensureFullURLPath(url)
alamoManager.download(audioFullURL)
.validate { request, response, temporaryURL, destinationURL in
var pathComponent = response.suggestedFilename!
if pathComponent == "m4a.mp4" {
// Due to the old Android audio files without a filename
// Assign a unique name so audio files don't overwrite each other
pathComponent = "\(NSUUID().uuidString).mp4"
}
let localURL = directoryURL.appendingPathComponent(pathComponent)
if response.statusCode == 200 {
completion?(.success, localURL)
} else {
completion?(.failure, nil)
}
return .success
}
.responseJSON { response in
debugPrint(response)
print(response.temporaryURL)
print(response.destinationURL)
}
}
However I can't actually access the files from the localURL
after saving. I have also noticed that the localURL
will be exactly the same for different files I try to download (maybe they are overwriting?). E.g: file:///Users/testuser/Library/Developer/CoreSimulator/Devices/D4254AEA-76DD-4F01-80AF-F1AF3BE8A204/data/Containers/Data/Application/29755154-DD21-4D4C-B340-6628607DC053/Documents/file1.mp3
Any ideas what I am doing wrong here?
Edited my code to look like this:
func downloadAudioFromURL(url: String, completion: ((_ status: ResponseStatus, _ audioLocalURL: URL?) -> Void)?) {
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
documentsURL.appendPathComponent("Audiofile.mp3")
return (documentsURL, [.removePreviousFile])
}
Alamofire.download(url, to: destination).response { response in
if let localURL = response.destinationURL {
completion?(.success, localURL)
} else {
completion?(.failure, nil)
}
}
}
How would I check for m4a.mp4 though?
Swift 5 - Alamofire 5.1. This is the approach.
let destination: DownloadRequest.Destination = { _, _ in
let documentsURL = FileManager.default.urls(for: .picturesDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendingPathComponent("image.png")
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
AF.download("https://httpbin.org/image/png", to: destination).response { response in
debugPrint(response)
if response.error == nil, let imagePath = response.fileURL?.path {
let image = UIImage(contentsOfFile: imagePath)
}
}
Why are you performing .validate
? You are not storing any data after download in your current code.
Alamofire allows you to store a file directly after download:
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let fileURL = documentsURL.appendPathComponent("pig.png")
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(urlString, to: destination).response { response in
print(response)
if response.result.isSuccess, let imagePath = response.destinationURL?.path {
let image = UIImage(contentsOfFile: imagePath)
}
}
And by the way, the download path you are providing in the download
method, is the local URL to the Documents directory and not a URL of a server.
Swift 3.x and Alamofire 4.x version
Well certainly the Alamofire
example posted by Alamofire itself has bugs. Since fileURL
returns Void
it can't be used as a parameter in return statement.
Also remove .createIntermediateDirectories
from option list of return statement if you don't want any Directories for the file you downloaded
EDIT
If you want to know the type of file, simply grab the last component part and convert String
to NSString
as NSString
have these functionalities.
//audioUrl should be of type URL
let audioFileName = String((audioUrl?.lastPathComponent)!) as NSString
//path extension will consist of the type of file it is, m4a or mp4
let pathExtension = audioFileName.pathExtension
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
// the name of the file here I kept is yourFileName with appended extension
documentsURL.appendPathComponent("yourFileName."+pathExtension)
return (documentsURL, [.removePreviousFile])
}
Alamofire.download("yourAudioUrl", to: destination).response { response in
if response.destinationURL != nil {
print(response.destinationURL!)
}
}
Output is
file:///Users/rajan/Library/Developer/CoreSimulator/Devices/92B4AB6E-92C0-4864-916F-9CB8F9443014/data/Containers/Data/Application/781AA5AC-9BE7-46BB-8DD9-564BBB343F3B/Documents/yourFileName.mp3
which is the actual path of your file where it is stored.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With