How to display pdf from network in iOS [duplicate] - ios

This question already has answers here:
How to display remote document using QLPreviewController in swift
(2 answers)
Closed 5 years ago.
Currently I am using QuickLook module to open pdf from network, but it shows a blank page with error "Couldn't issue file extension for url: https://testing-xamidea.s3.amazonaws.com/flowchart/20171103182728150973368.pdf" in console. I guess QuickLook can only open locally saved Pdf files. Is is possible to load pdf from network using quicklook? . This is my code so far- {fileURL contains url from which pdf is to be loaded, also ive set the delegates etc)
extension FlowchartVC:QLPreviewControllerDelegate,QLPreviewControllerDataSource {
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
let url : NSURL! = NSURL(string : fileURL)
return url
}
func previewControllerWillDismiss(_ controller: QLPreviewController) {
self.dismiss(animated: true, completion: nil)
}
}

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.

Related

QuickLook/QLPreviewController PDF Text Annotation background becomes black and font becomes small

I am Using QLPreviewController for editing the PDF. Everything is working properly but
if I add text annotation from the QLPreviewController and click on the done button it is working as expected I am getting the URL with edited PDF and if I do other changes for example add image annotation from outside of QLPreviewController and save that pdf using the code
self.pdfDocument.write(to: self.pdfUrl)
and if I open that pdf in the QLPReviewController and tap on the previously added text then the text annotation background becomes Black and the font becomes small.
I have attached the video please check.
**Video Link : ** https://www.dropbox.com/s/m0ql1csr8pars3t/Issue_video.mov?dl=0
I have used the below code for pdf mark up
func openPreview(_ url : URL){
let previewController = QLPreviewController()
previewController.isEditing = true
previewController.delegate = self
self.pdfUrl = url
previewController.dataSource = self
previewController.modalPresentationStyle = .overFullScreen
self.present(previewController, animated: true, completion: nil)
}
extension ViewController : QLPreviewControllerDataSource,QLPreviewControllerDelegate{
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return self.pdfUrl as QLPreviewItem
}
func previewController(_ controller: QLPreviewController, editingModeFor previewItem: QLPreviewItem) -> QLPreviewItemEditingMode {
return .updateContents
}
func previewControllerWillDismiss(_ controller: QLPreviewController) {
}
func previewController(_ controller: QLPreviewController, didUpdateContentsOf previewItem: QLPreviewItem) {
DispatchQueue.main.async {
self.pdfUrl = previewItem.previewItemURL
self.setPDFFile()
self.pdfDocument.write(to: self.pdfUrl)
}
}
}
func setPDFFile(){
if let doc = PDFDocument(url: self.pdfUrl){
self.pdfDocument = doc
self.pdfView.document = doc
}
}

Hide or disable share button from uidocumentinteractioncontroller in swift 5

