Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PDFKit's PDFDocument init(url: URL) does not work with HTTPS

Tags:

ios

swift

ios11

When I try to use PDFDocument.init(url: ), I noticed that it worked with http but not with https URLs. Does anyone know why?

import PDFKit

let httpURL = URL(string: "http://www.axmag.com/download/pdfurl-guide.pdf")!
let doc1 = PDFDocument(url: httpURL) //makes a PDFDocument

let httpsURL = URL(string: "https://www.gnu.org/s/libmicrohttpd/tutorial.pdf")!
let doc2 = PDFDocument(url: httpsURL) //nil
like image 399
72A12F4E Avatar asked Aug 16 '17 15:08

72A12F4E


2 Answers

@IBOutlet var pdfView: PDFView!

var pdfDOC: PDFDocument!

 override func viewDidLoad() {
        super.viewDidLoad()
        downloadPDF()
    }

  func downloadPDF(){
        let urlString = "https://www.tutorialspoint.com/swift/swift_tutorial.pdf"
        guard let url = URL(string: urlString) else {return}
        do{
            let data = try Data(contentsOf: url)
            pdfDOC = PDFDocument(data: data)
            pdfView.displayMode = .singlePageContinuous
            pdfView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
            pdfView.displaysAsBook = true
            pdfView.displayDirection = .vertical
            pdfView.document = pdfDOC
            pdfView.autoScales = true
            pdfView.maxScaleFactor = 4.0
            pdfView.minScaleFactor = pdfView.scaleFactorForSizeToFit
        }catch let err{
            print(err.localizedDescription)
        }
    }
like image 158
Jayesh G Tejwani Avatar answered Oct 05 '22 23:10

Jayesh G Tejwani


At first glance, this appears to be kind of a common problem in the Cocoa frameworks; many APIs take URLs, but in many cases, it's not clear what schemes they will accept. Some only take file URLs, some only take HTTP, some take HTTP, and HTTPS, and the documentation often doesn't say anything about which is going to be the case. It's often a good assumption that if the documentation doesn't say otherwise, the API probably only accepts file: URLs.

However, when you look a little deeper, it's not as much of a problem as it appears at first glance. In your case, you can work around the problem trivially by using Data's try init(contentsOf:), which does support HTTPS, and then initializing your PDFDocument from that, but this isn't actually the best way to go about it. What I'd actually recommend doing instead would be to use an asynchronous API like URLSession to load the PDF data from the server. The reason I suggest this is that loading data from the network can take time, especially with PDF files which can sometimes be quite large, and if you just try to load the file synchronously on the main thread, you'll block it and make your app appear as if it is locked up. By loading the PDF data asynchronously, you can provide progress information for your user, along with a way to cancel the operation, and if something goes wrong, like the network going down in the middle of the download, you can handle that error in a sensible way. Once the data's all downloaded, you can then use the resulting Data object to initialize a PDFDocument.

So to answer your question, my guess as to why PDFDocument doesn't support HTTPS is because a synchronous initializer like this isn't the recommended way to load something over a network, and thus, putting a lot of work into designing it for that purpose was not a priority.

Here is a link to Apple's recommendation that your networking be asynchronous: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010220-CH12-SW3

like image 21
Charles Srstka Avatar answered Oct 06 '22 00:10

Charles Srstka