How to use UIDocumentInteractionController?
Asked Answered
C

4

7

I have created a program that loads PDF files. I want when the user is editing that they can publish the file anywhere in PDF format.

Do I use UIDocumentInteractionController or use UIActivityViewController?

Here is the code:

import UIKit
import PDFKit

@available(iOS 11.0, *)
@available(iOS 11.0, *)

class PDFViewControllerEN: UIViewController {
    var document: UIDocumentInteractionController!

    override func viewDidLoad() {
        super.viewDidLoad()
        // retrieve URL to file in main bundle`
    }

    @IBOutlet var pdfview: UIView!

    @IBAction func share(_ sender: UIButton) {
    }

    @IBAction func doAction2(_ sender: UIBarButtonItem) {
        document.presentOptionsMenu(from: view.bounds, in: view, animated: true)
    }

    override func viewWillAppear(_ animated: Bool) {
        //Here you are going to display your PdfController
        //PDFController that is seprate class you had created to show pdf file being opened
        //i.e

        //check which button was being selected
        switch ButtonSelected.Tag {
        case 0:
            var document: UIDocumentInteractionController = {
                let pdfView = PDFView(frame: UIScreen.main.bounds)

                let url = Bundle.main.url(forResource: "EN1", withExtension: "pdf")

                let vc = UIDocumentInteractionController(url: url!)
                pdfView.document = PDFDocument(url: url!)
                view.addSubview(pdfView)
                vc.delegate = self

                return vc
            }()
            //  document.presentPreview(animated: true)
            break
        case 1:
            //here control when you selected button with tag 0
            //here need to open pdf AR2
            //set Frame here all bounds

            var document: UIDocumentInteractionController = {
                let pdfView = PDFView(frame: UIScreen.main.bounds)

                let url = Bundle.main.url(forResource: "EN2", withExtension: "pdf")

                let vc = UIDocumentInteractionController(url: url!)
                pdfView.document = PDFDocument(url: url!)
                view.addSubview(pdfView)
                vc.delegate = self

                return vc
            }()
            break
        case 2:
            //here control when you selected button with tag 0
            //here need to open pdf AR2
            //set Frame here all bounds

            var document: UIDocumentInteractionController = {
                let pdfView = PDFView(frame: UIScreen.main.bounds)

                let url = Bundle.main.url(forResource: "EN3", withExtension: "pdf")

                let vc = UIDocumentInteractionController(url: url!)
                pdfView.document = PDFDocument(url: url!)
                view.addSubview(pdfView)
                vc.delegate = self

                return vc
            }()
            break
        default:
            //Error Case
            print("No tag Value Available")
        }
    }
}

@available(iOS 11.0, *)
extension PDFViewControllerEN: UIDocumentInteractionControllerDelegate {
    func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
        return self
    }
}
Crossfertilize answered 30/1, 2018 at 6:40 Comment(0)
A
7

Using UIDocumentInteractionController is quite easy. You just need to know the url of your file, then you present the menu:

/// Needs to be global, otherwise the controller will be destroyed when the file is handed over to target application
var documentInteractionController: UIDocumentInteractionController!

class MyViewController: UIViewController {

    var url: URL

    ...

    @IBAction func share(_ sender: UIBarButtonItem) {
        documentInteractionController = UIDocumentInteractionController()
        documentInteractionController.url = url
        documentInteractionController.uti = url.uti
        documentInteractionController.presentOptionsMenu(from: sender, animated: true)
    }

}

extension URL {

    var uti: String {
        return (try? self.resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier ?? "public.data"
    }

}
Agree answered 30/1, 2018 at 12:13 Comment(3)
i got error Class 'PDFViewControllerEN' has no initializersCrossfertilize
i got this error when i clicked the button libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)Crossfertilize
My answer was meant as an example for how to call the UIDocumentInteractionController inside a ViewController. You cannot copy the code without initialization and additional functions for the ViewController. Please provide your full code for help.Agree
B
7

I have tried and explained in detail about UIDocumentInteractionController. Refer this link if you want to check the details.

https://medium.com/if-let-swift-programming/managing-files-in-ios-dfcdfdc1f426

Code

