iosswiftobjective-cuidocumentinteractioncontroller

Is there a delegate method that gets called before the UIDocumentInteractionController share sheet pop ups


Please can someone help.I would like to add an alert message once a user clicks on the share button on a pdf viewer, i'm using UIDocumentInteractionController to preview the pdf document. and i wanted to know if there are any delegate methods or functions that i can override, where i can add my alert before opening the sharing sheet?[![enter image description here][1]][1]

class ViewController: UIViewController {
    
    var documentController : UIDocumentInteractionController!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction private func buttonTapped(_ sender: Any) {
        
       guard let fileURL = Bundle.main.url(forResource: "infomation", withExtension: "pdf") else {return}
        documentController = UIDocumentInteractionController.init(url: fileURL)
        documentController.delegate = self
        documentController.presentPreview(animated: true)
    }
}

extension ViewController: UIDocumentInteractionControllerDelegate {
    func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
        
        return self
    }
    
    func documentInteractionControllerWillPresentOpenInMenu(_ controller: UIDocumentInteractionController) {
  
    }
    
    func documentInteractionControllerWillPresentOptionsMenu(_ controller: UIDocumentInteractionController) {
    
    }
    
    func documentInteractionController(_ controller: UIDocumentInteractionController, willBeginSendingToApplication application: String?) {
    
    }
}

but none of them get called when i click on the share button, even though i have set the delegate to be my view controller.is there a way that i can do this ?


Solution

  • Explanation:

    There isn't a way to do that without hacking it together by iterating all the sub-views and override the button's action and target.

    One clean way is to create your own preview controller like shown below. If you add the QLPreviewController to UINavigationController, it will automatically create a bottom toolbar which you don't want. To work around this, you add it as a child controller of a regular UIViewController and create a custom navigation bar.

    You can also use the UTI for the UIActivityItem to determine how the item can be shared. I've only implemented the preview and basic sharing capabilities, but the rest should be super easy to do, and at least it's more customizable than UIDocumentInteractionController since you have full control of everything.

    Now for the code that does all of this:

    //
    //  ViewController.swift
    //  CustomDocumentController
    //
    //  Created by brandon on 2022-01-13.
    //
    
    import UIKit
    import QuickLook
    import MobileCoreServices
    import UniformTypeIdentifiers
    
    private class PreviewItem: NSObject, QLPreviewItem {
        var previewItemURL: URL?
        var previewItemTitle: String?
        
        init(title: String, url: URL) {
            super.init()
            
            previewItemURL = url
            previewItemTitle = title
        }
    }
    
    class DocumentInteractionController: UIViewController {
        
        private let url: URL
        
        private lazy var navigationBar: UINavigationBar = {
            let navigationBar = UINavigationBar()
            let navigationItem = UINavigationItem(title: name ?? "Document")
            navigationItem.hidesBackButton = true
            navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(onDone))
            navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(onShare)) //UIImage(systemName: "square.and.arrow.up")
            navigationBar.pushItem(navigationItem, animated: false)
            return navigationBar
        }()
        
        private lazy var previewController: QLPreviewController = {
            let previewController = QLPreviewController()
            previewController.title = name
            previewController.dataSource = self
            previewController.delegate = self
            previewController.reloadData()
            return previewController
        }()
        
        var uti: String? {
            didSet {
                previewController.reloadData()
            }
        }
        
        var name: String? {
            didSet {
                previewController.title = name
                navigationBar.topItem?.title = name
            }
        }
        
        init(url: URL) {
            self.url = url
            super.init(nibName: nil, bundle: nil)
            //super.init(rootViewController: self.previewController)
            self.modalPresentationStyle = .fullScreen
            
            name = (try? url.resourceValues(forKeys: [.localizedNameKey]))?.localizedName
            uti = (try? url.resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
            
            if uti == nil {
                if #available(iOS 15.0, *) {
                    uti = UTType.url.identifier
                } else {
                    uti = String(kUTTypeURL)
                }
            }
        }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
    
            addChild(previewController)
            previewController.didMove(toParent: self)
            
            let separator = UIView()
            separator.backgroundColor = .lightGray
            
            view.addSubview(navigationBar)
            view.addSubview(separator)
            view.addSubview(previewController.view)
            
            NSLayoutConstraint.activate([
                navigationBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
                navigationBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
                navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
                
                separator.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
                separator.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
                separator.topAnchor.constraint(equalTo: navigationBar.bottomAnchor),
                separator.heightAnchor.constraint(equalToConstant: 1.0 / UIScreen.main.scale),
                
                previewController.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
                previewController.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
                previewController.view.topAnchor.constraint(equalTo: separator.bottomAnchor),
                previewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
            ])
            
            [navigationBar, separator, previewController.view].forEach({
                $0?.translatesAutoresizingMaskIntoConstraints = false
            })
            
            navigationBar.barTintColor = previewController.view.backgroundColor
            view.backgroundColor = previewController.view.backgroundColor
        }
    }
    
    extension DocumentInteractionController: QLPreviewControllerDelegate, QLPreviewControllerDataSource {
        func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
            return 1
        }
        
        func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
            return PreviewItem(title: name ?? "Document", url: url)
        }
    }
    
    extension DocumentInteractionController {
        @objc
        private func onDone() {
            self.dismiss(animated: true, completion: nil)
        }
        
        @objc
        private func onShare() {
            let activityViewController = UIActivityViewController(activityItems: [url],
                                                                  applicationActivities: nil)
            
            activityViewController.excludedActivityTypes = [.assignToContact]
            if UIDevice.current.userInterfaceIdiom == .pad {
                activityViewController.popoverPresentationController?.sourceView = self.view
            }
            self.present(activityViewController, animated: true, completion: nil)
        }
    }
    
    class ViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            let url = Bundle.main.url(forResource: "Testing", withExtension: ".md")
            let doc = DocumentInteractionController(url: url!)
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
                self.present(doc, animated: true, completion: nil)
            }
        }
    }
    

    Screenshots:

    Image-1 Image-2