1
votes

I have implemented iOS 11 Drag and Drop to allow PDF files to be dragged into my App from Files on iPad.

I have a DragDropFile class as follows:

import Foundation
import MobileCoreServices


//Drag and drop PDF files

class DragDropFile : NSObject, NSItemProviderReading {
    let fileData:Data?

    required init(data:Data, typeIdentifier:String) {
        fileData = data
    }

    static var readableTypeIdentifiersForItemProvider: [String] {
        var documentTypeArray: [String] = []

        documentTypeArray = [kUTTypePDF as String]
        return documentTypeArray

    }

    static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
        return self.init(data: data, typeIdentifier: typeIdentifier)
    }
}

Then canHandle specifies this class:

func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
            return session.canLoadObjects(ofClass: DragDropFile.self) 
        }

This works fine for dropping PDF files dragged from DropBox!

However, my App also needs access to the original PDF file name.

I would have expected to be able to also drop the URL as follows:

func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
        return session.canLoadObjects(ofClass: NSURL.self) && session.canLoadObjects(ofClass: DragDropFile.self) 
    }

Unfortunately, this does not work with DropBox as there appears to be no associated URL.

Does anyone know how to drag and drop and access the file name?

Thanks!

1
Did you ever get anywhere with this? I'm having trouble with receiving files dropped from Dropbox. Calling item.itemProvider.loadDataRepresentation(forTypeIdentifier: kUTTypePDF as String, completionHandler: completionHandler) results in the error: "The file “PDF document.pdf” couldn’t be opened because there is no such file."colincameron
I assume you get the content of a PDF and not the filename? But still it is interesting to know the file name of the file dropped on our app? Suggestion of Wei WANG does it.Jan Bergström

1 Answers

3
votes

I had the similar problem of getting the original filename, and after one day's digging I've come to the following solution (dragging files from Apple's Files app):

func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
    let filenameWithoutExtension = coordination.session.items.first?.itemProvider.suggestedName
}

I've used TableView in my case so in your case it should be something like:

func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
    let filenameWithoutExtension = session.items.first?.itemProvider.suggestedName
}

See here for reference (though very little information).

And note the suggestedName you retrieve from the above API is without the extension name. However it should not be a big deal since you've got the UTI so you know what exactly extension name should be... In my case I get it like:

class DragDropFile : NSObject, NSItemProviderReading {
    let fileData: Data?
    let extensionName: String?

    required init(data:Data, typeIdentifier:String) {
        fileData = data
        if typeIdentifier == (kUTTypePDF as String) {
            extensionName = "pdf"
        } else if typeIdentifier == (kUTTypePNG as String) {
            extensionName = "png"
        } else {
            //.,..
        }
    }
}

==== Updated 2/1/2019 ===

I ended up using UTTypeCopyPreferredTagWithClass to get the extension name from UTI:

class DragDropFile : NSObject, NSItemProviderReading {
    let fileData: Data?
    let extensionName: String?

    required init(data:Data, typeIdentifier:String) {
        fileData = data
        let cfExtensionName = UTTypeCopyPreferredTagWithClass(typeIdentifier as CFString, kUTTagClassFilenameExtension)
        self.extensionName = cfExtensionName?.takeRetainedValue() as String?
    }

    static var readableTypeIdentifiersForItemProvider: [String] {
        var documentTypeArray: [String] = []

        for ext in ["doc", "docx", "other_extensions..."] {
            let UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext as CFString, nil)
            if let documentType = UTI?.takeRetainedValue() as String? {
                documentTypeArray.append(documentType)
            }
        }

        return documentTypeArray
    }

}