In my application, I'm using the QuickLook framework to view the document files such as pdf, ppt, doc, etc. etc. But due to privacy concerns, I don't want that the user can share this document with others so please let me know how to disable/hide the share button and also the copy-paste option.
I know this question can be asked by a number of times and tried many solutions but nothing works for me
hide share button from QLPreviewController
UIDocumentInteractionController remove Actions Menu
How to hide share button in QLPreviewController using swift?
Hide right button n QLPreviewController?
Please suggest to me to achieve this.
Here is my demo code:
import UIKit
import QuickLook
class ViewController: UIViewController {
lazy var previewItem = NSURL()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func displayLocalFile(_ sender: UIButton){
let previewController = QLPreviewController()
// Set the preview item to display
self.previewItem = self.getPreviewItem(withName: "samplePDf.pdf")
previewController.dataSource = self
self.present(previewController, animated: true, completion: nil)
}
#IBAction func displayFileFromUrl(_ sender: UIButton){
// Download file
self.downloadfile(completion: {(success, fileLocationURL) in
if success {
// Set the preview item to display======
self.previewItem = fileLocationURL! as NSURL
// Display file
let previewController = QLPreviewController()
previewController.dataSource = self
self.present(previewController, animated: true, completion: nil)
}else{
debugPrint("File can't be downloaded")
}
})
}
func getPreviewItem(withName name: String) -> NSURL{
// Code to diplay file from the app bundle
let file = name.components(separatedBy: ".")
let path = Bundle.main.path(forResource: file.first!, ofType: file.last!)
let url = NSURL(fileURLWithPath: path!)
return url
}
func downloadfile(completion: #escaping (_ success: Bool,_ fileLocation: URL?) -> Void){
let itemUrl = URL(string: "https://images.apple.com/environment/pdf/Apple_Environmental_Responsibility_Report_2017.pdf")
// then lets create your document folder url
let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
// lets create your destination file url
let destinationUrl = documentsDirectoryURL.appendingPathComponent("filename.pdf")
// to check if it exists before downloading it
if FileManager.default.fileExists(atPath: destinationUrl.path) {
debugPrint("The file already exists at path")
completion(true, destinationUrl)
// if the file doesn't exist
} else {
// you can use NSURLSession.sharedSession to download the data asynchronously
URLSession.shared.downloadTask(with: itemUrl!, completionHandler: { (location, response, error) -> Void in
guard let tempLocation = location, error == nil else { return }
do {
// after downloading your file you need to move it to your destination url
try FileManager.default.moveItem(at: tempLocation, to: destinationUrl)
print("File moved to documents folder")
completion(true, destinationUrl)
} catch let error as NSError {
print(error.localizedDescription)
completion(false, nil)
}
}).resume()
}
}
}
//MARK:- QLPreviewController Datasource
extension ViewController: QLPreviewControllerDataSource {
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
controller.navigationItem.rightBarButtonItem = nil
return self.previewItem as QLPreviewItem
}
}
Please provide your suggestion to do so or any other framework to view different file formats.
Here is the image
Find below adopted my approach to your code (with modifications to test locally, but the code should be clear). The idea is
a) to override, which is completely allowed by API, needed classes to intercept modification
b) to use intentionally own UINavigationController, as only one navigation controller can be in stack
So here is code:
// Custom navigation item that just blocks adding right items
class MyUINavigationItem: UINavigationItem {
override func setRightBarButtonItems(_ items: [UIBarButtonItem]?, animated: Bool) {
// forbidden to add anything to right
}
}
// custom preview controller that provides own navigation item
class MyQLPreviewController: QLPreviewController {
private let item = MyUINavigationItem(title: "")
override var navigationItem: UINavigationItem {
get { return item }
}
}
class MyViewController : UIViewController, QLPreviewControllerDataSource {
lazy var previewItem = NSURL()
override func loadView() {
let view = UIView()
view.backgroundColor = .white
// just stub testing code
let button = UIButton(type: .roundedRect)
button.frame = CGRect(x: 150, y: 200, width: 200, height: 20)
button.setTitle("Show", for: .normal)
button.addTarget(self, action:
#selector(displayLocalFile(_:)), for: .touchDown)
view.addSubview(button)
self.view = view
}
#objc func displayLocalFile(_ sender: UIButton){
let previewController = MyQLPreviewController() // << custom preview
// now navigation item is fully customizable
previewController.navigationItem.title = "samplePDF.pdf"
previewController.navigationItem.leftBarButtonItem =
UIBarButtonItem(barButtonSystemItem: .done, target: self,
action: #selector(closePreview(_:)))
// wrap it into navigation controller
let navigationController = UINavigationController(rootViewController: previewController)
// Set the preview item to display
self.previewItem = self.getPreviewItem(withName: "samplePDF.pdf")
previewController.dataSource = self
// present navigation controller with preview
self.present(navigationController, animated: true, completion: nil)
}
#objc func closePreview(_ sender: Any?) {
self.dismiss(animated: true) // << dismiss preview
}
func getPreviewItem(withName name: String) -> NSURL{
// Code to diplay file from the app bundle
let file = name.components(separatedBy: ".")
let path = Bundle(for: type(of: self)).path(forResource: file.first!, ofType: file.last!)
let url = NSURL(fileURLWithPath: path!)
return url
}
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return self.previewItem as QLPreviewItem
}
}

UIDocumentInteractionController on iphoneX with iOS 11.1.2

