Drag-and-Drop from macOS Safari to NSItemProvider fails due to URL not being a file:// URL

(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?

I also try to be a good app, and provide asynchronous support.

I think that's your problem. It's too difficult to keep up with that. Your asynchronous code is already deprecated and disavowed.

First of all, make sure you try using the ClipboardViewer tool. I think it's in Xcode's AdditionalTools as a separate download. I know you're dealing with Drag and Drop, which is not quite the same, but it may be enlightening as most people implement Copy and Paste with the same data.

I've never tried dragging from Safari, but I certainly never seen any TIFF conversions. I even support data types that the system doesn't, so there's no way it ever could convert it.

Again, I think you're trying too hard. Instead of itemProvider.loadInPlaceFileRepresentation, try just loadItem. That should give you the actual URL.

You might run into concurrency problems. I seem to have encountered that myself with these APIs. Unfortunately, there's no easy solution. You definitely don't want to try those old dispatch queues, at least not in the final version. Swift Concurrency is much better.

However, you still have to be careful. Find a sweet spot and stick with it. Don't adopt an old technology like dispatch queue that Apple's already abandoned. But also don't jump on the bandwagon. If you start a new project with those beta versions, you'll get the latest Swift 6.2 MainActor concurrency, which you don't want yet. Don't get me wrong. It's a great idea, but it's not quite done yet. I've found Swift 6 to be pretty stable.

First of all, don't use comments to reply. They don't trigger notifications or update the status of a thread, and they're hidden.

I haven't looked at this code in some time. After reviewing it, I think see the problem.

It looks like you're trying to handle dragging of data, not URLs, from one app to another. There can be valid reasons for this. You may have an app that has an image where you can select part of it and copy/drag. There is no URL in this case. In most cases, the data is going to be converted to and transferred as TIFF data. But this is really an oddball use case. It's pretty rare for any app to support this. I don't have any image or vector apps that do this. Dragging always just moves things around.

But I'm pretty sure you are actually trying to support dragging of files. You explicitly said, "I can now support Drag-and-Drop from the Finder". That means you want URLs.

At a high level, there are two steps to this. First, use the UTIs that you've already listed as validation for your drop. You want files in all those raster (mostly) formats. There are various way to do this validation, but the key part is that these UTIs are for validating a drop.

But then, when you want to access the data being dropped, don't use those UTIs. Instead, coerce the item into a URL.

However, when I reviewed my code more closely, it looks like when my model called itemProvider.loadItem, that is only ever executed on iOS. While this API seems to exist on the Mac, I don't use it there.

I have one NSViewController subclass that adopts NSDraggingDestination. I override performDragOperation, get the draggingPasteboard from the NSDraggingInfo, and get the pasteboardItems from that. For each pasteboardItem, I get the data of type .fileURL, convert that to a URL via URL(dataRepresentation:relativeTo:)

Elsewhere, I'm using an NSOutlineView that has its own drag and drop support via NSOutlineViewDataSource. That gives me the same NSDraggingInfo.

On iOS, UICollectionView and UIDropInteractionDelegate seem to require NSItemProvider. I think on the Mac, that might exist only for SwiftUI.

For dragging things from Safari, it looks like you would want to add "public.url" to your validation UTIs. That will probably complicate your validation as any file would match. But I just tried Clipboard Viewer and it does support dragging. It look like Safari has a couple of "promise" types at the top. Your NSItemProvider likely expects a lot more logic to handle that. But I bet if you use the older logic that I described above, it will skip over the promises and get whatever data you want. In my one example from Avatar images here in the forum, it has PNG data, TIFF data, and then a public.url later on, in addition to a couple dozen other types.

Ty @Etresoft, for the answer. Yay comments being borked and not giving a notification is so fun.

So, I comtinued my search. 3rd day on this. As far as I can tell, and I don't know if that's a bug in the latest Beta or always was like that (or a case of it doesn't work on my machine), but it seems the .onDrop SwiftUI operation will only return one single element in passed NSItemProvider. So it's either one or zero representation. I can put everything in the of: [UTType], and it'll coalesce it into a single internal type.

This means, at this point, that unless I do loops and hoops, it's effectively a bug in the SwiftUI behaviour, where it will not allow me to drag and drop from Safari, since the URL is not file-based, and SwiftUI seemingly coded their things for file-based URLs, not web URLs.

That's 100% the opposite of PH photo providers, where it'll happily send me everything. Or the paste operation that's functional because it provides me the NSPasteboard directly through the contextual menu.

Because of that, once I am in the delegate, it's truly "too late" as the contents of the Drag pasteboard already got processed by the system. I tried asking for text, item, data, url, everything, but the only thing the onDrop sends me back is the unretrievable image (even asking for .url returns me the public.jpeg). So I will file a bug report and merely move on.

I'm sure I can do a ViewRepresentation and do the code in Obj-C, and actually retrieve the thing myself, but TBH, I don't mind much, and hope Apple fixes it someday.

I learned the VERY hard way (during SwiftUI's initial developer previews) you have to follow the intents of Apple, not try to do it how you envisioned it. If it's not how they made it to work, it won't work, or you'll have to backtrack the next year's version.

Drag-and-Drop from macOS Safari to NSItemProvider fails due to URL not being a file:// URL
 
 
Q