Search code examples
iosswiftuiwindow

Launch new window on iOS app using SwiftUI Lifecycle


The following code on WindowScene does indeed open a new window on macOS when a button is pressed in ContentView that opens an URL:

import SwiftUI

@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    
        WindowGroup("Viewer") {
            Text("Viewer").padding()
        }
        .handlesExternalEvents(matching: ["*"])
    }
}

However, when the same is applied to iOS, the app does not do anything when the openURL action is called.

The result from my research is that I can use the traditional requestSceneSessionActivation to open window manually. However, this will defeat the purpose of using the SwiftUI app lifecycle.

Any suggestions on a working method, without reverting back to the UIKit lifecycle?


Solution

  • After a very long research session, I finally found the property that does this in this blog post.

    Turns out that requestSceneSessionActivation is necessary, but there's no need to use a SceneDelegate.

    When creating the new session, set the targetContentIdentifier on the NSUserActivity object.

    let activity = NSUserActivity(activityType: "newWindow")
    activity.userInfo = ["some key":"some value"]
    activity.targetContentIdentifier = "newWindow" // IMPORTANT
    UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil)
    

    Finally, make sure the new WindowGroup can handle the event with the identifier:

    WindowGroup(id: "newWindow") {
        Text("New Window!").padding()
    }
    .handlesExternalEvents(matching: ["newWindow"])
    

    This solution retains the SwiftUI Lifecycle, and also works on Catalyst.


    Update for iPadOS 16/macOS Ventura:

    You can now use the new openWindow environment property:

    @Environment(\.openWindow) private var openWindow
    ...
    openWindow(id: "newWindow")
    

    Make sure the id passed to openWindow is the same as the id set in the WindowGroup or Window initializer.