(Re: previous answers - skip if you haven't followed the saga) Adding some context for the answer. I added AppKit specifically because it's not UIKit, as I didn't want an answer for iOS or ipadOS, but macOS.
The only SwiftUI line is the onDrag, that I faithfully added to the line as the "caller", but I didn't think I'd have a different DropHandler for macOS and ipadOS, the culprit seemingly being the onDrag SwiftUI part that tries to give me only the "good thing" on macOS, but somehow is unusable.
As I repeated, I wanted to quickly iterate and used the hacks instead of trying to use the Async versions, where some versions aren't actually available. The final code will be in Async, thank you.
My first SwiftUI app was with GCD because there wasn't an alternative back then. There's one now. But I'm also butting heads with SwiftData, where models cannot be Sendable, but Async are also required to be sendable, so I've had a lot of "fun" on this topic. With the nearly 200 trials I had to do in order to make it work, I wasn't about to create good code only to suit the taste of Internet good will helpers, I'm sure you'll agree with me.
So. I did another 8 hours on this, and I was able to do it properly!
(/snip)
The answer lies in using the .onDrop with the .image type, where it will magically send me the Drag & Drops where images are accessible. But then, to actually ignore the provider, and do the work yourself from the .drag pasteboard!!
In essence, the previous piece of code (still not asynchronous- that's my next work) got trimmed down on macOS only to do things through the same code I'm using for pasting things.
private func handleItemProviders(_ itemProviders: [NSItemProvider]) -> Bool {
guard let itemProvider = itemProviders.first else {
return false
}
let registeredContentTypes = itemProvider.registeredContentTypes
print("ContentTypes: \(registeredContentTypes)")
guard let contentType = registeredContentTypes.first else {
return false
}
#if canImport(AppKit)
handlePasteboard(NSPasteboard(name: .drag))
#else
[snip]
And the handlePasteboard operation is a long-winded function that processes whatever the pasteboard has in it. First by optionally getting an URL (file or web)
var url: URL?
let urlType = item.availableType(from: Self.supportedPasteboardURLTypes)
if let urlType,
let urlString = item.string(forType: urlType) {
url = URL(string: urlString)
Then by trying to get the data from the pasteboard itself (used in case of a drag-and-drop from Photos or Preview, or even Safari)
if let imageType = item.availableType(from: Self.supportedPasteboardTypes) {
guard let data = item.data(forType: imageType) else {
Then, if not functional, by trying to get the image from the URL through a coordinator (used in case of a drag-and-drop of an actual image from a file)
} else if let url {
if urlType == .fileURL {
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
Finally, when trying to drag-and-drop an actual link to an image, by trying to retrieve it with a downloadTask (don't forget the incoming network client capability!)
} else if urlType == .URL {
let session = URLSession.shared.downloadTask(with: url) { url, response, error in
In the last part, I check for the mime type for image, and download the URL if working.
So this works perfectly on macOS, under all circumstances. For iOS, a piece of code similar to what was written in the original question actually works, since the actual image got retrieved by Safari and the system sends back a local device URL, and not a https link.
So... Problem averted for now! And the code for the pasteboard handling can be reused with .general for a regular paste in SwiftUI.
.onDrop(of: Self.supportedDropItemUTIs, delegate: self)
.contextMenu {
Button(action: onPasteButton) {
Text("Paste")
Image(systemName: "doc.on.clipboard")
}
}
with
public func onPasteButton() {
handlePasteboard(.general)
}
Topic:
UI Frameworks
SubTopic:
AppKit
Tags: