Handle multiple URLs from Open With in SwiftUI on Mac

Viewed 330

In SwiftUI we have been given the onOpenURL(perform:) function. However, in macOS we can select multiple files in Finder and click on Open With. If I open these files with an app with code such as:

@main
struct testURLMacApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onOpenURL { url in
                    print("RECEIVED \(url)")
                }
        }
    }
}

it appears this function does not work properly for multiple files. It appears to sometimes to call the perform closure once, or sometimes if lucky 2-3 times max in succession. Sometimes it appears to do weird things like open a duplicate app window.

Has anyone found out a workaround for this, or the proper way of handling opening multiple files in a single window in a SwiftUI app?

EDIT: This is actually for making an existing iOS app work on Apple Sillicon Macs. So AppKit is not available.

1 Answers

As described (see below) it registers handler for external events, but uses only first to create new scene (maybe due to limitations, maybe bug, maybe intentionally, who knows...)

demo1

so if we have .onOpenURL that registered handler captures one URL and create new scene for it, others are remains unhandled and received in AppDelegate (see below). If we remove .onOpenURL completely, all opened URLs from Finder transferred to AppDelegate.

Tested with Xcode 13.4 / macOS 12.4

in App

@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
    WindowGroup {
        ContentView()
    }
    // needed because WindowGroup scene seems have default
    // handler for external events, so opens new scene even
    // if no onOpenURL or userActivity callbacks are present
    .handlesExternalEvents(matching: [])   // << here !!
}

and delegate

class AppDelegate: NSObject, NSApplicationDelegate {
    func application(_ application: NSApplication, open urls: [URL]) {
        print("Unhandled: \(urls)")    // << here !!
    }
}

Compelete test module is here

Related