Couldn't find "PLATFORM_NAME" variable in Xcodebuild output when providing binaryPath
Environment
System:
OS: macOS 14.6.1
CPU: (12) arm64 Apple M2 Pro
Memory: 435.45 MB / 32.00 GB
Shell:
version: 3.6.1
path: /opt/homebrew/bin/fish
Binaries:
Node:
version: 22.7.0
path: /opt/homebrew/bin/node
Yarn:
version: 1.22.19
path: /opt/homebrew/bin/yarn
npm:
version: 10.8.2
path: /opt/homebrew/bin/npm
Watchman: Not Found
Managers:
CocoaPods:
version: 1.15.0
path: /Users/kgwc595/.rbenv/shims/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 24.0
- iOS 18.0
- macOS 15.0
- tvOS 18.0
- visionOS 2.0
- watchOS 11.0
Android SDK: Not Found
IDEs:
Android Studio: 2023.3 AI-233.14808.21.2331.11709847
Xcode:
version: 16.0/16A242d
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.11
path: /opt/homebrew/opt/openjdk@17/bin/javac
Ruby:
version: 3.1.4
path: /Users/kgwc595/.rbenv/shims/ruby
npmPackages:
"@react-native-community/cli":
installed: 13.6.1
wanted: 13.6.1
react:
installed: 18.3.1
wanted: 18.3.1
react-native:
installed: 0.74.1
wanted: 0.74.1
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: false
newArchEnabled: false
Description
When providing the option --binary-path to run-ios the following error happens and fails the install:
Couldn't find "PLATFORM_NAME variable in Xcodebuild output
After doing some digging in the code for cli-platform-apple we see that in the file getBuildSettings.ts the function getPlatformName is called with buildOutput. The problem is that in the file runOnSimulator.ts (that calls getBuildSettings) the buildOutput variable is set as an empty string when providing a binaryPath.
Reproducible Demo
Haven't tried in a fresh React Native project but it should be present there as well. So create a React Native project with an iOS artifact already built and then run:
yarn react-native run-ios --binary-path= ./ios/build/Build/Products/Debug-iphonesimulator/MyApp.app
There hasn't been any activity on this issue in the past 3 months, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days.
@emilundg I'm running into this as well during my RN 0.79.2 upgrade. Did you find a solution?
Currently, I had to downgrade the CLI packages to 12.3.7 in order for it to work properly with pre-built binaries on iOS :(
@cipolleschi or @mikehardy would you be able to reopen this issue as it still exists?
The short version of the issue is that when you run npx react-native run-ios with --binary-path the CLI will execute runOnSimulator but it will not assign a value to buildOutput (because binaryPath is set) which means the call to installApp will eventually fail because of a call to getBuildSettings which calls getPlatformName(buildOutput) - with an undefined buildOutput because the app was already built.
@szymonrybczak @thymikee can you check whether this is still valid and reopen it if needed?
@thymikee thanks for reopening. I can add that this can be reproduced in a vanilla RN project with:
npx @react-native-community/cli@latest init AwesomeProject --version 0.79.2
And then running run-ios with a random file, e.g.:
npx react-native run-ios --binary-path index.js
This gives the following output:
info Found Xcode project "AwesomeProject.xcodeproj"
info Found booted iPhone 15 Pro
node:internal/process/promises:392
new UnhandledPromiseRejection(reason);
^
UnhandledPromiseRejection: This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "Error: Couldn't find "PLATFORM_NAME" variable in xcodebuild output. Please report this issue and run your project with Xcode instead.".
at throwUnhandledRejectionsMode (node:internal/process/promises:392:7)
at processPromiseRejections (node:internal/process/promises:475:17)
at process.processTicksAndRejections (node:internal/process/task_queues:106:32) {
code: 'ERR_UNHANDLED_REJECTION'
}
Node.js v22.9.0
@szymonrybczak or @thymikee any news on this?
For now, I've created this patch to fix various issues with the CLI (primarily issues with prebuilt binaries):
Patch part 1:
Fix destination in buildProject when running with device arg but no specific UDID or args.destination.
Patch part 2:
Select the right target in getBuildSettings when having multiple targets in the Xcode build scheme (my "app target" is the third one in the build list).
Patch part 3:
Harcode PLATFORM_NAME in getPlatformName (getBuildSettings) because it cannot detect it when using prebuilt binaries. I've simply hardcoded it to 'iphonesimulator' but it appears to also work fine when installing a prebuilt binary on a physical device.
Patch part 4:
Fix plist path in installApp when running with a prebuilt binary (when appPath is set) located at a custom path.
diff --git a/node_modules/@react-native-community/cli-platform-apple/build/commands/buildCommand/buildProject.js b/node_modules/@react-native-community/cli-platform-apple/build/commands/buildCommand/buildProject.js
index e41378d..1b1fa68 100644
--- a/node_modules/@react-native-community/cli-platform-apple/build/commands/buildCommand/buildProject.js
+++ b/node_modules/@react-native-community/cli-platform-apple/build/commands/buildCommand/buildProject.js
@@ -48,12 +48,26 @@ function prettifyXcodebuildMessages(output) {
}
function buildProject(xcodeProject, platform, udid, mode, scheme, args) {
return new Promise((resolve, reject) => {
- const simulatorDest = _simulatorDestinationMap.simulatorDestinationMap === null || _simulatorDestinationMap.simulatorDestinationMap === void 0 ? void 0 : _simulatorDestinationMap.simulatorDestinationMap[platform];
- if (!simulatorDest) {
- reject(new (_cliTools().CLIError)(`Unknown platform: ${platform}. Please, use one of: ${Object.values(_cliConfigApple().supportedPlatforms).join(', ')}.`));
- return;
+ const isDevice = args.device
+ let destination = ""
+ if (udid) {
+ destination = `id=${udid}`
+ } else if (isDevice) {
+ destination = "generic/platform=iOS"
+ } else if (mode === 'Debug') {
+ const simulatorDest = _simulatorDestinationMap.simulatorDestinationMap === null || _simulatorDestinationMap.simulatorDestinationMap === void 0 ? void 0 : _simulatorDestinationMap.simulatorDestinationMap[platform];
+ if (!simulatorDest) {
+ reject(new (_cliTools().CLIError)(`Unknown platform: ${platform}. Please, use one of: ${Object.values(_cliConfigApple().supportedPlatforms).join(', ')}.`));
+ return;
+ }
+ destination = `generic/platform=${simulatorDest}`
+ } else {
+ destination = `generic/platform=${platform}`
+ }
+ if (args.destination) {
+ destination += `,${args.destination}`
}
- const xcodebuildArgs = [xcodeProject.isWorkspace ? '-workspace' : '-project', xcodeProject.name, ...(args.xcconfig ? ['-xcconfig', args.xcconfig] : []), ...(args.buildFolder ? ['-derivedDataPath', args.buildFolder] : []), '-configuration', mode, '-scheme', scheme, '-destination', (udid ? `id=${udid}` : mode === 'Debug' ? `generic/platform=${simulatorDest}` : `generic/platform=${platform}`) + (args.destination ? ',' + args.destination : '')];
+ const xcodebuildArgs = [xcodeProject.isWorkspace ? '-workspace' : '-project', xcodeProject.name, ...(args.xcconfig ? ['-xcconfig', args.xcconfig] : []), ...(args.buildFolder ? ['-derivedDataPath', args.buildFolder] : []), '-configuration', mode, '-scheme', scheme, '-destination', destination];
if (args.extraParams) {
xcodebuildArgs.push(...args.extraParams);
}
diff --git a/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js b/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js
index 8e60c59..1a86938 100644
--- a/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js
+++ b/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/getBuildSettings.js
@@ -34,7 +34,7 @@ async function getBuildSettings(xcodeProject, mode, buildOutput, scheme, target)
const targets = settings.map(({
target: settingsTarget
}) => settingsTarget);
- let selectedTarget = targets[0];
+ let selectedTarget = targets[2]; // In our Xcode schemes, the actual app is the third target in the build list
if (target) {
if (!targets.includes(target)) {
_cliTools().logger.info(`Target ${_chalk().default.bold(target)} not found for scheme ${_chalk().default.bold(scheme)}, automatically selected target ${_chalk().default.bold(selectedTarget)}`);
@@ -54,9 +54,11 @@ async function getBuildSettings(xcodeProject, mode, buildOutput, scheme, target)
}
function getPlatformName(buildOutput) {
// Xcode can sometimes escape `=` with a backslash or put the value in quotes
- const platformNameMatch = /export PLATFORM_NAME\\?="?(\w+)"?$/m.exec(buildOutput);
+ let platformNameMatch = /export PLATFORM_NAME\\?="?(\w+)"?$/m.exec(buildOutput);
if (!platformNameMatch) {
- throw new (_cliTools().CLIError)('Couldn\'t find "PLATFORM_NAME" variable in xcodebuild output. Please report this issue and run your project with Xcode instead.');
+ platformNameMatch = ["","iphonesimulator"] // Hardcode platform because it cannot be found when we are just trying to install a prebuilt binary and not build a new one. This is an overly simple fix for the bug and can potentially hide other iOS building issues. It also seems to work when installing prebuilt binaries on physical iOS devices.
+ console.warn(`Manually setting 'platform' to '${platformNameMatch[1]}' due to a bug in the CLI with prebuilt binaries: https://github.com/react-native-community/cli/issues/2517.`)
+ // throw new (_cliTools().CLIError)('Couldn\'t find "PLATFORM_NAME" variable in xcodebuild output. Please report this issue and run your project with Xcode instead.');
}
return platformNameMatch[1];
}
diff --git a/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/installApp.js b/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/installApp.js
index f95f97a..e796d62 100644
--- a/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/installApp.js
+++ b/node_modules/@react-native-community/cli-platform-apple/build/commands/runCommand/installApp.js
@@ -61,9 +61,11 @@ async function installApp({
if (!appPath) {
appPath = await (0, _getBuildPath.getBuildPath)(buildSettings, platform);
}
+
const targetBuildDir = buildSettings.TARGET_BUILD_DIR;
const infoPlistPath = buildSettings.INFOPLIST_PATH;
- if (!infoPlistPath) {
+ const plistPath = appPath ? _path().default.join(appPath, "Info.plist") : _path().default.join(targetBuildDir, infoPlistPath)
+ if (!plistPath) {
throw new (_cliTools().CLIError)('Failed to find Info.plist');
}
if (!targetBuildDir) {
@@ -76,7 +78,7 @@ async function installApp({
stdio: 'inherit'
});
}
- const bundleID = _child_process().default.execFileSync('/usr/libexec/PlistBuddy', ['-c', 'Print:CFBundleIdentifier', _path().default.join(targetBuildDir, infoPlistPath)], {
+ const bundleID = _child_process().default.execFileSync('/usr/libexec/PlistBuddy', ['-c', 'Print:CFBundleIdentifier', plistPath], {
encoding: 'utf8'
}).trim();
_cliTools().logger.info(`Launching "${_chalk().default.bold(bundleID)}"`);
The patch seems to work for new builds, builds with prebuilt binaries and both on simulators and physical devices.
@szymonrybczak or @thymikee do you have any comments on this broken feature?
Yeah these are real issues that need to be fixed. Would you be so kind and contribute the non-hardcoded patches to this repo? Will try to find some time to address the PLATFORM_NAME one in the upcoming days.
Just FYI @jenskuhrjorgensen, in RNEF we've addressed I think all of the issues that you mentioned, as we've rewritten this logic from scratch. It's quite convoluted in RNC CLI, but maybe we can hack our way around it, since this logic basically shouldn't be run when binaryPath is set
@thymikee sorry for the long delay.
Here are some PRs for the non-hardcoded fixes from above patch:
Patch part #1: https://github.com/react-native-community/cli/pull/2706
Patch part #2: https://github.com/react-native-community/cli/pull/2707
Patch part #4: https://github.com/react-native-community/cli/pull/2705
There hasn't been any activity on this issue in the past 3 months, so it has been marked as stale and it will be closed automatically if no further activity occurs in the next 7 days.