Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS11 How to handle a custom file dropped in a custom view

Tags:

ios

swift

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;
 }
like image 987
Luis Avatar asked Dec 05 '17 17:12

Luis


1 Answers

I admit, it's not straightforward :

  • you can list all the UIDragItems dragged by the user in the UIDropSession items member
  • each of these items have a NSItemProvider itemProvider member
  • this item provider has an optional String? 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).

like image 120
Pierre Mardon Avatar answered Oct 14 '22 06:10

Pierre Mardon