Search code examples
iosswift

Opening a PDF with UIDocumentInteractionController URL error


The app needs to create a URL to pass into a UIDocumentInteractionController that will present the user with options to share the file. It's a PDF that is downloaded over the network and confirmed as being in place.

let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let filePath = documentsPath.appendingPathComponent("documents/\(self.filename!)").path
let fileURL = URL(fileURLWithPath: filePath)

This is where the PDF is stored after being downloaded.

let documentController: UIDocumentInteractionController = UIDocumentInteractionController.init(url: fileURL)
documentController.uti = "com.adobe.pdf"
documentController.presentOpenInMenu(from: CGRect(x: 0, y: 0, width: self.container.frame.width, height: self.container.frame.height), in: self.container, animated: true)

This opens up the menu with the sharing options but when trying to select an app to open the PDF, the following error occurs:

Could not instantiate class NSURL. Error: Error Domain=NSCocoaErrorDomain Code=4864 "The URL archive of type “public.url” contains invalid data." UserInfo={NSDebugDescription=The URL archive of type “public.url” contains invalid data.}

After having confirmed the document is where it should be, when printing the fileURL, it's the following:

file:///var/mobile/Containers/Data/Application/3296B736-4DFB-4F62-9B05-C800D574982B/Documents/documents/77351848-68816600-1626168959.pdf

I have searched high and low for an answer to this and I believe it's more linked to the URL than the UIDocumentInteractionController itself.

Any advice would be enormously appreciated.


Solution

  • Swift 5 Implementation(Xcode 12.5):

    class VC1: UIViewController {
        
        var pdfURL: URL?
        var documentInteractionController:UIDocumentInteractionController!
        
        override func viewDidLoad() {
            super.viewDidLoad()
        }
        
        @IBAction func downloadAction(_ sender: Any) {
            self.downloadPDF()
        }
        
        func downloadPDF() {
            guard let url = URL(string: "https://file-examples-com.github.io/uploads/2017/10/file-sample_150kB.pdf") else { return }
            
            let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
            
            let downloadTask = urlSession.downloadTask(with: url)
            downloadTask.resume()
        }
        
        func showPDF(url: URL) {
            documentInteractionController = UIDocumentInteractionController(url: url)
            documentInteractionController.delegate = self
            
            DispatchQueue.main.async { [self] in
                documentInteractionController.presentPreview(animated: true)
            }
        }
    }
    
    extension VC1: UIDocumentInteractionControllerDelegate {
        func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
               return self
           }
        
        func documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) {
            print("Dismissed!!!")
            documentInteractionController = nil
        }
    }
    
    extension VC1:  URLSessionDownloadDelegate {
        func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
            guard let url = downloadTask.originalRequest?.url else { return }
            let documentsPath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
            let destinationURL = documentsPath.appendingPathComponent(url.lastPathComponent)
            try? FileManager.default.removeItem(at: destinationURL)
            do {
                try FileManager.default.copyItem(at: location, to: destinationURL)
                self.pdfURL = destinationURL
                showPDF(url: destinationURL)
            } catch let error {
                print("Error: \(error.localizedDescription)")
            }
        }
    }