如何在swift中使用QLPreviewController显示远程文档

时间:2017-11-06 15:25:56

标签: ios swift document

我正在使用QLPreviewController来预览文档。但我不知道如何显示存储在服务器上的文档。

2 个答案:

答案 0 :(得分:10)

你做不到。 QuickLook仅适用于本地资源文件。您需要先异步下载数据,将其保存到文档目录或临时文件夹,并在完成后从主线程中显示QLPreviewController:

import UIKit
import QuickLook
class ViewController: UIViewController, QLPreviewControllerDataSource {
    let preview = QLPreviewController()
    let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent("quicklook.pdf")
    func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
        return 1
    }
    func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
        return tempURL as QLPreviewItem
    }
    override func viewDidLoad() {
        super.viewDidLoad()
        preview.dataSource = self
        preview.currentPreviewItemIndex = 0
        let url = URL(string:"https://images.apple.com/environment/pdf/Apple_Environmental_Responsibility_Report_2017.pdf")!
        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 and update the UI from the main thread
                DispatchQueue.main.async {
                    UIApplication.shared.isNetworkActivityIndicatorVisible = false
                    let alert = UIAlertController(title: "Alert", message: error?.localizedDescription ?? "Failed to download the pdf!!!", preferredStyle: .alert)
                    alert.addAction(UIAlertAction(title: "OK", style: .default))
                    self.present(alert, animated: true)
                }
                return
            }
            // write the downloaded data to a temporary folder or to the document directory if you want to keep the pdf for later usage
            do {
                try data.write(to: self.tempURL, options: .atomic)   // atomic option overwrites it if needed
                // you neeed to check if the downloaded data is a valid pdf
                // and present your controller from the main thread
                DispatchQueue.main.async {
                    UIApplication.shared.isNetworkActivityIndicatorVisible = false
                    if self.tempURL.typeIdentifier == "com.adobe.pdf" {
                        self.present(self.preview, animated: true)
                    } else {
                        print("the data downloaded it is not a valid pdf file")
                    }
                }
            } catch {
                print(error)
                return
            }

        }.resume()
        UIApplication.shared.isNetworkActivityIndicatorVisible = true
    }
}

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

答案 1 :(得分:2)

您只需要子类化QLPreviewController并添加您的功能。我是这样做的,它等待文件从服务器下载,然后自动加载。

我的PreviewController类

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
    }
}

使用方法

 let quickPreviewController = JSQuickPreviewController()
 quickPreviewController?.url = fileURL
 quickPreviewController?.fileName = filename
 self.show(quickPreviewController, animated: true)