Search code examples
swiftmacosswiftui

How to access NSWindow from @main App using only SwiftUI?


At this answer the solution work for Scene plus swiftUI.

However using @main like:

@main
struct MyApp: App {
    @StateObject private var model = MyModel()
    
    var body: some Scene {
        WindowGroup {
            Router {
                AppContent()
            }.environmentObject(self.model)
        }
    }
}

I also tried to get the main window by using

var window: NSWindow? {
        let window = NSApplication.shared.mainWindow
        return window
    }

Nevertheless, the mainWindow always return nil

Update:

I need the NSWindow due to the need of conforming with ASWebAuthenticationPresentationContextProviding which obligates to return a NSWindow. Basically, I'm trying to do something like:

LoginView(store: AuthStore(window: window))

Where AuthStore uses the AuthenticationServices to perform an authentication.


Solution

  • Basically, I'm trying to do something like:

    LoginView(store: AuthStore(window: window))

    Here is a demo of possible approach (with some replicated entities)

    demo

    class AuthStore {
        var window: NSWindow
    
        init(window: NSWindow) {
            self.window = window
        }
    }
    
    struct DemoWindowAccessor: View {
        @State private var window: NSWindow?   // << detected in run-time so optional
        var body: some View {
            VStack {
                if nil != window {
                    LoginView(store: AuthStore(window: window!))    // << usage
                }
            }.background(WindowAccessor(window: $window))
        }
    }
    
    struct WindowAccessor: NSViewRepresentable {
        @Binding var window: NSWindow?
    
        func makeNSView(context: Context) -> NSView {
            let view = NSView()
            DispatchQueue.main.async {
                self.window = view.window   // << right after inserted in window
            }
            return view
        }
    
        func updateNSView(_ nsView: NSView, context: Context) {}
    }
    
    struct LoginView: View {
        let store: AuthStore
    
        var body: some View {
            Text("LoginView with Window: \(store.window)")
        }
    }