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