I've been messing around with the drop feature of iOS11
. I found a lot of examples with the standard UIImage
etc but nothing with custom files.
The drop part works pretty well, I use it to drop a custom file and import it into my app.
The problem is that I only get the Data of this file and I would like to get its name and extension for example.
I don't know if my way of handling the custom file dropped is how it should be to obtain this information. And if so, how do you get this information from the file?
I have a DropFile
class conforming to the NSItemProviderReading
protocol.
class DropFile : NSObject, NSItemProviderReading {
let fileData:Data?
required init(data:Data, typeIdentifier:String) {
fileData = data
}
static var readableTypeIdentifiersForItemProvider: [String] {
var documentTypeArray: [String] = []
for ext in FileImportProcessHelper.sharedInstance.getImportDocumentType() {
let UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext as CFString, nil)
documentTypeArray.append((UTI?.takeRetainedValue() as String?)!)
}
return documentTypeArray
}
static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
return self.init(data: data, typeIdentifier: typeIdentifier)
}
}
This is my ViewController
conforming to the UIDropInteractionDelegate
// MARK: Handling Drop
@available(iOS 11.0, *)
// We refuse the dropped items based on their UTI
func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
var documentTypeArray: [String] = []
for ext in FileImportProcessHelper.sharedInstance.getImportDocumentType() {
let UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext as CFString, nil)
documentTypeArray.append(UTI?.takeRetainedValue() as! String)
}
return session.hasItemsConforming(toTypeIdentifiers: documentTypeArray) && session.items.count == 1
}
@available(iOS 11.0, *)
func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
// Copy file from source app
return UIDropProposal(operation: .copy)
}
@available(iOS 11.0, *)
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
// Consume drag items
session.loadObjects(ofClass: DropFile.self) { items in
if let fileItems = items as? [DropFile] {
DragnDropManager.sharedManager.createDropObject(fileItems: fileItems)
}
}
}
And then how I write my file.
func createDropObject(fileItems: [DropFile]) {
let documentsPathString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let inbox = URL(fileURLWithPath: documentsPathString!).appendingPathComponent("UserDropInbox/")
do {
try FileManager.default.createDirectory(atPath: inbox.path, withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
NSLog("Unable to create directory \(error.debugDescription)")
}
for file in fileItems {
do {
let dropFilePath = inbox.appendingPathComponent("File").appendingPathExtension("pdf")
try file.fileData?.write(to:dropFilePath)
} catch {
NSLog(error as! String)
}
}
FileImportInboxManager.shared.hasReceivedFiles = true;
}
I admit, it's not straightforward :
UIDragItem
s dragged by the user in the UIDropSession
items
memberNSItemProvider
itemProvider
memberString?
suggestedName
member that may not be nil
A simple loop to print all the session's items suggested names :
for item in session.items {
if let name = item.itemProvider.suggestedName {
print(name)
}
}
Practically, when files come from the File app it will provide the name of the file without its extension, but given you can easily access its UTI, you can append an extension that will be close to the original one (jpeg
instead of jpg
for example).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With