(Using macOS 26 Beta 9 and Xcode 26 Beta 7) I am trying to support basic onDrop from a source app to my app. I am trying to get the closest "source" representation of a drag-and-drop, e.g. a JPEG file being dropped into my app shouldn't be converted, but stored as a JPEG in Data. Otherwise, everything gets converted into TIFFs and modern iPhone photos get huge. I also try to be a good app, and provide asynchronous support.
Alas, I've been running around for days now, where I can now support Drag-and-Drop from the Finder, from uncached iCloud files with Progress bar, but so far, drag and dropping from Safari eludes me.
My code is as follows for the onDrop support:
Image(nsImage: data.image).onDrop(of: Self.supportedDropItemUTIs, delegate: self)
The UTIs are as follows:
public static let supportedDropItemUTIs: [UTType] = [
.image,
.heif,
.rawImage,
.png,
.tiff,
.svg,
.heic,
.jpegxl,
.bmp,
.gif,
.jpeg,
.webP,
]
Finally, the code is as follows:
public func performDrop(info: DropInfo) -> Bool {
let itemProviders = info.itemProviders(for: Self.supportedDropItemUTIs)
guard let itemProvider = itemProviders.first else {
return false
}
let registeredContentTypes = itemProvider.registeredContentTypes
guard let contentType = registeredContentTypes.first else {
return false
}
var suggestedName = itemProvider.suggestedName
if suggestedName == nil {
switch contentType {
case UTType.bmp: suggestedName = "image.bmp"
case UTType.gif: suggestedName = "image.gif"
case UTType.heic: suggestedName = "image.heic"
case UTType.jpeg: suggestedName = "image.jpeg"
case UTType.jpegxl: suggestedName = "image.jxl"
case UTType.png: suggestedName = "image.png"
case UTType.rawImage: suggestedName = "image.raw"
case UTType.svg: suggestedName = "image.svg"
case UTType.tiff: suggestedName = "image.tiff"
case UTType.webP: suggestedName = "image.webp"
default: break
}
}
let progress = itemProvider.loadInPlaceFileRepresentation(forTypeIdentifier: contentType.identifier) { url, _, error in
if let error {
print("Failed to get URL from dropped file: \(error)")
return
}
guard let url else {
print("Failed to get URL from dropped file!")
return
}
let queue = OperationQueue()
queue.underlyingQueue = .global(qos: .utility)
let intent = NSFileAccessIntent.readingIntent(with: url, options: .withoutChanges)
let coordinator = NSFileCoordinator()
coordinator.coordinate(with: [intent],
queue: queue) { error in
if let error {
print("Failed to coordinate data from dropped file: \(error)")
return
}
do {
// Load file contents into Data object
let data = try Data(contentsOf: intent.url)
Dispatch.DispatchQueue.main.async {
self.data.data = data
self.data.fileName = suggestedName
}
} catch {
print("Failed to load coordinated data from dropped file: \(error)")
}
}
}
DispatchQueue.main.async {
self.progress = progress
}
return true
}
For your information, this code is at the state where I gave up and sent it here, because I cannot find a solution to my issue.
Now, this code works everywhere, except for dragging and dropping from Safari.
Let's pretend I go to this web site:
https://commons.wikimedia.org/wiki/File:Tulip_Tulipa_clusiana_%27Lady_Jane%27_Rock_Ledge_Flower_Edit_2000px.jpg
and I try to drag-and-drop the image, it will fail with the following error:
URL https://upload.wikimedia.org/wikipedia/commons/c/cf/Tulip_Tulipa_clusiana_%27Lady_Jane%27_Rock_Ledge_Flower_Edit_2000px.jpg is not a file:// URL.
And then, fail with the dreaded
Failed to get URL from dropped file: Error Domain=NSItemProviderErrorDomain Code=-1000
As far as I can tell, the problem lies in the opaque NSItemProvider receiving a web site URL from Safari. I tried most solutions, I couldn't retrieve that URL. The error happens in the callback of loadInPlaceFileRepresentation, but also fails in loadFileRepresentation. I tried hard-requesting a loadObject of type URL, but there's only one representation for the JPEG file. I tried only putting .url in the requests, but it would not transfer it.
Anyone solved this mystery?