How to Display Remote Document Using Qlpreviewcontroller in Swift

How to display remote document using QLPreviewController in swift

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

How to display pdf from network in iOS

You need to save the file to disk first and then you can present the pdf. There is no way to present it with QuickLook if the file is in a remote location. The file is saved in the temporary directory. Here is an example view controller showing how it could be done.

Swift 5:

import UIKit
import QuickLook

class ViewController: UIViewController, QLPreviewControllerDataSource {
// Remote url pdf I found on google
let itemURL = URL(string: "https://www.ets.org/Media/Tests/GRE/pdf/gre_research_validity_data.pdf")!
var fileURL: URL?

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

let quickLookController = QLPreviewController()
quickLookController.dataSource = self

do {
// Download the pdf and get it as data
// This should probably be done in the background so we don't
// freeze the app. Done inline here for simplicity
let data = try Data(contentsOf: itemURL)

// Give the file a name and append it to the file path
fileURL = FileManager().temporaryDirectory.appendingPathComponent("sample.pdf")
if let fileUrl = fileURL {
// Write the pdf to disk in the temp directory
try data.write(to: fileUrl, options: .atomic)
}

// Make sure the file can be opened and then present the pdf
if QLPreviewController.canPreview(fileUrl as QLPreviewItem) {
quickLookController.currentPreviewItemIndex = 0
present(quickLookController, animated: true, completion: nil)
}
} catch {
// cant find the url resource
}
}

func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}

func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return fileURL! as QLPreviewItem
}
}

Swift 3:

import UIKit
import QuickLook

class ViewController: UIViewController, QLPreviewControllerDataSource {
// Remote url pdf I found on google
let itemURL = URL(string: "https://www.ets.org/Media/Tests/GRE/pdf/gre_research_validity_data.pdf")!
var fileURL = URL(string: "")

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

let quickLookController = QLPreviewController()
quickLookController.dataSource = self

do {
// Download the pdf and get it as data
// This should probably be done in the background so we don't
// freeze the app. Done inline here for simplicity
let data = Data(contentsOf: itemURL)

// Give the file a name and append it to the file path
fileURL = FileManager().temporaryDirectory.appendingPathComponent("sample.pdf")
// Write the pdf to disk
try data?.write(to: fileURL!, options: .atomic)

// Make sure the file can be opened and then present the pdf
if QLPreviewController.canPreview(fileUrl as QLPreviewItem) {
quickLookController.currentPreviewItemIndex = 0
present(quickLookController, animated: true, completion: nil)
}
} catch {
// cant find the url resource
}
}

func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}

func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return fileURL! as QLPreviewItem
}
}

Here is the file showing in the simulator. Using a sample project with just that code.

enter image description here

Is it possible to view a PDF file from an URL link using Quick Look Framework

I have resolved by using UIDocumentInteractionController

UIDocumentInteractionController *viewer = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
viewer.delegate = self;
[viewer presentPreviewAnimated:YES];

iOS QLPreviewController load file from remote server URL

To show any file that supports QLPreviewController, the url should
be the fileURL.

(id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index

It always returns fileURL - if you will use any other URL, it will crash. After downloading is over save the file in documents directory and then push to preview.

- (void)saveFileInDocDirectoryWithFileName:(NSString *)title{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath_ = [paths objectAtIndex:0];
NSString *filePath = [ docPath_ stringByAppendingPathComponent:title];

self.fileURL = [NSURL fileURLWithPath:filePath];
[self pushToPreViewWithURL:fileURL];
}

- (void)pushToPreViewWithURL:(NSURL *)filePathURL{
QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
// start previewing the document at the current section index

[[NSOperationQueue mainQueue] addOperationWithBlock:^{

[self.navigationController pushViewController:previewController animated:YES];

}];
}

Then in delegate method, return fileURL:

 - (id)previewController:(QLPreviewController *)previewController previewItemAtIndex:(NSInteger)idx {
return self.fileURL;
}

QLPreviewController showing file then going blank in SwiftUI

I finally got it to work – big thanks to Leo Dabus for his help in the comments.

Here's my currently working code:

@State private var isShowingDoc = false
@State private var isLoadingFile = false
@State private var fileURL: URL?

var body: some View {
Button {
let destination: DownloadRequest.Destination = { _, _ in
let documentsURL = FileManager.default.documentsDirectory
.appendingPathComponent(document.id.string)
.appendingPathComponent(document.name ?? "file.jpg")
return (documentsURL, [.removePreviousFile, .createIntermediateDirectories])
}
isLoadingFile = true
AF
.download(url, to: destination)
.responseURL { (response) in
self.isLoadingFile = false
guard let url = response.fileURL else { return }
isShowingDoc = true
self.fileURL = url
}
} label: {
VStack {
Text("download")
if isLoadingFile {
ActivityIndicator(style: .medium)
}
}
}
.sheet(isPresented: $isShowingDoc, onDismiss: { isShowingDoc = false }) {
QuickLookView(url: fileURL!)
}
}

with this QuickLookView: (mostly unchanged)

struct QuickLookView: UIViewControllerRepresentable {

var url: URL

func makeCoordinator() -> Coordinator {
Coordinator(self)
}

func updateUIViewController(_ viewController: UINavigationController, context: UIViewControllerRepresentableContext<Self>) {
(viewController.topViewController as? QLPreviewController)?.reloadData()
}

func makeUIViewController(context: Context) -> UINavigationController {
let controller = QLPreviewController()

controller.dataSource = context.coordinator
controller.reloadData()
return UINavigationController(rootViewController: controller)
}

class Coordinator: NSObject, QLPreviewControllerDataSource {
var parent: QuickLookView

init(_ qlPreviewController: QuickLookView) {
self.parent = qlPreviewController
super.init()
}

func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
1
}

func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
self.parent.url as QLPreviewItem
}
}
}

As you can see, there's hardly any difference to my code from when I asked the question. Yesterday night, the fileURL was always nil for an unclear reason; yet, now it started working just fine. In exchange, the remote images in my list (not shown here) stopped working even though I haven't touched them, haha.

I don't know what's going on and what I even changed to make it work, but it works and I won't complain!

QLPreviewController not loading multiple files

Turns out, I misunderstood how multiple items are loaded in a QLPreviewController.

I thought, the user had to scroll vertically and see the side bar with thumbnails. This is only for pages within a single document, however.

I had to scroll horizontally.

Thanks to @matt, who cleared this up for me.

Does `QLPreviewItem` works with local files only?

QLPreviewItem works with local file URLs only, it won't download your file for you if you provide it a remote file url.

You need to download your file to your app's local file system before presenting QLPreviewController and provide it that local file url.

For advanced usage - multiple urls, dataSource, delegate handling - you should watch Quick Look Previews from the Ground Up from WWDC 2018.

iOS/Swift: QLPreviewController shows blank page in iOS11

You did not add the current viewController as the parent class of the QLPreviewController()

Just add QLController.didMove(toParentViewController: self) after adding it to the self.view

I think this should solve your issue.



Related Topics



Leave a reply



Submit