Saving PDF Files with Swift in iOS and display them
Asked Answered
P

8

40

I want to build an app which also includes the possibility to show and save PDFs inside the app and display them (as a FileSystem) within a tableview and open them when I tap on one PDF.

Here are my important questions for that:

1. How do I save a PDF local on my app ( for example if the user can enter a url) and where exactly will it save it ?

2. When saved, how can I show all the local storaged files within a tableview to open them?

Pga answered 6/4, 2015 at 21:14 Comment(1)
Look at the answer below, there you have the solution ;)Pga
F
40

Since several people requested this, here is the equivalent to the first answer in Swift:

//The URL to Save
let yourURL = NSURL(string: "http://somewebsite.com/somefile.pdf")
//Create a URL request
let urlRequest = NSURLRequest(URL: yourURL!)
//get the data
let theData = NSURLConnection.sendSynchronousRequest(urlRequest, returningResponse: nil, error: nil)

//Get the local docs directory and append your local filename.
var docURL = (NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)).last as? NSURL

docURL = docURL?.URLByAppendingPathComponent( "myFileName.pdf")

//Lastly, write your file to the disk.
theData?.writeToURL(docURL!, atomically: true)

Also, since this code uses a synchronous network request, I highly recommend dispatching it to a background queue:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { () -> Void in
    //The URL to Save
    let yourURL = NSURL(string: "http://somewebsite.com/somefile.pdf")
    //Create a URL request
    let urlRequest = NSURLRequest(URL: yourURL!)
    //get the data
    let theData = NSURLConnection.sendSynchronousRequest(urlRequest, returningResponse: nil, error: nil)

    //Get the local docs directory and append your local filename.
    var docURL = (NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)).last as? NSURL

    docURL = docURL?.URLByAppendingPathComponent( "myFileName.pdf")

    //Lastly, write your file to the disk.
    theData?.writeToURL(docURL!, atomically: true)
})

And the answer to second question in Swift:

//Getting a list of the docs directory
let docURL = (NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last) as? NSURL

//put the contents in an array.
var contents = (NSFileManager.defaultManager().contentsOfDirectoryAtURL(docURL!, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions.SkipsHiddenFiles, error: nil))
//print the file listing to the console
println(contents)



Frequently answered 18/7, 2015 at 22:23 Comment(3)
Hi! I tested your code and it works. I can see the path of the file in the console. But where is ,in the device, the Documents folder that I see in the path? What if I want to download the file and then display it? ThanksBibliophile
Hello! I'm glad it worked for you. In terms of absolute paths, I don't know where the app specific Documents directory is on the iPhone. Since Apple intentionally obfuscates the filesystem from developers, you can use the various constants used above to access the specific Documents directoryFrequently
Thanks for the answer! So if I understood, I can't see it in the iPhone by accessing to it from a directory or something else. That's it? And another question please: what if I want to take the cotent (the path) of the latest downloaded pdf? Can you please take a look in my issue please? #40568452 thanks a lot!Bibliophile
C
34

Swift 4.1

 func savePdf(urlString:String, fileName:String) {
        DispatchQueue.main.async {
            let url = URL(string: urlString)
            let pdfData = try? Data.init(contentsOf: url!)
            let resourceDocPath = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last! as URL
            let pdfNameFromUrl = "YourAppName-\(fileName).pdf"
            let actualPath = resourceDocPath.appendingPathComponent(pdfNameFromUrl)
            do {
                try pdfData?.write(to: actualPath, options: .atomic)
                print("pdf successfully saved!")
            } catch {
                print("Pdf could not be saved")
            }
        }
    }

    func showSavedPdf(url:String, fileName:String) {
        if #available(iOS 10.0, *) {
            do {
                let docURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
                let contents = try FileManager.default.contentsOfDirectory(at: docURL, includingPropertiesForKeys: [.fileResourceTypeKey], options: .skipsHiddenFiles)
                for url in contents {
                    if url.description.contains("\(fileName).pdf") {
                       // its your file! do what you want with it!

                }
            }
        } catch {
            print("could not locate pdf file !!!!!!!")
        }
    }
}

