Receiving File Drops on macOS (and iOS) with SwiftUI
Starting Point
While porting a pure SwiftUI
app, I noticed that the onDrop
file import handler used for the iOS app does not work as expected on macOS:
providers.first!.loadFileRepresentation(forTypeIdentifier: UTType.item.identifier) {
url, _ in
message = describeDroppedURL(url!)
}
At first I thought it was just an issue with file names being erased / hidden, e.g. .com.apple.Foundation.NSItemProvider.MpBDqm.tmp
instead of notes.txt
, but upon closer inspection the file contents were also different. Instead of the expected data, the file read from the initial URL contained another URL in the form of file:///.file/id=6571367.2773272/
.
Adaptation for macOS
Eventually I came to find out that these are known as File reference URL
s, and this post offered a good reference on how they had to be handled historically (with NSURL
), and that they should work out of the box with Swift’s URL
.
In order to avoid having the system to create temporary files which then need to be read & referenced to get to the final file, I switched the macOS implementation to read the dropped file URL from the NSPasteboard
item itself:
providers.first!.loadObject(ofClass: NSPasteboard.PasteboardType.self) {
pasteboardItem, _ in
message = describeDroppedURL(URL(string: pasteboardItem!.rawValue)!)
}
Bonus
One last finding I made during testing was that the dropped data was different from whether the item was dragged from within the Finder’s tree view compared to when it was dragged from the title bar 🤔