From c813bca11518a15b5b4e4ed659f7fb546029a576 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 06:40:52 +0000 Subject: [PATCH 1/6] Add expo-ios-scene-lifecycle-plugin workaround for Xcode 27 beta Expo SDK 56 prebuild templates crash on iOS 27 / Xcode 27 beta because Apple now requires the UIKit scene-based lifecycle. This temporary plugin patches Info.plist and AppDelegate.swift during prebuild until Expo adds native support. Ref: https://github.com/expo/expo/issues/46664 https://claude.ai/code/session_01WYWCN8jNbVMaUXFTp3GREU --- app.config.js | 1 + package-lock.json | 19 +++++++++++++++++++ package.json | 1 + 3 files changed, 21 insertions(+) diff --git a/app.config.js b/app.config.js index c4d28d1b..b75681ff 100644 --- a/app.config.js +++ b/app.config.js @@ -120,6 +120,7 @@ export default { githubUrl: 'https://github.com/wyne/scorepad-react-native', owner: 'wyne', plugins: [ + 'expo-ios-scene-lifecycle-plugin', ['expo-splash-screen', { backgroundColor: '#F2F2F7', dark: { backgroundColor: '#000000' }, diff --git a/package-lock.json b/package-lock.json index aafd7167..debd25a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "expo-font": "~56.0.5", "expo-haptics": "~56.0.3", "expo-image": "~56.0.10", + "expo-ios-scene-lifecycle-plugin": "github:YesterdaysLemon/expo-ios-scene-lifecycle-plugin", "expo-keep-awake": "~56.0.3", "expo-linking": "~56.0.13", "expo-screen-orientation": "~56.0.5", @@ -11206,6 +11207,17 @@ } } }, + "node_modules/expo-ios-scene-lifecycle-plugin": { + "version": "0.1.0", + "resolved": "git+ssh://git@github.com/YesterdaysLemon/expo-ios-scene-lifecycle-plugin.git#dfd1786e687996061617d14bd5e1069880a85ded", + "license": "MIT", + "dependencies": { + "@expo/config-plugins": "^56.0.8" + }, + "peerDependencies": { + "expo": ">=56.0.0" + } + }, "node_modules/expo-json-utils": { "version": "56.0.0", "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-56.0.0.tgz", @@ -28381,6 +28393,13 @@ "sf-symbols-typescript": "^2.2.0" } }, + "expo-ios-scene-lifecycle-plugin": { + "version": "git+ssh://git@github.com/YesterdaysLemon/expo-ios-scene-lifecycle-plugin.git#dfd1786e687996061617d14bd5e1069880a85ded", + "from": "expo-ios-scene-lifecycle-plugin@github:YesterdaysLemon/expo-ios-scene-lifecycle-plugin", + "requires": { + "@expo/config-plugins": "^56.0.8" + } + }, "expo-json-utils": { "version": "56.0.0", "resolved": "https://registry.npmjs.org/expo-json-utils/-/expo-json-utils-56.0.0.tgz", diff --git a/package.json b/package.json index a0746196..0a93d721 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "expo-font": "~56.0.5", "expo-haptics": "~56.0.3", "expo-image": "~56.0.10", + "expo-ios-scene-lifecycle-plugin": "github:YesterdaysLemon/expo-ios-scene-lifecycle-plugin", "expo-keep-awake": "~56.0.3", "expo-linking": "~56.0.13", "expo-screen-orientation": "~56.0.5", From 4e989c7b12e462118df5f54a74906df279c8a540 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 15:49:31 +0000 Subject: [PATCH 2/6] Fix expo-ios-scene-lifecycle-plugin regex for indented #endif The plugin regex assumed #endif was unindented, but Expo SDK 56's generated AppDelegate.swift indents it with 4 spaces, causing the pattern match to fail. Changed \n#endif to \n[ \t]*#endif to allow leading whitespace. https://claude.ai/code/session_01WYWCN8jNbVMaUXFTp3GREU --- patches/expo-ios-scene-lifecycle-plugin+0.1.0.patch | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 patches/expo-ios-scene-lifecycle-plugin+0.1.0.patch diff --git a/patches/expo-ios-scene-lifecycle-plugin+0.1.0.patch b/patches/expo-ios-scene-lifecycle-plugin+0.1.0.patch new file mode 100644 index 00000000..a10709df --- /dev/null +++ b/patches/expo-ios-scene-lifecycle-plugin+0.1.0.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/expo-ios-scene-lifecycle-plugin/app.plugin.js b/node_modules/expo-ios-scene-lifecycle-plugin/app.plugin.js +index c3f914c..3c470de 100644 +--- a/node_modules/expo-ios-scene-lifecycle-plugin/app.plugin.js ++++ b/node_modules/expo-ios-scene-lifecycle-plugin/app.plugin.js +@@ -91,7 +91,7 @@ function patchAppDelegate(contents) { + let nextContents = contents; + + const startupBlockPattern = +- /#if os\(iOS\) \|\| os\(tvOS\)\n\s*window = UIWindow\(frame: UIScreen\.main\.bounds\)\n\s*factory\.startReactNative\(\n\s*withModuleName: "main",\n\s*in: window,\n\s*launchOptions: launchOptions\)\n#endif/; ++ /#if os\(iOS\) \|\| os\(tvOS\)\n\s*window = UIWindow\(frame: UIScreen\.main\.bounds\)\n\s*factory\.startReactNative\(\n\s*withModuleName: "main",\n\s*in: window,\n\s*launchOptions: launchOptions\)\n[ \t]*#endif/; + + if (!startupBlockPattern.test(nextContents)) { + throw new Error('Could not find the Expo AppDelegate React Native startup block to patch for UIScene lifecycle.'); From 3c00f16743264bc815c4825e906f97b81a95d0ad Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 16:09:36 +0000 Subject: [PATCH 3/6] Replace npm scene lifecycle plugin with local fixed copy The EAS local build runs npm install without scripts, so patch-package never applies. Moving the plugin inline to plugins/withIosSceneLifecycle.js ensures the regex fix (allowing indented #endif) is always in effect. https://claude.ai/code/session_01WYWCN8jNbVMaUXFTp3GREU --- app.config.js | 2 +- plugins/withIosSceneLifecycle.js | 154 +++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 plugins/withIosSceneLifecycle.js diff --git a/app.config.js b/app.config.js index b75681ff..65f8c4b1 100644 --- a/app.config.js +++ b/app.config.js @@ -120,7 +120,7 @@ export default { githubUrl: 'https://github.com/wyne/scorepad-react-native', owner: 'wyne', plugins: [ - 'expo-ios-scene-lifecycle-plugin', + './plugins/withIosSceneLifecycle', ['expo-splash-screen', { backgroundColor: '#F2F2F7', dark: { backgroundColor: '#000000' }, diff --git a/plugins/withIosSceneLifecycle.js b/plugins/withIosSceneLifecycle.js new file mode 100644 index 00000000..3e166fcc --- /dev/null +++ b/plugins/withIosSceneLifecycle.js @@ -0,0 +1,154 @@ +// Local copy of expo-ios-scene-lifecycle-plugin with fixed regex. +// The upstream package regex assumed #endif was unindented, but Expo SDK 56 +// generates AppDelegate.swift with an indented #endif. Changed \n#endif to +// \n[ \t]*#endif to allow leading whitespace. +// Ref: https://github.com/expo/expo/issues/46664 +const { withAppDelegate, withInfoPlist } = require('@expo/config-plugins'); + +const sceneConfigurationMethod = ` public func application( + _ application: UIApplication, + configurationForConnecting connectingSceneSession: UISceneSession, + options: UIScene.ConnectionOptions + ) -> UISceneConfiguration { + let configuration = UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + configuration.delegateClass = SceneDelegate.self + return configuration + } +`; + +const sceneDelegateClass = `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 appDelegate = UIApplication.shared.delegate as? AppDelegate, + let factory = appDelegate.reactNativeFactory else { + return + } + + let nextWindow = UIWindow(windowScene: windowScene) + window = nextWindow + appDelegate.window = nextWindow + + factory.startReactNative( + withModuleName: "main", + in: nextWindow, + launchOptions: nil) + + if !connectionOptions.urlContexts.isEmpty { + self.scene(scene, openURLContexts: connectionOptions.urlContexts) + } + } + + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { + guard let urlContext = URLContexts.first, + let appDelegate = UIApplication.shared.delegate as? AppDelegate else { + return + } + + var options: [UIApplication.OpenURLOptionsKey: Any] = [ + .openInPlace: urlContext.options.openInPlace, + ] + + if let sourceApplication = urlContext.options.sourceApplication { + options[.sourceApplication] = sourceApplication + } + + if let annotation = urlContext.options.annotation { + options[.annotation] = annotation + } + + _ = appDelegate.application(UIApplication.shared, open: urlContext.url, options: options) + } +} +`; + +function addInfoPlistSceneManifest(config) { + return withInfoPlist(config, (nextConfig) => { + nextConfig.modResults.UIApplicationSceneManifest = { + UIApplicationSupportsMultipleScenes: false, + UISceneConfigurations: { + UIWindowSceneSessionRoleApplication: [ + { + UISceneConfigurationName: 'Default Configuration', + UISceneDelegateClassName: '$(PRODUCT_MODULE_NAME).SceneDelegate', + }, + ], + }, + }; + + return nextConfig; + }); +} + +function patchAppDelegate(contents) { + if (contents.includes('class SceneDelegate: UIResponder, UIWindowSceneDelegate')) { + return contents; + } + + let nextContents = contents; + + // Allow optional leading whitespace before #endif — Expo SDK 56 generates + // AppDelegate.swift with an indented #endif inside function bodies. + const startupBlockPattern = + /#if os\(iOS\) \|\| os\(tvOS\)\n\s*window = UIWindow\(frame: UIScreen\.main\.bounds\)\n\s*factory\.startReactNative\(\n\s*withModuleName: "main",\n\s*in: window,\n\s*launchOptions: launchOptions\)\n[ \t]*#endif/; + + if (!startupBlockPattern.test(nextContents)) { + throw new Error('Could not find the Expo AppDelegate React Native startup block to patch for UIScene lifecycle.'); + } + + nextContents = nextContents.replace( + startupBlockPattern, + `#if os(iOS) || os(tvOS) + if #unavailable(iOS 13.0) { + window = UIWindow(frame: UIScreen.main.bounds) + factory.startReactNative( + withModuleName: "main", + in: window, + launchOptions: launchOptions) + } +#endif`, + ); + + if (!nextContents.includes('configurationForConnecting connectingSceneSession')) { + const linkingMarker = '\n // Linking API'; + + if (!nextContents.includes(linkingMarker)) { + throw new Error('Could not find the AppDelegate linking section to insert the UIScene configuration method.'); + } + + nextContents = nextContents.replace(linkingMarker, `\n${sceneConfigurationMethod}\n // Linking API`); + } + + const reactNativeDelegateMarker = '\nclass ReactNativeDelegate: ExpoReactNativeFactoryDelegate'; + + if (!nextContents.includes(reactNativeDelegateMarker)) { + throw new Error('Could not find ReactNativeDelegate to insert SceneDelegate.'); + } + + return nextContents.replace(reactNativeDelegateMarker, `\n${sceneDelegateClass}${reactNativeDelegateMarker}`); +} + +function addAppDelegateSceneLifecycle(config) { + return withAppDelegate(config, (nextConfig) => { + if (nextConfig.modResults.language !== 'swift') { + throw new Error( + `Cannot apply iOS scene lifecycle plugin to ${nextConfig.modResults.language} AppDelegate. Swift is required.`, + ); + } + + nextConfig.modResults.contents = patchAppDelegate(nextConfig.modResults.contents); + return nextConfig; + }); +} + +module.exports = function withIosSceneLifecycle(config) { + return addAppDelegateSceneLifecycle(addInfoPlistSceneManifest(config)); +}; From 7cf0c2c388c61925692e0d0540f72550ec1ec193 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 16:20:02 +0000 Subject: [PATCH 4/6] Fix scene lifecycle plugin to handle injected code between UIWindow and startReactNative The previous approach matched the UIWindow creation and factory.startReactNative as a single adjacent block, but other plugins (Firebase, TouchVisualizer) inject code between them in this project's AppDelegate.swift. Now each line is targeted and wrapped independently with if #unavailable(iOS 13.0), preserving all injected code while correctly gating the scene-incompatible calls. https://claude.ai/code/session_01WYWCN8jNbVMaUXFTp3GREU --- plugins/withIosSceneLifecycle.js | 54 +++++++++++++++++--------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/plugins/withIosSceneLifecycle.js b/plugins/withIosSceneLifecycle.js index 3e166fcc..2995d4eb 100644 --- a/plugins/withIosSceneLifecycle.js +++ b/plugins/withIosSceneLifecycle.js @@ -1,7 +1,8 @@ -// Local copy of expo-ios-scene-lifecycle-plugin with fixed regex. -// The upstream package regex assumed #endif was unindented, but Expo SDK 56 -// generates AppDelegate.swift with an indented #endif. Changed \n#endif to -// \n[ \t]*#endif to allow leading whitespace. +// Local copy of expo-ios-scene-lifecycle-plugin with revised patching strategy. +// The upstream plugin matched the entire #if os(iOS) ... #endif block as one unit, +// which breaks when other plugins (Firebase, TouchVisualizer) inject code between +// `window = UIWindow(...)` and `factory.startReactNative(...)`. +// Instead, we target each line individually and wrap them in if #unavailable(iOS 13.0). // Ref: https://github.com/expo/expo/issues/46664 const { withAppDelegate, withInfoPlist } = require('@expo/config-plugins'); @@ -95,40 +96,41 @@ function patchAppDelegate(contents) { let nextContents = contents; - // Allow optional leading whitespace before #endif — Expo SDK 56 generates - // AppDelegate.swift with an indented #endif inside function bodies. - const startupBlockPattern = - /#if os\(iOS\) \|\| os\(tvOS\)\n\s*window = UIWindow\(frame: UIScreen\.main\.bounds\)\n\s*factory\.startReactNative\(\n\s*withModuleName: "main",\n\s*in: window,\n\s*launchOptions: launchOptions\)\n[ \t]*#endif/; - - if (!startupBlockPattern.test(nextContents)) { - throw new Error('Could not find the Expo AppDelegate React Native startup block to patch for UIScene lifecycle.'); + // Wrap the window creation line — capture only horizontal whitespace (spaces/tabs) + // so the preceding newline isn't included and we don't get spurious blank lines. + const windowPattern = /([ \t]+)window = UIWindow\(frame: UIScreen\.main\.bounds\)/; + if (!windowPattern.test(nextContents)) { + throw new Error( + 'Could not find "window = UIWindow(frame: UIScreen.main.bounds)" to patch for UIScene lifecycle.' + ); } + nextContents = nextContents.replace(windowPattern, (_, ws) => + `${ws}if #unavailable(iOS 13.0) {\n${ws} window = UIWindow(frame: UIScreen.main.bounds)\n${ws}}` + ); - nextContents = nextContents.replace( - startupBlockPattern, - `#if os(iOS) || os(tvOS) - if #unavailable(iOS 13.0) { - window = UIWindow(frame: UIScreen.main.bounds) - factory.startReactNative( - withModuleName: "main", - in: window, - launchOptions: launchOptions) - } -#endif`, + // Wrap the factory.startReactNative call — capture only horizontal whitespace. + const factoryPattern = + /([ \t]+)factory\.startReactNative\(\n[ \t]+withModuleName: "main",\n[ \t]+in: window,\n[ \t]+launchOptions: launchOptions\)/; + if (!factoryPattern.test(nextContents)) { + throw new Error( + 'Could not find "factory.startReactNative(...)" block to patch for UIScene lifecycle.' + ); + } + nextContents = nextContents.replace(factoryPattern, (_, ws) => + `${ws}if #unavailable(iOS 13.0) {\n${ws} factory.startReactNative(\n${ws} withModuleName: "main",\n${ws} in: window,\n${ws} launchOptions: launchOptions)\n${ws}}` ); + // Insert the scene configuration method before the Linking API section. if (!nextContents.includes('configurationForConnecting connectingSceneSession')) { const linkingMarker = '\n // Linking API'; - if (!nextContents.includes(linkingMarker)) { throw new Error('Could not find the AppDelegate linking section to insert the UIScene configuration method.'); } - nextContents = nextContents.replace(linkingMarker, `\n${sceneConfigurationMethod}\n // Linking API`); } + // Insert the SceneDelegate class before ReactNativeDelegate. const reactNativeDelegateMarker = '\nclass ReactNativeDelegate: ExpoReactNativeFactoryDelegate'; - if (!nextContents.includes(reactNativeDelegateMarker)) { throw new Error('Could not find ReactNativeDelegate to insert SceneDelegate.'); } @@ -140,7 +142,7 @@ function addAppDelegateSceneLifecycle(config) { return withAppDelegate(config, (nextConfig) => { if (nextConfig.modResults.language !== 'swift') { throw new Error( - `Cannot apply iOS scene lifecycle plugin to ${nextConfig.modResults.language} AppDelegate. Swift is required.`, + `Cannot apply iOS scene lifecycle plugin to ${nextConfig.modResults.language} AppDelegate. Swift is required.` ); } From 9c11ebb558f5738996996a6936cdfa19adf95536 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 16:34:48 +0000 Subject: [PATCH 5/6] Add withPodsDeploymentTarget plugin for Xcode 27 beta compatibility Xcode 27 beta requires all pod targets to have IPHONEOS_DEPLOYMENT_TARGET >= 15.0, but many third-party pods (AsyncStorage, RNSVG, Firebase/Google libs) still ship with older minimums (9.0 - 13.4). Injects a post_install Ruby hook into the Podfile to raise any sub-15.0 target at pod install time. https://claude.ai/code/session_01WYWCN8jNbVMaUXFTp3GREU --- app.config.js | 1 + plugins/withPodsDeploymentTarget.js | 43 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 plugins/withPodsDeploymentTarget.js diff --git a/app.config.js b/app.config.js index 65f8c4b1..faf2f22c 100644 --- a/app.config.js +++ b/app.config.js @@ -121,6 +121,7 @@ export default { owner: 'wyne', plugins: [ './plugins/withIosSceneLifecycle', + './plugins/withPodsDeploymentTarget', ['expo-splash-screen', { backgroundColor: '#F2F2F7', dark: { backgroundColor: '#000000' }, diff --git a/plugins/withPodsDeploymentTarget.js b/plugins/withPodsDeploymentTarget.js new file mode 100644 index 00000000..91c90dcd --- /dev/null +++ b/plugins/withPodsDeploymentTarget.js @@ -0,0 +1,43 @@ +// Raises any CocoaPods target whose IPHONEOS_DEPLOYMENT_TARGET is below 15.0. +// Xcode 27 beta requires a minimum of 15.0 across all targets, but many third-party +// pods still ship with older minimums (9.0, 12.x, 13.x), causing archive failures. +const { withDangerousMod } = require('@expo/config-plugins'); +const fs = require('fs'); +const path = require('path'); + +const MIN_TARGET = '15.0'; + +const deploymentTargetFix = ` + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < ${MIN_TARGET} + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '${MIN_TARGET}' + end + end + end +`; + +module.exports = function withPodsDeploymentTarget(config) { + return withDangerousMod(config, [ + 'ios', + (config) => { + const podfilePath = path.join(config.modRequest.platformProjectRoot, 'Podfile'); + let podfile = fs.readFileSync(podfilePath, 'utf8'); + + const marker = ' post_install do |installer|\n react_native_post_install('; + if (!podfile.includes(marker)) { + throw new Error( + 'withPodsDeploymentTarget: Could not find post_install block in Podfile to inject deployment target fix.' + ); + } + + podfile = podfile.replace( + marker, + ` post_install do |installer|${deploymentTargetFix} react_native_post_install(` + ); + + fs.writeFileSync(podfilePath, podfile); + return config; + }, + ]); +}; From ffde889c972ca684ce7c3ad799d69c055bbdc99f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 14 Jun 2026 16:45:22 +0000 Subject: [PATCH 6/6] Patch expo-modules-jsi weak let for Swift 6.2 / Xcode 27 beta MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swift 6.2 (bundled with Xcode 27 beta) no longer accepts `weak let` since weak references are implicitly mutable. expo-modules-jsi@56.0.7 uses this pattern in 15 Swift files, causing the ExpoModulesJSI xcframework build to fail silently with exit code 1. Adds a Podfile post_install hook to rewrite `weak let` → `nonisolated(unsafe) weak var` across all ExpoModulesJSI Swift sources after pod install but before xcodebuild runs the xcframework build script. Ref: https://github.com/expo/expo/issues/46242 https://claude.ai/code/session_01WYWCN8jNbVMaUXFTp3GREU --- plugins/withPodsDeploymentTarget.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/plugins/withPodsDeploymentTarget.js b/plugins/withPodsDeploymentTarget.js index 91c90dcd..133711b4 100644 --- a/plugins/withPodsDeploymentTarget.js +++ b/plugins/withPodsDeploymentTarget.js @@ -1,6 +1,10 @@ // Raises any CocoaPods target whose IPHONEOS_DEPLOYMENT_TARGET is below 15.0. // Xcode 27 beta requires a minimum of 15.0 across all targets, but many third-party // pods still ship with older minimums (9.0, 12.x, 13.x), causing archive failures. +// +// Also patches expo-modules-jsi Swift source for Swift 6.2 / Xcode 27 compatibility: +// `weak let runtime` is no longer valid in Swift 6.2 — must be `nonisolated(unsafe) weak var`. +// Ref: https://github.com/expo/expo/issues/46242 const { withDangerousMod } = require('@expo/config-plugins'); const fs = require('fs'); const path = require('path'); @@ -17,6 +21,18 @@ const deploymentTargetFix = ` end `; +// Patches weak let → nonisolated(unsafe) weak var across expo-modules-jsi Swift sources. +// The xcframework build runs after pod install, reading from ${PODS_ROOT}/ExpoModulesJSI/, +// so patching here is sufficient. +const expoModulesJSIFix = ` + jsi_sources = Dir.glob(File.join(installer.sandbox.root, 'ExpoModulesJSI', '**', '*.swift')) + jsi_sources.each do |file| + content = File.read(file) + modified = content.gsub(/\\bweak let /, 'nonisolated(unsafe) weak var ') + File.write(file, modified) if modified != content + end +`; + module.exports = function withPodsDeploymentTarget(config) { return withDangerousMod(config, [ 'ios', @@ -27,13 +43,13 @@ module.exports = function withPodsDeploymentTarget(config) { const marker = ' post_install do |installer|\n react_native_post_install('; if (!podfile.includes(marker)) { throw new Error( - 'withPodsDeploymentTarget: Could not find post_install block in Podfile to inject deployment target fix.' + 'withPodsDeploymentTarget: Could not find post_install block in Podfile to inject fixes.' ); } podfile = podfile.replace( marker, - ` post_install do |installer|${deploymentTargetFix} react_native_post_install(` + ` post_install do |installer|${deploymentTargetFix}${expoModulesJSIFix} react_native_post_install(` ); fs.writeFileSync(podfilePath, podfile);