From 39864ff50f5fd5fd29c2ba653f4bad8202e93e83 Mon Sep 17 00:00:00 2001 From: Rui Siu Date: Sat, 26 Sep 2026 13:22:57 -0700 Subject: [PATCH] Fix iOS scene lifecycle startup --- apps/mobile/app.json | 1 + apps/mobile/plugins/withIOSSceneLifecycle.js | 62 ++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 apps/mobile/plugins/withIOSSceneLifecycle.js diff --git a/apps/mobile/app.json b/apps/mobile/app.json index 5c782733..51297594 100644 --- a/apps/mobile/app.json +++ b/apps/mobile/app.json @@ -11,6 +11,7 @@ "android": { "package": "app.openmuse.mobile" }, "web": { "bundler": "metro", "name": "OpenMuse — a little room for everything" }, "plugins": [ + "./plugins/withIOSSceneLifecycle", "expo-document-picker", "@config-plugins/react-native-blob-util", "@config-plugins/react-native-pdf" diff --git a/apps/mobile/plugins/withIOSSceneLifecycle.js b/apps/mobile/plugins/withIOSSceneLifecycle.js new file mode 100644 index 00000000..c6a4e455 --- /dev/null +++ b/apps/mobile/plugins/withIOSSceneLifecycle.js @@ -0,0 +1,62 @@ +const fs = require("node:fs"); +const path = require("node:path"); +const { withDangerousMod, withInfoPlist, withXcodeProject } = require("expo/config-plugins"); + +const sceneDelegate = `import UIKit + +final class SceneDelegate: UIResponder, UIWindowSceneDelegate { + var window: UIWindow? + + func scene( + _ scene: UIScene, + willConnectTo session: UISceneSession, + options connectionOptions: UIScene.ConnectionOptions + ) { + guard let windowScene = scene as? UIWindowScene else { return } + guard let appWindow = (UIApplication.shared.delegate as? AppDelegate)?.window else { return } + appWindow.windowScene = windowScene + window = appWindow + appWindow.makeKeyAndVisible() + } +} +`; + +function withIOSSceneLifecycle(config) { + config = withInfoPlist(config, (mod) => { + mod.modResults.UIApplicationSceneManifest = { + UIApplicationSupportsMultipleScenes: false, + UISceneConfigurations: { + UIWindowSceneSessionRoleApplication: [ + { + UISceneConfigurationName: "Default Configuration", + UISceneDelegateClassName: "$(PRODUCT_MODULE_NAME).SceneDelegate", + }, + ], + }, + }; + return mod; + }); + + config = withDangerousMod(config, [ + "ios", + async (mod) => { + const filePath = path.join( + mod.modRequest.platformProjectRoot, + mod.modRequest.projectName, + "SceneDelegate.swift", + ); + fs.writeFileSync(filePath, sceneDelegate); + return mod; + }, + ]); + + return withXcodeProject(config, (mod) => { + const project = mod.modResults; + const target = project.getFirstTarget(); + if (!project.hasFile("OpenMuse/SceneDelegate.swift")) + project.addSourceFile("OpenMuse/SceneDelegate.swift", { target: target.uuid }, "OpenMuse"); + return mod; + }); +} + +module.exports = withIOSSceneLifecycle;