How to Download File in Swift

How to download file in swift?

Example downloader class without Alamofire:

class Downloader {
class func load(URL: NSURL) {
let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
let request = NSMutableURLRequest(URL: URL)
request.HTTPMethod = "GET"
let task = session.dataTaskWithRequest(request, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
if (error == nil) {
// Success
let statusCode = (response as NSHTTPURLResponse).statusCode
println("Success: \(statusCode)")

// This is your file-variable:
// data
}
else {
// Failure
println("Failure: %@", error.localizedDescription);
}
})
task.resume()
}
}

This is how to use it in your own code:

class Foo {
func bar() {
if var URL = NSURL(string: "http://www.mywebsite.com/myfile.pdf") {
Downloader.load(URL)
}
}
}

Swift 3 Version

Also note to download large files on disk instead instead in memory. see `downloadTask:

class Downloader {
class func load(url: URL, to localUrl: URL, completion: @escaping () -> ()) {
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = try! URLRequest(url: url, method: .get)

let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Success: \(statusCode)")
}

do {
try FileManager.default.copyItem(at: tempLocalUrl, to: localUrl)
completion()
} catch (let writeError) {
print("error writing file \(localUrl) : \(writeError)")
}

} else {
print("Failure: %@", error?.localizedDescription);
}
}
task.resume()
}
}

How to download a Pdf file in swift and find in file manager

Configure your app so that its files appear in the Files app by adding below lines to your Info.plist file.

UIFileSharingEnabled

LSSupportsOpeningDocumentsInPlace

OR

Just like below using Xcode

Sample Image

Note: Remember that you must be running iOS 11 or above.

Download file with right extension

The issue there is that you are trying to share the temporary file returned. It has a dynamic UTI (Unified Type Identifier). You need to get the url response suggested file name and rename the file.

import UIKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true


extension URL {
var typeIdentifier: String? { (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier }
}


let url = URL(string: "https://i.stack.imgur.com/varL9.jpg")!
URLSession.shared.downloadTask(with: url) { location, response, error in
guard let location = location,
let httpURLResponse = response as? HTTPURLResponse,
httpURLResponse.statusCode == 200 else { return }
let fileName = httpURLResponse.suggestedFilename ?? httpURLResponse.url?.lastPathComponent ?? url.lastPathComponent
let destination = FileManager.default.temporaryDirectory.appendingPathComponent(fileName)
do {
if FileManager.default.fileExists(atPath: destination.path) {
try FileManager.default.removeItem(at: destination)
}
print("location", location.typeIdentifier ?? "no UTI") // location dyn.ah62d4rv4ge81k5pu
try FileManager.default.moveItem(at: location, to: destination)
print("destination", destination.typeIdentifier ?? "no UTI") // destination public.jpeg
} catch {
print(error)
}
}.resume()

Download file from server using Swift

edit/update: Xcode 11.5 • Swift 5.2

import UIKit
import AVFoundation

class ViewController: UIViewController {
var player: AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
let alarm = URL(string: "https://www.ringtonemobi.com/storage/upload/user_id_1/iphone-5-alarm-2016-08-21-01-49-25.mp3")!
do {
try alarm.download(to: .documentDirectory) { url, error in
guard let url = url else { return }
self.player = AVPlayer(url: url)
self.player.play()
}
} catch {
print(error)
}
}
}

import Foundation
extension URL {
func download(to directory: FileManager.SearchPathDirectory, using fileName: String? = nil, overwrite: Bool = false, completion: @escaping (URL?, Error?) -> Void) throws {
let directory = try FileManager.default.url(for: directory, in: .userDomainMask, appropriateFor: nil, create: true)
let destination: URL
if let fileName = fileName {
destination = directory
.appendingPathComponent(fileName)
.appendingPathExtension(self.pathExtension)
} else {
destination = directory
.appendingPathComponent(lastPathComponent)
}
if !overwrite, FileManager.default.fileExists(atPath: destination.path) {
completion(destination, nil)
return
}
URLSession.shared.downloadTask(with: self) { location, _, error in
guard let location = location else {
completion(nil, error)
return
}
do {
if overwrite, FileManager.default.fileExists(atPath: destination.path) {
try FileManager.default.removeItem(at: destination)
}
try FileManager.default.moveItem(at: location, to: destination)
completion(destination, nil)
} catch {
print(error)
}
}.resume()
}
}


Original answer

Xcode 8.3.2 • Swift 3.1

if let audioUrl = URL(string: "http://freetone.org/ring/stan/iPhone_5-Alarm.mp3") {
// create your document folder url
let documentsUrl = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
// your destination file url
let destination = documentsUrl.appendingPathComponent(audioUrl.lastPathComponent)
print(destination)
// check if it exists before downloading it
if FileManager.default.fileExists(atPath: destination.path) {
print("The file already exists at path")
} else {
// if the file doesn't exist
// just download the data from your url
URLSession.shared.downloadTask(with: audioUrl, completionHandler: { (location, response, error) in
// after downloading your data you need to save it to your destination url
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("audio"),
let location = location, error == nil
else { return }
do {
try FileManager.default.moveItem(at: location, to: destination)
print("file saved")
} catch {
print(error)
}
}).resume()
}
}

Download File Using Alamofire 4.0 (Swift 3)

I used to use this statements:

let destination = DownloadRequest.suggestedDownloadDestination(for: .documentDirectory)

Alamofire.download(
url,
method: .get,
parameters: parameters,
encoding: JSONEncoding.default,
headers: nil,
to: destination).downloadProgress(closure: { (progress) in
//progress closure
}).response(completionHandler: { (DefaultDownloadResponse) in
//here you able to access the DefaultDownloadResponse
//result closure
})

For more details read more in Alamofire docs about Migration to 4.0:

Swift: wait for app execution till file downloads ends

You have to make downloadFile really async by using the appropriate async URLSession API. The completion handler API doesn't wait.

func downloadFile (fileOnServer: String, fileOnDevice: URL) async throws {
guard let dataURL = URL(string: fileOnServer) else { throw URLError(.badURL) }
let (dataTempFileUrl, _) = try await URLSession.shared.download(from: dataURL)
try FileManager.default.moveItem(at: dataTempFileUrl, to: fileOnDevice)
}

In the task you have add a do - catch block to handle the error(s)

.task()
{
do {
print ("START downloadFile() ")
try await downloadFile(fileOnServer: htmlLinkForJSON, fileOnDevice: downloadedJSON)
try await downloadFile(fileOnServer: htmlLinkForCategories, fileOnDevice: downloadedCategories)
print ("END downloadFile()")
print ("---------")
print ("Start checkSavedFile()")
checkSavedFile(file: downloadedJSON)
checkSavedFile(file: downloadedCategories)
print ("END checkSavedFile()")
print ("---------")
} catch {
print(error)
}
}


Related Topics



Leave a reply



Submit