How to display remote document using QLPreviewController in swift

后端 未结 2 951
别跟我提以往
别跟我提以往 2020-11-30 14:24

I am using QLPreviewController to preview documents. But i do not know how to display document stored on a server.

相关标签:
2条回答
  • 2020-11-30 14:47

    You can't. QuickLook only works for local resource files. You would need to download the data asynchronously first, save it to the document directory or to a temporary folder and present the QLPreviewController from the main thread when finished:

    edit/update:

    Xcode 11.3.1 • Swift 5.1


    ViewController.swift

    import UIKit
    import QuickLook
    
    class ViewController: UIViewController, QLPreviewControllerDelegate, QLPreviewControllerDataSource {
        let previewController = QLPreviewController()
        var previewItems: [PreviewItem] = []
        override func viewDidLoad() {
            super.viewDidLoad()
            let url = URL(string:"https://www.adobe.com/support/products/enterprise/knowledgecenter/media/c4611_sample_explain.pdf")!
            quickLook(url: url)
        }
        func numberOfPreviewItems(in controller: QLPreviewController) -> Int { previewItems.count }
        func quickLook(url: URL) {
            URLSession.shared.dataTask(with: url) { data, response, error in
                guard let data = data, error == nil else {
                    //  in case of failure to download your data you need to present alert to the user
                    self.presentAlertController(with: error?.localizedDescription ?? "Failed to download the pdf!!!")
                    return
                }
                // you neeed to check if the downloaded data is a valid pdf
                guard
                    let httpURLResponse = response as? HTTPURLResponse,
                    let mimeType = httpURLResponse.mimeType,
                    mimeType.hasSuffix("pdf")
                else {
                    print((response as? HTTPURLResponse)?.mimeType ?? "")
                    self.presentAlertController(with: "the data downloaded it is not a valid pdf file")
                    return
                }
                do {
                    // rename the temporary file or save it to the document or library directory if you want to keep the file
                    let suggestedFilename = httpURLResponse.suggestedFilename ?? "quicklook.pdf"
                    var previewURL = FileManager.default.temporaryDirectory.appendingPathComponent(suggestedFilename)
                    try data.write(to: previewURL, options: .atomic)   // atomic option overwrites it if needed
                    previewURL.hasHiddenExtension = true
                    let previewItem = PreviewItem()
                    previewItem.previewItemURL = previewURL
                    self.previewItems.append(previewItem)
                    DispatchQueue.main.async {
                        UIApplication.shared.isNetworkActivityIndicatorVisible = false
                        self.previewController.delegate = self
                        self.previewController.dataSource = self
                        self.previewController.currentPreviewItemIndex = 0
                        self.present(self.previewController, animated: true)
                     }
                } catch {
                    print(error)
                    return
                }
            }.resume()
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
        }
        func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem { previewItems[index] }
        func presentAlertController(with message: String) {
             // present your alert controller from the main thread
            DispatchQueue.main.async {
                UIApplication.shared.isNetworkActivityIndicatorVisible = false
                let alert = UIAlertController(title: "Alert", message: message, preferredStyle: .alert)
                alert.addAction(.init(title: "OK", style: .default))
                self.present(alert, animated: true)
            }
        }
    }
    

    ExtensionsURL.swift

    extension URL {
        var hasHiddenExtension: Bool {
            get { (try? resourceValues(forKeys: [.hasHiddenExtensionKey]))?.hasHiddenExtension == true }
            set {
                var resourceValues = URLResourceValues()
                resourceValues.hasHiddenExtension = newValue
                try? setResourceValues(resourceValues)
            }
        }
    }
    

    PreviewItem.swift

    import QuickLook
    class PreviewItem: NSObject, QLPreviewItem {
        var previewItemURL: URL?
    }
    
    0 讨论(0)
  • 2020-11-30 15:05

    You just need to subclass the QLPreviewController and add your functionality. I did it in my case, It waits for files to download from the server and then load those automatically.

    My PreviewController Class

    import UIKit
    import QuickLook
    
    class JSQuickPreviewController: QLPreviewController, QLPreviewControllerDataSource {
    
        var fileName: String = ""
        var url: URL?
    
        private var previewItem : PreviewItem!
        private let activityIndicator: UIActivityIndicatorView = {
            let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
            activityIndicator.translatesAutoresizingMaskIntoConstraints = false
            activityIndicator.hidesWhenStopped = true
            activityIndicator.tintColor = .black
            activityIndicator.color = .black
            activityIndicator.startAnimating()
            return activityIndicator
        }()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            self.dataSource = self;
            self.view.addSubview(activityIndicator)
            activityIndicator.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            activityIndicator.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
    
            self.title = fileName;
            self.downloadfile(fileName: fileName, itemUrl: url)
            
            self.hideErrorLabel();
            // Do any additional setup after loading the view.
        }
        
        @objc
        func hideErrorLabel() {
            
            var found = false
            for v in self.view.allViews.filter({ $0 is UILabel }) {
                v.isHidden = true
                found = true
            }
            
            if !found {
                self.perform(#selector(hideErrorLabel), with: nil, afterDelay: 0.1);
            }
    
        }
        
        private func downloadfile(fileName:String, itemUrl:URL?){
            
            self.previewItem = PreviewItem()
            let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
            let destinationUrl = documentsDirectoryURL.appendingPathComponent(fileName)
            if FileManager.default.fileExists(atPath: destinationUrl.path) {
                self.previewItem.previewItemURL = destinationUrl;
                self.loadFile()
            }
            else {
                DispatchQueue.main.async(execute: {
                    if let itemUrl = itemUrl {
                        
                        URLSession.shared.downloadTask(with: itemUrl, completionHandler: { (location, response, error) -> Void in
                            if error != nil {
                                for v in self.view.allViews.filter({ $0 is UILabel }) {
                                    v.isHidden = false
                                    (v as? UILabel)?.text = error?.localizedDescription
                                }
                            } else {
                                guard let tempLocation = location, error == nil else { return }
                                try? FileManager.default.moveItem(at: tempLocation, to: destinationUrl)
                                self.previewItem.previewItemURL = destinationUrl;
                                self.loadFile()
                            }
                        }).resume()
                    }
                })
            }
        }
        
        func loadFile() {
        
            DispatchQueue.main.async {
                self.activityIndicator.isHidden = true
                self.reloadData()
            }
        }
        
        func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
            return previewItem == nil ? 0 : 1
        }
        
        func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
            return previewItem
        }
    }
    
    extension UIView {
        var allViews: [UIView] {
            var views = [self]
            subviews.forEach {
                views.append(contentsOf: $0.allViews)
            }
            return views
        }
    }
    

    How to use it

     let quickPreviewController = JSQuickPreviewController()
     quickPreviewController?.url = fileURL
     quickPreviewController?.fileName = filename
     self.show(quickPreviewController, animated: true)
    
    0 讨论(0)
提交回复
热议问题