Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 25.2k
Fix error in react-native run-ios when Product Name and Scheme are inequal#10178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
d4e9495028535ad9e2d2d93d3aab4db0df2c48a6dfee2b353e37439d9501c1de357742c01f837File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -31,7 +31,7 @@ function runIOS(argv, config, args) { | ||
| if (args.device) { | ||
| const selectedDevice = matchingDevice(devices, args.device); | ||
| if (selectedDevice){ | ||
| runOnDevice(selectedDevice, scheme, xcodeProject); | ||
| return runOnDevice(selectedDevice, scheme, xcodeProject); | ||
| } else { | ||
| if (devices){ | ||
| console.log('Could not find device with the name: "' + args.device + '".'); | ||
| @@ -42,16 +42,16 @@ function runIOS(argv, config, args) { | ||
| } | ||
| } | ||
| } else if (args.udid) { | ||
| runOnDeviceByUdid(args.udid, scheme, xcodeProject, devices); | ||
| return runOnDeviceByUdid(args.udid, scheme, xcodeProject, devices); | ||
| } else { | ||
| runOnSimulator(xcodeProject, args, inferredSchemeName, scheme); | ||
| return runOnSimulator(xcodeProject, args, inferredSchemeName, scheme); | ||
| } | ||
| } | ||
| function runOnDeviceByUdid(udid, scheme, xcodeProject, devices) { | ||
| const selectedDevice = matchingDeviceByUdid(devices, udid); | ||
| if (selectedDevice){ | ||
| runOnDevice(selectedDevice, scheme, xcodeProject); | ||
| return runOnDevice(selectedDevice, scheme, xcodeProject); | ||
| } else { | ||
| if (devices){ | ||
| console.log('Could not find device with the udid: "' + udid + '".'); | ||
| @@ -64,82 +64,119 @@ function runOnDeviceByUdid(udid, scheme, xcodeProject, devices) { | ||
| } | ||
| function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ | ||
| try { | ||
| var simulators = JSON.parse( | ||
| child_process.execFileSync('xcrun', ['simctl', 'list', '--json', 'devices'], {encoding: 'utf8'}) | ||
| ); | ||
| } catch (e) { | ||
| throw new Error('Could not parse the simulator list output'); | ||
| } | ||
| const selectedSimulator = findMatchingSimulator(simulators, args.simulator); | ||
| if (!selectedSimulator) { | ||
| throw new Error(`Cound't find ${args.simulator} simulator`); | ||
| } | ||
| const simulatorFullName = formattedDeviceName(selectedSimulator); | ||
| console.log(`Launching ${simulatorFullName}...`); | ||
| try { | ||
| child_process.spawnSync('xcrun', ['instruments', '-w', selectedSimulator.udid]); | ||
| } catch (e) { | ||
| // instruments always fail with 255 because it expects more arguments, | ||
| // but we want it to only launch the simulator | ||
| } | ||
| buildProject(xcodeProject, selectedSimulator.udid, scheme); | ||
| const appPath = `build/Build/Products/Debug-iphonesimulator/${inferredSchemeName}.app`; | ||
| console.log(`Installing ${appPath}`); | ||
| child_process.spawnSync('xcrun', ['simctl', 'install', 'booted', appPath], {stdio: 'inherit'}); | ||
| return new Promise((resolve) => { | ||
| try { | ||
| var simulators = JSON.parse( | ||
| child_process.execFileSync('xcrun', ['simctl', 'list', '--json', 'devices'], {encoding: 'utf8'}) | ||
| ); | ||
| } catch (e) { | ||
| throw new Error('Could not parse the simulator list output'); | ||
| } | ||
| const bundleID = child_process.execFileSync( | ||
| '/usr/libexec/PlistBuddy', | ||
| ['-c', 'Print:CFBundleIdentifier', path.join(appPath, 'Info.plist')], | ||
| {encoding: 'utf8'} | ||
| ).trim(); | ||
| const selectedSimulator = findMatchingSimulator(simulators, args.simulator); | ||
| if (!selectedSimulator) { | ||
| throw new Error(`Cound't find ${args.simulator} simulator`); | ||
| } | ||
| console.log(`Launching ${bundleID}`); | ||
| child_process.spawnSync('xcrun', ['simctl', 'launch', 'booted', bundleID], {stdio: 'inherit'}); | ||
| const simulatorFullName = formattedDeviceName(selectedSimulator); | ||
| console.log(`Launching ${simulatorFullName}...`); | ||
| try { | ||
| child_process.spawnSync('xcrun', ['instruments', '-w', selectedSimulator.udid]); | ||
| } catch (e) { | ||
| // instruments always fail with 255 because it expects more arguments, | ||
| // but we want it to only launch the simulator | ||
| } | ||
| resolve(selectedSimulator.udid) | ||
| }) | ||
| .then((udid) => buildProject(xcodeProject, udid, scheme)) | ||
| .then((appName) => { | ||
| if (!appName) { | ||
| appName = inferredSchemeName; | ||
| } | ||
| const appPath = `build/Build/Products/Debug-iphonesimulator/${appName}.app`; | ||
| console.log(`Installing ${appPath}`); | ||
| child_process.spawnSync('xcrun', ['simctl', 'install', 'booted', appPath], {stdio: 'inherit'}); | ||
| const bundleID = child_process.execFileSync( | ||
| '/usr/libexec/PlistBuddy', | ||
| ['-c', 'Print:CFBundleIdentifier', path.join(appPath, 'Info.plist')], | ||
| {encoding: 'utf8'} | ||
| ).trim(); | ||
| console.log(`Launching ${bundleID}`); | ||
| child_process.spawnSync('xcrun', ['simctl', 'launch', 'booted', bundleID], {stdio: 'inherit'}); | ||
| }) | ||
| } | ||
| function runOnDevice(selectedDevice, scheme, xcodeProject){ | ||
| buildProject(xcodeProject, selectedDevice.udid, scheme); | ||
| const iosDeployInstallArgs = [ | ||
| '--bundle', 'build/Build/Products/Debug-iphoneos/' + scheme + '.app', | ||
| '--id' , selectedDevice.udid, | ||
| '--justlaunch' | ||
| ]; | ||
| console.log(`installing and launching your app on ${selectedDevice.name}...`); | ||
| var iosDeployOutput = child_process.spawnSync('ios-deploy', iosDeployInstallArgs, {encoding: 'utf8'}); | ||
| if (iosDeployOutput.error) { | ||
| console.log(''); | ||
| console.log('** INSTALLATION FAILED **'); | ||
| console.log('Make sure you have ios-deploy installed globally.'); | ||
| console.log('(e.g "npm install -g ios-deploy")'); | ||
| } else { | ||
| console.log('** INSTALLATION SUCCEEDED **'); | ||
| } | ||
| return buildProject(xcodeProject, selectedDevice.udid, scheme) | ||
| .then((appName) => { | ||
| if (!appName) { | ||
| appName = scheme; | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same nits as above | ||
| } | ||
| const iosDeployInstallArgs = [ | ||
| '--bundle', 'build/Build/Products/Debug-iphoneos/' + appName + '.app', | ||
| '--id' , selectedDevice.udid, | ||
| '--justlaunch' | ||
| ]; | ||
| console.log(`installing and launching your app on ${selectedDevice.name}...`); | ||
| const iosDeployOutput = child_process.spawnSync('ios-deploy', iosDeployInstallArgs, {encoding: 'utf8'}); | ||
| if (iosDeployOutput.error) { | ||
| console.log(''); | ||
| console.log('** INSTALLATION FAILED **'); | ||
| console.log('Make sure you have ios-deploy installed globally.'); | ||
| console.log('(e.g "npm install -g ios-deploy")'); | ||
| } else { | ||
| console.log('** INSTALLATION SUCCEEDED **'); | ||
| } | ||
| }); | ||
| } | ||
| function buildProject(xcodeProject, udid, scheme) { | ||
| const xcodebuildArgs = [ | ||
| xcodeProject.isWorkspace ? '-workspace' : '-project', xcodeProject.name, | ||
| '-scheme', scheme, | ||
| '-destination', `id=${udid}`, | ||
| '-derivedDataPath', 'build', | ||
| ]; | ||
| console.log(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`); | ||
| child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'inherit'}); | ||
| return new Promise((resolve,reject) => | ||
| { | ||
| const xcodebuildArgs = [ | ||
| xcodeProject.isWorkspace ? '-workspace' : '-project', xcodeProject.name, | ||
| '-scheme', scheme, | ||
| '-destination', `id=${udid}`, | ||
| '-derivedDataPath', 'build', | ||
| ]; | ||
| console.log(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`); | ||
| const buildProcess = child_process.spawn('xcodebuild', xcodebuildArgs); | ||
| let buildOutput = ""; | ||
| buildProcess.stdout.on('data', function(data) { | ||
| console.log(data.toString()); | ||
| buildOutput += data.toString(); | ||
| }); | ||
| buildProcess.stderr.on('data', function(data) { | ||
| console.error(data.toString()); | ||
| }); | ||
| buildProcess.on('close', function(code) { | ||
| //FULL_PRODUCT_NAME is the actual file name of the app, which actually comes from the Product Name in the build config, which does not necessary match a scheme name, example output line: export FULL_PRODUCT_NAME="Super App Dev.app" | ||
| let productNameMatch = /export FULL_PRODUCT_NAME="?(.+).app/.exec(buildOutput); | ||
| if (productNameMatch && productNameMatch.length && productNameMatch.length > 1) { | ||
| return resolve(productNameMatch[1]);//0 is the full match, 1 is the app name | ||
| } | ||
| return buildProcess.error? reject(error) : resolve(); | ||
| }); | ||
| }); | ||
| } | ||
| function matchingDevice(devices, deviceName) { | ||
| if (deviceName === true && devices.length === 1) | ||
| ||
| { | ||
| console.log(`Using first available device ${devices[0].name} due to lack of name supplied.`) | ||
| return devices[0]; | ||
| } | ||
| for (let i = devices.length - 1; i >= 0; i--) { | ||
| if (devices[i].name === deviceName || formattedDeviceName(devices[i]) === deviceName) { | ||
| return devices[i]; | ||
| } | ||
| } | ||
| } | ||
| function matchingDeviceByUdid(devices, udid) { | ||
| for (let i = devices.length - 1; i >= 0; i--) { | ||
| if (devices[i].udid === udid) { | ||
| @@ -190,7 +227,7 @@ module.exports = { | ||
| default: 'ios', | ||
| }, { | ||
| command: '--device [string]', | ||
| description: 'Explicitly set device to use by name', | ||
| description: 'Explicitly set device to use by name. The value is not required if you have a single device connected.', | ||
| },{ | ||
| command: '--udid [string]', | ||
| description: 'Explicitly set device to use by udid', | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const simulatorsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left as var because simulators is used outside the context of the try/catch it's in. Turn it into a const and you get "simulators is not defined" error. You could pull it out of the try/catch, but then you have to use let. So I thought var was actually the best choice here. If you want, I'll add "let simulators;" above the try. What do you prefer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes,
let simulatorsoutside of the try-catch block would be the preferred style.