Search code examples
iosswiftswift3alamofire

How do I download a file in Alamofire 4 and save to the Documents directory?


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?


Solution

  • 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.