extension ViewController {
    /// This function will set all the required properties, and then provide a preview for the document
    func share(url: URL) {
        documentInteractionController.url = url
        documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
        documentInteractionController.name = url.localizedName ?? url.lastPathComponent
        documentInteractionController.presentPreview(animated: true)
    }

    /// This function will store your document to some temporary URL and then provide sharing, copying, printing, saving options to the user
    func storeAndShare(withURLString: String) {
        guard let url = URL(string: withURLString) else { return }
        /// START YOUR ACTIVITY INDICATOR HERE
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard let data = data, error == nil else { return }
            let tmpURL = FileManager.default.temporaryDirectory
                .appendingPathComponent(response?.suggestedFilename ?? "fileName.png")
            do {
                try data.write(to: tmpURL)
            } catch {
                print(error)
            }
            DispatchQueue.main.async {
                /// STOP YOUR ACTIVITY INDICATOR HERE
                self.share(url: tmpURL)
            }
            }.resume()
    }
}

extension ViewController: UIDocumentInteractionControllerDelegate {
    /// If presenting atop a navigation stack, provide the navigation controller in order to animate in a manner consistent with the rest of the platform
    func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
        guard let navVC = self.navigationController else {
            return self
        }
        return navVC
    }
}

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

Calling

@IBAction func showOptionsTapped(_ sender: UIButton) {
    /// Passing the remote URL of the file, to be stored and then opted with mutliple actions for the user to perform
    storeAndShare(withURLString: "https://images5.alphacoders.com/581/581655.jpg")
}

Note

https://www.bignerdranch.com/blog/working-with-the-files-app-in-ios-11/

Before your files can appear in the Files app, you must indicate that your app supports Open in Place and File Sharing Enabled. These options are configured using keys in your Info.plist file.

The first key is UIFileSharingEnabled, which enables iTunes sharing of files in your Documents folder.

The second key is LSSupportsOpeningDocumentsInPlace, which grants the local file provider access to files in your Documents folder.

Add these keys to your Info.plist and set their values to YES.

Britain answered 24/4, 2018 at 9:24 Comment(7)
super explanation @BritainMockery
Glad you found it useful @MockeryBritain
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewSkijoring
@MarkRotteveel Thanks, added.Britain
How would you handle a temporary file? I figured documentInteractionControllerDidDismissOptionsMenu() is called also when you, say share in Messages, cancel that, and the UIDocumentInteractionController shows again. There is no method in the delegate protocol that is called when the interaction controller is dismissed for good. I wonder when a temporary file could be removed.Warila
doing this can get your app rejected if you store other app related files thereGenoa
@Genoa where are we storing other app’s data ? Can you please elaborateBritain
F
4

Silly case but might help to someone.

To anyone who can't save files check if your controller is alive. My problem was that my UIDocumentInteractionController was destroyed after it was closed.

Here's how my function looked like:

private func showDocumentInteractionController(url: URL) {
     let documentInteractionController = UIDocumentInteractionController(url: url)
     documentInteractionController.presentOptionsMenu(from: view.frame, in: view, animated: true)
     documentInteractionController.delegate = self
}

The fix is to make sure that UIDocumentInteractionController is alive after it closes:

class ViewController: UIViewController, UIDocumentInteractionControllerDelegate {
    private let documentInteractionController = UIDocumentInteractionController()

    private func showDocumentInteractionController(url: URL) {
       documentInteractionController.url = url
       documentInteractionController.presentOptionsMenu(from: view.frame, in: view, animated: true)
       documentInteractionController.delegate = self
    }
}
Fajardo answered 26/8, 2021 at 11:5 Comment(0)
Y
0

This should work which shows a PDF file:

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [self] in
            guard let path = Bundle.main.url(forResource: "YOUR_PDF_FILE_NAME_WITHOUT_EXTENSION", withExtension: "pdf") else { return }
            let documentInteractionController = UIDocumentInteractionController.init(url: path)
            documentInteractionController.delegate = self
            documentInteractionController.presentPreview(animated: true)
        }

    }
}

extension ViewController: UIDocumentInteractionControllerDelegate {
    func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
        return self
    }
}
Yoho answered 7/9, 2021 at 15:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.