When I use UIDocumentInteractionController on iphoneX with iOS 11.1.2, it doesn't show, and log on the console as:
[ShareSheet] ERROR: <_UIDICActivityViewController: 0x107075c00> timed out waiting to establish a connection to the ShareUI view service extension.
but the same code runs ok on other device with iOS 11.1.2, only the iphoneX cannot preview the documentInteraction menu. Is there some thing wrong with my code? Please tell me if you find the solution.
My code:
var doc: UIDocumentInteractionController?
fileprivate func openWithOtherApp(with url: URL) -> Void {
let doc = UIDocumentInteractionController(url: url)
self.doc = doc
doc.delegate = self
DispatchQueue.main.async { [weak self] in
guard let weakSelf = self else {
return
}
if weakSelf.doc?.presentOpenInMenu(from: weakSelf.view.bounds, in: weakSelf.view, animated: true) != true {
Toast(message: "No app on you iPhone can open this file.")
}
}
}
delegate:
extension UniversalPreviewController: UIDocumentInteractionControllerDelegate {
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self
}
func documentInteractionControllerRectForPreview(_ controller: UIDocumentInteractionController) -> CGRect {
return self.view.bounds
}
func documentInteractionControllerViewForPreview(_ controller: UIDocumentInteractionController) -> UIView? {
return self.view
}
func documentInteractionControllerWillBeginPreview(_ controller: UIDocumentInteractionController) {
NSLog("documentInteractionControllerWillBeginPreview")
}
func documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) {
self.doc = nil
}
}
My Latest Test:
When i use permanent file url(drag the file into the project filelist), It works.
let permanentUrl = Bundle.main.url(forResource: "INBOX24-2.2-resolv", withExtension: "conf")
self.doc = UIDocumentInteractionController.init(url: permanentUrl!)
//permanentUrl:file:///var/containers/Bundle/Application/40F14112-208E-4A97-8214-D55CC8E597C4/xxx.app/INBOX24-2.2-resolv.conf
But when i change to the real code that files storage on the apps documents directory it doesn't work,code like this:
let url = URL.init(fileURLWithPath: storedPath
self.doc = UIDocumentInteractionController.init(url: url)
//url:file:///var/mobile/Containers/Data/Application/9624FFB3-8CB0-437C-A67B-C71AAB314370/Documents/INBOX24-2.2-resolv.conf
I found the same issue in my iPhone, I just restarted my iPhone and it was resolved.

How to access created pdf document on iOS?

My app has an action that creates pdf file. After creating file on simulator I can access the created file on Mac but on iPhone I can not. Even I have searched but couldn't find. On Acrobat Reader neither.
So what can I do with this created pdf file? Should I convert it ePub or something?
This is my code for creating pdf:
func createPdfFromView(_ imageView: UIImageView, saveToDocumentsWithFileName fileName: String)
{
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, imageView.bounds, nil)
UIGraphicsBeginPDFPage()
let pdfContext = UIGraphicsGetCurrentContext()
if (pdfContext == nil)
{
return
}
imageView.layer.render(in: pdfContext!)
UIGraphicsEndPDFContext()
}
#IBAction func createPdfAction(_ sender: UIButton) {
createPdfFromView(ImageDisplay, saveToDocumentsWithFileName: "")
}
Write the PDF Data as a file in local path
private var pdfData: NSMutableData!
private var filPath: NSString!
private var docController: UIDocumentInteractionController!
func writeDataAsFile()
{
//Search for local path
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let directoryPath = paths[0] as NSString
//Appending file name to be saved in directory path
filPath = directoryPath.appendingPathComponent("TestPDF.pdf") as NSString!
//Check file is already exist in path
let isFileExists = FileManager.default.fileExists(atPath: filPath as String)
if(!isFileExists)
{
//pdfData is NSData/NSMutableData, Write to the filepath
pdfData.write(toFile: filPath as String, atomically: true)
}
}
UIDocumentInteractionController provides in-app support for managing user interactions with files in the local system
#IBAction func goPDF(sender: UIButton) {
docController = UIDocumentInteractionController.init(url: NSURL.fileURL(withPath: filPath as String, isDirectory: true))
docController.delegate = self
docController.presentOpenInMenu(from: CGRect.zero, in: self.view, animated: true)
}
UIDocumentInteractionControllerDelegate to handle document interactions
func documentInteractionController(_ controller: UIDocumentInteractionController, willBeginSendingToApplication application: String?) {
print("willBeginSendingToApplication")
}
func documentInteractionController(_ controller: UIDocumentInteractionController, didEndSendingToApplication application: String?) {
print("didEndSendingToApplication")
}
func documentInteractionControllerDidDismissOpenInMenu(_ controller: UIDocumentInteractionController) {
print("documentInteractionControllerDidDismissOpenInMenu")
}
Using delegate in your ViewController should conforms the UIDocumentInteractionControllerDelegate like this, for example, in ViewController
import UIKit
class FirstViewController: UIViewController, UIDocumentInteractionControllerDelegate {
}
For open PDF in iBooks the menu will provide "Import with iBooks" option. This option will lead to open the PDF in iBooks after importing.

Opening a PDF document when clicking a button

I am trying to create an app for my family restaurant in swift. I currently have a button that you click on that takes you too a webviewer page of our menu. I want to make the menu with in the app so it does not redirect to safari.
Basically what I want to do is click a button and it opens the menu pdf within the app instead safari.
The code that I use too open the PDF in a browser:
#IBAction func menu(sender: AnyObject) {
if let url = NSURL(string:"http://nebula.wsimg.com/db5e994c02db104ea89bdf6e59550490?AccessKeyId=895454CA4A1E296ED3E3&disposition=0&alloworigin=1") {
UIApplication.sharedApplication().openURL(url)
}
You can use QLPreviewController to preview your pdf but it needs to be a local resource or downloaded from the web prior to previewing:
Swift 3 or later
import UIKit
import QuickLook
class ViewController: UIViewController, QLPreviewControllerDataSource {
let preview = QLPreviewController()
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return Bundle.main.url(forResource: "menu", withExtension: "pdf")!
as QLPreviewItem
}
override func viewDidLoad() {
super.viewDidLoad()
// set preview data source
preview.dataSource = self
// set current item index (only one = 0)
preview.currentPreviewItemIndex = 0
}
#IBAction func showMenu(sender: UIButton) {
present(preview, animated: true) {
// code
}
}
}

Resources