// check to avoid saving a file multiple times
func pdfFileAlreadySaved(url:String, fileName:String)-> Bool {
    var status = false
    if #available(iOS 10.0, *) {
        do {
            let docURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
            let contents = try FileManager.default.contentsOfDirectory(at: docURL, includingPropertiesForKeys: [.fileResourceTypeKey], options: .skipsHiddenFiles)
            for url in contents {
                if url.description.contains("YourAppName-\(fileName).pdf") {
                    status = true
                }
            }
        } catch {
            print("could not locate pdf file !!!!!!!")
        }
    }
    return status
}
Caladium answered 15/9, 2018 at 17:9 Comment(0)
E
7

I am giving an example of storing and retrieving a pdf document in iOS. I hope that is what you are looking for.

1. How do I save a PDF local on my app ( for example if the user can enter a url) and where exactly will it save it ?

// the URL to save
NSURL *yourURL = [NSURL URLWithString:@"http://yourdomain.com/yourfile.pdf"];
// turn it into a request and use NSData to load its content
NSURLRequest *request = [NSURLRequest requestWithURL:result.link];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

// find Documents directory and append your local filename
NSURL *documentsURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
documentsURL = [documentsURL URLByAppendingPathComponent:@"localFile.pdf"];

// and finally save the file
[data writeToURL:documentsURL atomically:YES];

2. When saved, how can I show all the local storaged files within a tableview to open them?

You can check that the file has downloaded, or you can list the Documents directory like so:

// list contents of Documents Directory just to check
NSURL *documentsURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

NSArray *contents = [[NSFileManager defaultManager]contentsOfDirectoryAtURL:documentsURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles error:nil];

NSLog(@"%@", [contents description]);
Edo answered 6/4, 2015 at 21:38 Comment(4)
Thanks for the quick reply! I understand and will try to translate it to swift as soon as I can, or do you even know how to make it with Swift?Pga
I tried it but I couldn't do it. I still have some problems of which datatypes to use.Pga
can u put swift code here, it would be so helpfull, thanks in advance :)Eng
@Pga can you put the swift code please? Thanks a lot :)Calamint
A
2

Downloading and displaying PDF in Webview using Swift.

let request = URLRequest(url:  URL(string: "http://<your pdf url>")!)
        let config = URLSessionConfiguration.default
        let session =  URLSession(configuration: config)
        let task = session.dataTask(with: request, completionHandler: {(data, response, error) in
            if error == nil{
                if let pdfData = data {
                   let pathURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("\(filename).pdf")
                    do {
                        try pdfData.write(to: pathURL, options: .atomic)
                    }catch{
                        print("Error while writting")
                    }

                    DispatchQueue.main.async {
                        self.webView.delegate = self
                        self.webView.scalesPageToFit = true
                        self.webView.loadRequest(URLRequest(url: pathURL))
                    }
                }
            }else{
                print(error?.localizedDescription ?? "")
            }
        }); task.resume()
Amphibian answered 12/3, 2019 at 9:7 Comment(4)
Sorry for that, definitely add some explanation.Amphibian
And where is that explanation?Eulalie
what is "fileName"Afternoons
@BIJUC Where the PDF is save in iPhone?Johniejohnna
H
1

