79561173

Date: 2025-04-08 04:34:32
Score: 0.5
Natty:
Report link

This thread really helped me with a problem and I thought I'd express my gratitude and the details of how it helped me in case it helps someone else in my situation.

The game I'm developing is a multi-platform RealityKit board game with Game Center (GameKit) support that has a single target with destinations for iOS, macOS, and visionOS (and I'm hoping for RealityKit support for tvOS this year?).

On macOS, my SwiftUI App declares a Window with content that's a ZStack with the BoardView that's a RealityView and an OverlayView with a SwiftUI overlay of controls for the scoreboard, starting a new game, etc. On iOS, it's a WindowGroup with the same ZStack of BoardView and OverlayView. On visionOS, it's two separate windows: a volumetric window with the RealityView game board, plus a "2D-ish" window for the overlay that is positioned per the .utitiltyPanel position. That makes the overlay much closer to the user than when I had added this overlay as a SwiftUI attachment, and it can present Game Center view controllers and Pickers and things that caused crashes as an attachment in the RealityView.

#if os(visionOS)
WindowGroup(id: MyBoardGameApp.gameboardVolumetricWindow) {
    BoardView(appState: appState)
}
.windowStyle(.volumetric)

ImmersiveSpace(id: MyBoardGameApp.immersiveSpaceName) {
    BoardView(appState: appState)
}
.immersionStyle(selection: $appState.immersionStyle, in: .mixed, .progressive)

WindowGroup(id: MyBoardGameApp.windowName) {
    OverlayView(appState: appState)
}
.windowStyle(.plain)
.defaultWindowPlacement { _, context in
    return WindowPlacement(.utilityPanel)
}
#elseif os(iOS)
WindowGroup(MyBoardGameApp.windowName, id: MyBoardGameApp.windowName) {
    ZStack {
        BoardView(appState: appState)
        OverlayView(appState: appState)
    }
}
#else
Window(MyBoardGameApp.windowName, id: MyBoardGameApp.windowName) {
    ZStack {
        BoardView(appState: appState)
        OverlayView(appState: appState)
    }
}
#endif

That utiltiyPanel window in addition to the volumetric window or immersive space with the game board requires that I make the Info.plist set the Application Scene Manifest : Enable Mulltiple Windows to true/YES. But if that's true, then when I run my app on iPadOS, I can opt to create a new window in split view or slide over, and my game doesn't support multiple instances of several objects like the gesture state, game board state, turn-based game state, etc. -- lots of use of static shared well-known instances (pseudo singletons). On macOS, the use of Window vs WindowGroup effectively blocks the creation of more than one window.

So I needed my single-target, multi-platform app to have one different Info.plist value for iOS vs visionOS.

That's where this post came to my rescue. Based on this post, I wrote this shell script and put it in my project next to the Info.plist:

#!/bin/sh
INFO_PLIST="$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH"
PLATFORM_NAME=${PLATFORM_NAME}
if [ "$PLATFORM_NAME" == "iphoneos" ] ; then
echo "DISABLING MULTIPLE SCENES FOR iOS"
/usr/libexec/PlistBuddy -c "Set UIApplicationSceneManifest:UIApplicationSupportsMultipleScenes false" "$INFO_PLIST"
fi

I added execution permissions to the script in Terminal with

chmod u+x NoMultipleScenesForiOSInfoPlist.sh

Then I went to Build Phases for my multi-platform target and clicked the + button to add a 'New Run Script Phase' - which I made sure to run at the end of the list per the advice here. In the new 'Run Script' code area I put the absolute path, like:

# Type a script or drag a script file from your workspace to insert its path.
/Users/andy/Developer/MyBoardGameApp/MyBoardGameApp/NoMultipleScenesForiOSInfoPlist.sh

And voila, iOS has no multiple-window support, visionOS does.

Grateful for everyone who participated in this thread!

-Andy

Reasons:
  • Blacklisted phrase (0.5): I need
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Low reputation (1):
Posted by: andymangobananas