fix(apple): enforce a single window on macOS and iPadOS

macOS uses a single-instance `Window` scene instead of `WindowGroup`, which
otherwise lets the app open multiple windows (via ⌘N). iPadOS sets
`UIApplicationSupportsMultipleScenes = false` to block a second scene via Stage
Manager / split view. (`LSMultipleInstancesProhibited` only blocks a second
process, not a second window.)
This commit is contained in:
2026-07-24 13:19:26 +02:00
parent 42f569dcf0
commit 20597e6e88
2 changed files with 18 additions and 1 deletions

View File

@@ -1,5 +1,8 @@
import SwiftUI
/// Scene identifier for the single main window.
private let mainWindowId = "main"
/// Native app entry point for iOS, iPadOS, and macOS.
/// Opens `.vnd` invitations via `onOpenURL` and routes them to the receive flow.
@main
@@ -7,11 +10,21 @@ struct VniDropApp: App {
@StateObject private var externalInvitations = ExternalInvitationController()
var body: some Scene {
WindowGroup {
#if os(macOS)
// A single-instance `Window` (not `WindowGroup`): the app must never open a
// second window. `Window` also drops the N "New Window" command.
Window(Text(verbatim: "VniDrop"), id: mainWindowId) {
RootView(dependencies: makeAppDependencies(externalInvitations: externalInvitations))
.ignoresSafeArea()
.onOpenURL(perform: openInvitation)
}
#else
WindowGroup(id: mainWindowId) {
RootView(dependencies: makeAppDependencies(externalInvitations: externalInvitations))
.ignoresSafeArea()
.onOpenURL(perform: openInvitation)
}
#endif
}
/// Reads a `.vnd` invitation document under a security scope, enforcing the

View File

@@ -67,6 +67,10 @@
<string>VniDrop uses the camera to scan transfer QR codes.</string>
<key>NSLocalNetworkUsageDescription</key>
<string>VniDrop needs local network access to send to other local devices if needed.</string>
<!-- iPadOS: a single scene only — no second window via Stage Manager / split
view. Mirrors the single-window macOS behavior. -->
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>