Uidocumentinteractioncontroller() Swift

How to use UIDocumentInteractionController?

Using UIDocumentInteractionController is quite easy. You just need to know the url of your file, then you present the menu:

/// Needs to be global, otherwise the controller will be destroyed when the file is handed over to target application
var documentInteractionController: UIDocumentInteractionController!

class MyViewController: UIViewController {

var url: URL

...

@IBAction func share(_ sender: UIBarButtonItem) {
documentInteractionController = UIDocumentInteractionController()
documentInteractionController.url = url
documentInteractionController.uti = url.uti
documentInteractionController.presentOptionsMenu(from: sender, animated: true)
}

}

extension URL {

var uti: String {
return (try? self.resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier ?? "public.data"
}

}

Presenting UIDocumentInteractionController with UIViewControllerRepresentable in SwiftUI

Here is possible approach to integrate UIDocumentInteractionController for usage from SwiftUI view.

demo

Full-module code. Tested with Xcode 11.2 / iOS 13.2

import SwiftUI
import UIKit

struct DocumentPreview: UIViewControllerRepresentable {
private var isActive: Binding<Bool>
private let viewController = UIViewController()
private let docController: UIDocumentInteractionController

init(_ isActive: Binding<Bool>, url: URL) {
self.isActive = isActive
self.docController = UIDocumentInteractionController(url: url)
}

func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentPreview>) -> UIViewController {
return viewController
}

func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<DocumentPreview>) {
if self.isActive.wrappedValue && docController.delegate == nil { // to not show twice
docController.delegate = context.coordinator
self.docController.presentPreview(animated: true)
}
}

func makeCoordinator() -> Coordintor {
return Coordintor(owner: self)
}

final class Coordintor: NSObject, UIDocumentInteractionControllerDelegate { // works as delegate
let owner: DocumentPreview
init(owner: DocumentPreview) {
self.owner = owner
}
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return owner.viewController
}

func documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) {
controller.delegate = nil // done, so unlink self
owner.isActive.wrappedValue = false // notify external about done
}
}
}

// Demo of possible usage
struct DemoPDFPreview: View {
@State private var showPreview = false // state activating preview

var body: some View {
VStack {
Button("Show Preview") { self.showPreview = true }
.background(DocumentPreview($showPreview, // no matter where it is, because no content
url: Bundle.main.url(forResource: "example", withExtension: "pdf")!))
}
}
}

struct DemoPDFPreview_Previews: PreviewProvider {
static var previews: some View {
DemoPDFPreview()
}
}

Opening a PDF with UIDocumentInteractionController URL error

Swift 5 Implementation(Xcode 12.5):

class VC1: UIViewController {

var pdfURL: URL?
var documentInteractionController:UIDocumentInteractionController!

override func viewDidLoad() {
super.viewDidLoad()
}

@IBAction func downloadAction(_ sender: Any) {
self.downloadPDF()
}

func downloadPDF() {
guard let url = URL(string: "https://file-examples-com.github.io/uploads/2017/10/file-sample_150kB.pdf") else { return }

let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())

let downloadTask = urlSession.downloadTask(with: url)
downloadTask.resume()
}

func showPDF(url: URL) {
documentInteractionController = UIDocumentInteractionController(url: url)
documentInteractionController.delegate = self

DispatchQueue.main.async { [self] in
documentInteractionController.presentPreview(animated: true)
}
}
}

extension VC1: UIDocumentInteractionControllerDelegate {
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return self
}

func documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) {
print("Dismissed!!!")
documentInteractionController = nil
}
}

extension VC1: URLSessionDownloadDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
guard let url = downloadTask.originalRequest?.url else { return }
let documentsPath = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
let destinationURL = documentsPath.appendingPathComponent(url.lastPathComponent)
try? FileManager.default.removeItem(at: destinationURL)
do {
try FileManager.default.copyItem(at: location, to: destinationURL)
self.pdfURL = destinationURL
showPDF(url: destinationURL)
} catch let error {
print("Error: \(error.localizedDescription)")
}
}
}

UIDocumentInteractionController() swift

Revise your code to the following

import UIKit

class ViewController: UIViewController {
var docController:UIDocumentInteractionController!

override func viewDidLoad() {
let someText = NSString(string: "Test")
if let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as? String {

let destinationPath = documentsPath.stringByAppendingPathComponent("Data.txt")
var error:NSError?

let written = someText.writeToFile(destinationPath,
atomically: true,
encoding: NSUTF8StringEncoding,
error: &error)

if written{
println("Successfully stored the file at path \(destinationPath)")
}
if let url = NSURL(fileURLWithPath: destinationPath) {
docController = UIDocumentInteractionController(URL: url)
}
}
}

@IBAction func sendFile(sender:AnyObject) {
docController.presentOptionsMenuFromRect(sender.frame, inView:self.view, animated:true)
}

}

Now wire up the IBAction to a button in the storyboard. Next:

  1. click on the blue project icon in the left sidebar and then select
    Info from the horizontal menu.
  2. expand Document Types and enter "txt" in the Name field and
    "public.data, public.content" in the Types field
  3. now expand Exported UTIs and enter "txt" in the Description
    field, "kUTTypeText" in the Identifier field and
    "public.data, public.content" in the Conforms to field

So that everything looks like this:

Sample Image

You can now build and run the app to test.

Sharing a Document with UIDocumentInteractionController

It turned out to be trivial, even silly. I leave the question anyhow in case someone else stumbles over it.

I need to maintain the instance of UIDocumentInteractionController outside the button action handler that presents the controller. I will update the question to better show this problem. With a small change, it works as expected:

var documentInteractionController: UIDocumentInteractionController?

@IBAction func createDocumentButtonClicked(_ sender: Any) {
do {
// create temporary file
let tempUrl = FileManager.default.temporaryDirectory.appendingPathComponent("fileName.txt")
try "abc".write(to: tempUrl, atomically: true, encoding: .utf8)

// share file
documentInteractionController = UIDocumentInteractionController(url: tempUrl)
documentInteractionController!.name = "filename.txt"
documentInteractionController!.presentOptionsMenu(from: view.frame, in: view, animated: true)
} catch {
// ...
}
}

XCODE / IOS - Share via UIDocumentInteractionController

Here is working code through that you can share your image to whatsapp, All you need to do is just add LSApplicationQueriesSchemes whatsapp into your plist file for WhatsApp sharing enable.

Swift 4

func shareOnWhatsUp() {

if UIApplication.shared.canOpenURL(URL(string: "whatsapp://app")!) {
var documentInteractionController: UIDocumentInteractionController = UIDocumentInteractionController.init()
let iconImage = UIImage(named: "IMG_1.jpg")
let pathURL = URL.init(fileURLWithPath: NSHomeDirectory() + "/Documents/whatsAppTmp.wai")

do {
try UIImageJPEGRepresentation(iconImage!, 1.0)?.write(to: pathURL)
} catch {
print(error.localizedDescription)
}
documentInteractionController!.url = pathURL
documentInteractionController!.uti = "net.whatsapp.image"
documentInteractionController!.delegate = self
documentInteractionController!.presentOpenInMenu(from: CGRect(x: 0, y: 0, width: 0, height: 0), in: self.view, animated: true)
}
else {
print("whatsup not installed")
}
}

UIDocumentInteractionController does not open other app in iOS 11

The problem was that I was trying to share a URL to a file inside the app bundle. It seems Apple's apps have permission to access that URL but third-party apps don't. I solved this by first copying the resource to the cache directory and then using that cache directory URL for sharing.



Related Topics



Leave a reply



Submit