If you want to store file in Files app add`

NSURL *url = [NSURL URLWithString:@"PATH TO PDF"];
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithURL:url inMode:UIDocumentPickerModeExportToService];
[documentPicker setDelegate:self];
[self presentViewController:documentPicker animated:YES completion:nil];

And here are delegate methods

- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
}

- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls {

}

It will open a DocumentPickerViewController where you can choose a folder to store the file.

Requires iOS11 or later.

Hemorrhoid answered 21/1, 2020 at 13:49 Comment(0)
E
0

if you want to print the PDF data wich is in the directoryURL then use :

let printInfo = NSPrintInfo.shared
        let manager = FileManager.default
        do{
            let directoryURL = try manager.url(for: .documentDirectory, in:.userDomainMask, appropriateFor:nil, create:true)
            let docURL = NSURL(string:"LadetagMahlzeiten.pdf", relativeTo:directoryURL)

            let pdfDoc =  PDFDocument.init(url: docURL! as URL)

            let page = CGRect(x: 0, y: 0, width: 595.2, height: 1841.8) // A4, 72 dpi

            let pdfView : PDFView = PDFView.init(frame: page)

            pdfView.document = pdfDoc

            let operation: NSPrintOperation = NSPrintOperation(view: pdfView, printInfo: printInfo)
            operation.printPanel.options.insert(NSPrintPanel.Options.showsPaperSize)
            operation.printPanel.options.insert(NSPrintPanel.Options.showsOrientation)

            operation.run()
        }catch{

        }
Episternum answered 24/4, 2018 at 11:32 Comment(0)
S
0
        //savePdf(urlString:url, fileName:fileName)
        let urlString = "here String with your URL"
        let url = URL(string: urlString)
        let fileName = String((url!.lastPathComponent)) as NSString
        // Create destination URL
        let documentsUrl:URL =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL!
        let destinationFileUrl = documentsUrl.appendingPathComponent("\(fileName)")
        //Create URL to the source file you want to download
        let fileURL = URL(string: urlString)
        let sessionConfig = URLSessionConfiguration.default
        let session = URLSession(configuration: sessionConfig)
        let request = URLRequest(url:fileURL!)
        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("Successfully downloaded. Status code: \(statusCode)")
                }
                do {
                    try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
                    do {
                        //Show UIActivityViewController to save the downloaded file
                        let contents  = try FileManager.default.contentsOfDirectory(at: documentsUrl, includingPropertiesForKeys: nil, options: .skipsHiddenFiles)
                        for indexx in 0..<contents.count {
                            if contents[indexx].lastPathComponent == destinationFileUrl.lastPathComponent {
                                let activityViewController = UIActivityViewController(activityItems: [contents[indexx]], applicationActivities: nil)
                                self.present(activityViewController, animated: true, completion: nil)
                            }
                        }
                    }
                    catch (let err) {
                        print("error: \(err)")
                    }
                } catch (let writeError) {
                    print("Error creating a file \(destinationFileUrl) : \(writeError)")
                }
            } else {
                print("Error took place while downloading a file. Error description: \(error?.localizedDescription ?? "")")
            }
        }
        task.resume()
    }
Status answered 18/3, 2020 at 21:12 Comment(2)
With this solution can I show all the local storage files within a tableview?Wendalyn
It will only try to save, if the file already exists will throw an errorStatus
C
0

For Swift 5 and up Version: Save PDF base64 String Data to Document Directory

Create a Folder where you want to save PDF file with Name

   fileprivate func getFilePath() -> URL? {
            let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            let directoryURl = documentDirectoryURL.appendingPathComponent("Invoice", isDirectory: true)
            
            if FileManager.default.fileExists(atPath: directoryURl.path) {
                return directoryURl
            } else {
                do {
                    try FileManager.default.createDirectory(at: directoryURl, withIntermediateDirectories: true, attributes: nil)
                    return directoryURl
                } catch {
                    print(error.localizedDescription)
                    return nil
                }
            }
        }

Write PDF base64 String Data to Document Directory

fileprivate func saveInvoice(invoiceName: String, invoiceData: String) {
    
    guard let directoryURl = getFilePath() else {
        print("Invoice save error")
        return }
    
    let fileURL = directoryURl.appendingPathComponent("\(invoiceName).pdf")
    
    guard let data = Data(base64Encoded: invoiceData, options: .ignoreUnknownCharacters) else {
        print("Invoice downloaded Error")
        self.hideHUD()
        return
    }
    
    do {
        try data.write(to: fileURL, options: .atomic)
        print("Invoice downloaded successfully")
    } catch {
        print(error.localizedDescription)
    }
}
Cally answered 3/3, 2021 at 11:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.