Skip to content

run-ios --buildFolder installs the app from the default DerivedData instead of the build folder #2869

Description

@lovisschmidt

Environment

System:
  OS: macOS 27.0.1
Binaries:
  Node: 24.18.0
  pnpm: 11
IDEs:
  Xcode: 27.0/27A266a
npmPackages:
  "@react-native-community/cli-platform-apple": 20.2.0
  react-native: 0.85

The bug does not depend on the Xcode version; the relevant code is unchanged on main (21.0.0-alpha.1).

Description

run-ios --buildFolder <dir> builds into <dir> but installs the app from Xcode's default DerivedData.

buildProject passes the folder to the build as -derivedDataPath <dir>. After the build, installApp resolves the app through getBuildSettings, which runs xcodebuild … -showBuildSettings -json without -derivedDataPath. TARGET_BUILD_DIR therefore points into ~/Library/Developer/Xcode/DerivedData/<Project>-<hash>/… and not into <dir>. As a result:

  • If the default DerivedData holds an older build of the project (for example from an Xcode IDE build), the CLI installs and launches that stale .app without any warning.

  • If it holds no build, the command fails after success Successfully built the app:

    UnhandledPromiseRejection: … The promise rejected with the reason "Error: target build directory /Users/…/Library/Developer/Xcode/DerivedData/<Project>-<hash>/Build/Products/Debug-iphonesimulator does not exist".
    

The same applies to runOnDevice (physical device and Mac Catalyst) and to openApp (macOS), because they all go through getBuildSettings.

--binary-path does not work around this: it skips the build and passes buildOutput: '', so getBuildSettings throws on getPlatformName('') (#2517).

Code references on main:

  • packages/cli-platform-apple/src/commands/buildCommand/buildProject.ts adds -derivedDataPath from args.buildFolder.
  • packages/cli-platform-apple/src/commands/runCommand/getBuildSettings.ts builds the -showBuildSettings call without it.
  • runOnSimulator.ts, runOnDevice.ts and createRun.ts (macOS) do not pass args.buildFolder to installApp / openApp / getBuildSettings.

Related: createRun calls process.chdir(sourceDir) (the ios/ directory) before building, so a relative --buildFolder resolves against ios/ and not the project root. The option description does not say which directory it is relative to.

Proposed fix: thread buildFolder from the run paths into getBuildSettings and append -derivedDataPath <buildFolder> to the -showBuildSettings call when it is set. I applied this as a local patch on 20.2.0: run-ios --buildFolder build/DerivedData then installs and launches the freshly built app from ios/build/DerivedData/Build/Products/Debug-iphonesimulator/. PR to follow.

Reproducible Demo

  1. In any React Native project, make sure the default DerivedData has no build for it: rm -rf ~/Library/Developer/Xcode/DerivedData/<Project>-*.
  2. Run npx react-native run-ios --buildFolder build/DerivedData.
  3. The build succeeds into ios/build/DerivedData, then the CLI fails with target build directory …/Library/Developer/Xcode/DerivedData/<Project>-<hash>/Build/Products/Debug-iphonesimulator does not exist.

Expected: the CLI installs and launches the app it just built in ios/build/DerivedData.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions