본문 바로가기
Xcode/Swift - PlayGround

PlayGround) URLSessionDownload를 이용해서 PDF 파일 다운로드

by 후르륵짭짭 2021. 12. 26.
728x90
반응형

안녕하세요. 후르륵짭짭입니다.

그냥 호기심으로 어떻게 하면 API로 다운로드 상태를 확인 할 수 있지???

로 시작해서 글을 정리 하려고 합니다.

참고로 이미 만들어져 있는 raywenderlich.com을 이용해서 Playground에 연습한거라서

크게 정리할 생각은 없습니다. 왜냐하면 저기가 더 자세하게 작성 되어 있기 때문입니다.

다음에는 URLSession이 아니라 Alamofire로 하는 방법을 자세하게 작성 하도록 하겠습니다.

 

** NetworkRepository ** 

class NetworkRepository: NSObject, URLSessionDelegate {
    var downloadSession : URLSession?

    override init(){
        super.init()
        self.downloadSession = setURLSession()
    }

    private func setURLSession() -> URLSession {
        let configuration = URLSessionConfiguration.default
        return URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    }

    func downloadTask(url : URL){
        let task = downloadSession?.downloadTask(with: url)
        task?.resume()
    }

}

1. 기본적인 URLSession을 생성해줍니다.

2.그리고 downloadTask 함수를 통해서 다운로드 함수를 정의해줍니다.

-- URLSessionDelegate을 해주셔야합니다. --

 

** URLSessionDownloadDelegate ** 

extension NetworkRepository : URLSessionDownloadDelegate {
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        print("Finished Downloading to \(location)")
        //location은 임시적인 위치입니다. 다운 받고 함수가 끝나면 해당 파일은 사라집니다.

        guard let sourcURL = downloadTask.originalRequest?.url else {return}

        print("Source URL : \(sourcURL)")

        let fileManager = FileManager.default
        let documentURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let destinationURL = documentURL.appendingPathComponent(sourcURL.lastPathComponent)
        print("Destination URL : " ,destinationURL)

        try? fileManager.removeItem(at: destinationURL)

        do{
            try fileManager.copyItem(at: location, to: destinationURL)
        }
        catch let error {
            print("Could not copy file to disk: \(error.localizedDescription)")
        }
    }
    
    ....
    
  }

1. NetworkRepository에 URLSessionDownloadDelegate를 해주시고 

urlSession - session: downloadTask: didFinishDownloadingTo:를 해줍니다.

이 함수는 다운로드가 완료하면 수행되는 함수 입니다.

그래서 이 함수 부분에 (1)파일을 저장할 위치 를 정의 해줬습니다.

-- location은 임시적인 위치입니다. 다운 받고 함수가 끝나면 해당 파일은 사라집니다. --

 

** 현재 파일 다운로드 상태 추적하기 ** 

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {

        let currentProgress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
        let totalSize = ByteCountFormatter.string(fromByteCount: totalBytesExpectedToWrite, countStyle: .file)

        print("current Progress : \(currentProgress) / totalSize : \(totalSize)")

    }

해당 함수는 URLSessionDownloadDelegate 에 있는 함수 입니다.

(1) totalBytesWritten은 현재 다운 받은 정도

(2) totalBytesExpectedToWrite은 다운 받아야하는 양

을 의미합니다.

ByteCountFormatter.string(fromByteCount: totalBytesExpectedToWrite, countStyle: .file)

해당 코드는 Int의 값을 Byte로 되어있는 원하는 타입의 형태로 사용자가 쉽게 볼 수 있도록 변형 해줍니다.

 

** 호출 **

class TestView {

    let repository = NetworkRepository()

    init(){

        if let url = URL(string: "https://file-examples-com.github.io/uploads/2017/10/file-example_PDF_1MB.pdf") {
            repository.downloadTask(url: url)
        }

    }
}

let test = TestView()

저는 그냥 간단하게 다음과 같이 호출 했습니다.

 

** 결과 **

current Progress : 0.0022347881 / totalSize : 1 MB
current Progress : 0.040562987 / totalSize : 1 MB
current Progress : 0.04452976 / totalSize : 1 MB
current Progress : 0.04716564 / totalSize : 1 MB
current Progress : 0.049810153 / totalSize : 1 MB
current Progress : 0.05245467 / totalSize : 1 MB
current Progress : 0.055099186 / totalSize : 1 MB
current Progress : 0.0577437 / totalSize : 1 MB
current Progress : 0.060388215 / totalSize : 1 MB
current Progress : 0.20382822 / totalSize : 1 MB
current Progress : 0.4237356 / totalSize : 1 MB
current Progress : 0.64445853 / totalSize : 1 MB
current Progress : 0.8957911 / totalSize : 1 MB
current Progress : 1.0 / totalSize : 1 MB
Finished Downloading to file:///Users/taesooyoon/Library/Developer/XCPGDevices/AD3ACB57-447C-4B32-A551-8CAA21B75ABD/data/Containers/Data/Application/67BDE4C2-1CE4-4049-82DE-DE7ED56D7386/tmp/CFNetworkDownload_uCzv0c.tmp
Source URL : https://file-examples-com.github.io/uploads/2017/10/file-example_PDF_1MB.pdf
Destination URL :  file:///Users/taesooyoon/Library/Developer/XCPGDevices/AD3ACB57-447C-4B32-A551-8CAA21B75ABD/data/Containers/Data/Application/67BDE4C2-1CE4-4049-82DE-DE7ED56D7386/Documents/file-example_PDF_1MB.pdf

 

** 코드 ** 

더보기
import UIKit

class NetworkRepository: NSObject, URLSessionDelegate {
    var downloadSession : URLSession?

    override init(){
        super.init()
        self.downloadSession = setURLSession()
    }

    private func setURLSession() -> URLSession {
        let configuration = URLSessionConfiguration.default
        return URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
    }

    func downloadTask(url : URL){
        let task = downloadSession?.downloadTask(with: url)
        task?.resume()
    }

}

extension NetworkRepository : URLSessionDownloadDelegate {
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        print("Finished Downloading to \(location)")

        guard let sourcURL = downloadTask.originalRequest?.url else {return}

        print("Source URL : \(sourcURL)")

        let fileManager = FileManager.default
        let documentURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
        let destinationURL = documentURL.appendingPathComponent(sourcURL.lastPathComponent)
        print("Destination URL : " ,destinationURL)

        try? fileManager.removeItem(at: destinationURL)

        do{
            try fileManager.copyItem(at: location, to: destinationURL)
        }
        catch let error {
            print("Could not copy file to disk: \(error.localizedDescription)")
        }
    }

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {

        let currentProgress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
        let totalSize = ByteCountFormatter.string(fromByteCount: totalBytesExpectedToWrite, countStyle: .file)

        print("current Progress : \(currentProgress) / totalSize : \(totalSize)")

    }

}



class TestView {

    let repository = NetworkRepository()

    init(){

        if let url = URL(string: "https://file-examples-com.github.io/uploads/2017/10/file-example_PDF_1MB.pdf") {
            repository.downloadTask(url: url)
        }

    }
}

let test = TestView()

 

참고 사이트 : 

 - 강의 사이트

https://www.raywenderlich.com/3244963-urlsession-tutorial-getting-started

 

URLSession Tutorial: Getting Started

In this URLSession tutorial, you’ll learn how to create HTTP requests as well as implement background downloads that can be both paused and resumed.

www.raywenderlich.com

 - 한글 번역 사이트 

https://o-o-wl.tistory.com/50

 

URLSession Tutorial: Getting Started 번역본

URLSession Tutorial: Getting Started https://www.raywenderlich.com/3244963-urlsession-tutorial-getting-started 서버로 부터 데이터를 가져오거나 우리의 소셜 미디어 상태를 업데이트하거나, 디스크로 리모..

o-o-wl.tistory.com

 - 파일URL로 파일 사이즈 구하기

https://www.codegrepper.com/code-examples/swift/swift+file+size+from+url 

 

swift file size from url Code Example

do { let resources = try url.resourceValues(forKeys:[.fileSizeKey]) let fileSize = resources.fileSize! print ("\(fileSize)") } catch { print("Error: \(error)") }

www.codegrepper.com

 - 파일URL로 파일 사이즈 구하기2

https://nemecek.be/blog/22/how-to-get-file-size-using-filemanager-formatting

 

How to get file size using FileManager + formatting

Learn how to get file size URL and also how to format it to human-readable string by special formatter.

nemecek.be

 - HTTP Get의 파일 사이즈 구하기 

https://gist.github.com/fethica/3ad09bcbc56ace668d9bb96ad15224a7

 

[Swift] Get the size (ContentLength) of an http remote file

[Swift] Get the size (ContentLength) of an http remote file - fetchContentLength.swift

gist.github.com

 

728x90
반응형

댓글