Scene Phase issue with VisionOS 2.0

Hello,

I am new to swiftUI and VisionOS but I developed an app with a window and an ImmersiveSpace. I want the Immersive space to be dismissed when the window/app is closed.

I have the code below using the state of ScenePhase and it was working fine in Vision OS 1.1 but it stopped working with VisionOS 2.0.

Any idea what I am doing wrong? Is there another way to handle the dismissal of ImmersiveSpace when my main Window is closed?



@main
struct MyApp: App {
    
    @State private var viewModel = ViewModel()

    var body: some Scene {
        
        @Environment(\.scenePhase) var scenePhase
        @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
        
        WindowGroup {
            SideBarView()
                .environment(viewModel)
                .frame(width: 1150,height: 700)
                .onChange(of: scenePhase, { oldValue, newValue in
                    if newValue == .inactive || newValue == .background {
                        Task {
                            await dismissImmersiveSpace()
                            viewModel.immersiveSpaceIsShown = false
                        }
                    }
                })

        }.windowResizability(.contentSize)
           
        ImmersiveSpace(id: "ImmersiveSpace") {
            ImmersiveView(area: viewModel.currentModel)
                .environment(viewModel)
       }      

    }
}

Answered by Mike91601 in 791738022

I corrected as per your recommendation, it still had no effect. But I manage to get it to work by moving the "onchange" modifier inside the view itself.

Hi,

The above code didn't compile for me but changing it to something like this worked:

            .onChange(of: scenePhase) { (oldValue, newValue) in
                if newValue == .inactive || newValue == .background {
                    Task {
                        await dismissImmersiveSpace()
                        viewModel.immersiveSpaceIsShown = false
                    }
                }
            }
Accepted Answer

I corrected as per your recommendation, it still had no effect. But I manage to get it to work by moving the "onchange" modifier inside the view itself.

Hi, glad you figured it out! For people who may encounter this in the future, I'll point this out:

Where you place your scenePhase environment variable matters—not the onChange.

  • If you grab it from within your App, you will get an aggregate phase for all your scenes—this should become "background" only if all scenes have been backgrounded.
  • However, grabbing it in a View will give the phase for that view's scene only.

See the documentation for scenePhase for more information.

So, if you wanted to know if your ImmersiveSpace was being backgrounded, you should use the scenePhase inside of your ImmersiveView.

Here's an example to demonstrate:

import SwiftUI

@main
struct MyApp: App {
    @Environment(\.scenePhase) private var scenePhase

    var body: some Scene {
        WindowGroup() {
            ContentView()
        }
        .onChange(of: scenePhase, initial: true) {
            print("App scenePhase: \(scenePhase)")
        }

        ImmersiveSpace(id: "ImmersiveSpace") {
            ImmersiveView()
        }
    }
}

struct ContentView: View {
    @Environment(\.scenePhase) private var scenePhase
    @Environment(\.openImmersiveSpace) private var openImmersiveSpace
    @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace

    var body: some View {
        NavigationStack {
            Button("Open Immersive Space") {
                Task { await openImmersiveSpace(id: "ImmersiveSpace") }
            }
            Button("Close Immersive Space") {
                Task { await dismissImmersiveSpace() }
            }
        }
        .onChange(of: scenePhase, initial: true) {
            print("Window scenePhase: \(scenePhase)")
        }
    }
}

struct ImmersiveView: View {
    @Environment(\.scenePhase) private var scenePhase

    var body: some View {
        MyImmersiveView()
            .onChange(of: scenePhase, initial: true) {
                print("ImmersiveSpace scenePhase: \(scenePhase)")
            }
    }
}
Scene Phase issue with VisionOS 2.0
 
 
Q