From d4e94954e9bdd90f44fdd9d904e300b1f5867d25 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Thu, 29 Sep 2016 13:59:34 -0400 Subject: [PATCH 1/8] Uses correct ios app file name so that react-native run-ios won't fail if Product Name and Scheme aren't equal --- local-cli/runIOS/runIOS.js | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index db55a611b6cec9..ebbb2368c16196 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -86,9 +86,11 @@ function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ // but we want it to only launch the simulator } - buildProject(xcodeProject, selectedSimulator.udid, scheme); + var appName = buildProject(xcodeProject, selectedSimulator.udid, scheme); + if (!appName) + appName = inferredSchemeName; - const appPath = `build/Build/Products/Debug-iphonesimulator/${inferredSchemeName}.app`; + const appPath = `build/Build/Products/Debug-iphonesimulator/${appName}.app`; console.log(`Installing ${appPath}`); child_process.spawnSync('xcrun', ['simctl', 'install', 'booted', appPath], {stdio: 'inherit'}); @@ -103,9 +105,11 @@ function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ } function runOnDevice(selectedDevice, scheme, xcodeProject){ - buildProject(xcodeProject, selectedDevice.udid, scheme); + var appName = buildProject(xcodeProject, selectedDevice.udid, scheme); + if (!appName) + appName = scheme; const iosDeployInstallArgs = [ - '--bundle', 'build/Build/Products/Debug-iphoneos/' + scheme + '.app', + '--bundle', 'build/Build/Products/Debug-iphoneos/' + appName + '.app', '--id' , selectedDevice.udid, '--justlaunch' ]; @@ -130,6 +134,14 @@ function buildProject(xcodeProject, udid, scheme) { ]; console.log(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`); child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'inherit'}); + var buildProcess = child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'pipe'}); + var buildOutput = buildProcess.stdout.toString(); + //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" + var exportFullProductLines = buildOutput.match(new RegExp("export FULL_PRODUCT_NAME=\".+")); + if (exportFullProductLines && exportFullProductLines.length) + { + return exportFullProductLines[exportFullProductLines.length - 1].replace("export FULL_PRODUCT_NAME=\"","").replace(".app\"","");//strip out everything but the file name + } } function matchingDevice(devices, deviceName) { From 028535a9f69744c4e03b42122566abc5e97c29f5 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Thu, 29 Sep 2016 14:35:21 -0400 Subject: [PATCH 2/8] Improved regex and parsing slightly --- local-cli/runIOS/runIOS.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index ebbb2368c16196..df0f38a4208ccd 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -137,10 +137,10 @@ function buildProject(xcodeProject, udid, scheme) { var buildProcess = child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'pipe'}); var buildOutput = buildProcess.stdout.toString(); //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" - var exportFullProductLines = buildOutput.match(new RegExp("export FULL_PRODUCT_NAME=\".+")); + var exportFullProductLines = buildOutput.match(new RegExp("export FULL_PRODUCT_NAME=.+\.app")); if (exportFullProductLines && exportFullProductLines.length) { - return exportFullProductLines[exportFullProductLines.length - 1].replace("export FULL_PRODUCT_NAME=\"","").replace(".app\"","");//strip out everything but the file name + return exportFullProductLines[exportFullProductLines.length - 1].replace("\"","").replace("export FULL_PRODUCT_NAME=","").replace(".app","");//strip out everything but the file name } } From d9e2d2d00e48ed4b6a3e0607f723610931317b36 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Thu, 29 Sep 2016 14:44:52 -0400 Subject: [PATCH 3/8] Fixed double spawnsync --- local-cli/runIOS/runIOS.js | 1 - 1 file changed, 1 deletion(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index df0f38a4208ccd..01a3bf48ff23d7 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -133,7 +133,6 @@ function buildProject(xcodeProject, udid, scheme) { '-derivedDataPath', 'build', ]; console.log(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`); - child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'inherit'}); var buildProcess = child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'pipe'}); var buildOutput = buildProcess.stdout.toString(); //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" From 93d3aabaefa0fcff39dbeb440372426c152b9b6e Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Thu, 29 Sep 2016 14:47:00 -0400 Subject: [PATCH 4/8] Wrote build output to the console. Needed this becaeuse called to spawnSync stdio param had to change from inherit to pipe, so user was no longer seeing build output --- local-cli/runIOS/runIOS.js | 1 + 1 file changed, 1 insertion(+) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index 01a3bf48ff23d7..9b5103490007cd 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -135,6 +135,7 @@ function buildProject(xcodeProject, udid, scheme) { console.log(`Building using "xcodebuild ${xcodebuildArgs.join(' ')}"`); var buildProcess = child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'pipe'}); var buildOutput = buildProcess.stdout.toString(); + console.log(buildOutput); //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" var exportFullProductLines = buildOutput.match(new RegExp("export FULL_PRODUCT_NAME=.+\.app")); if (exportFullProductLines && exportFullProductLines.length) From c48a6df6ef574ddf33339726106982a0ce66c1fb Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Mon, 10 Oct 2016 18:03:24 -0400 Subject: [PATCH 5/8] Switched a vew var keywords to let. Tightened up build output regex matching for the app name --- local-cli/runIOS/runIOS.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index 9b5103490007cd..365a7fb1460d86 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -86,7 +86,7 @@ function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ // but we want it to only launch the simulator } - var appName = buildProject(xcodeProject, selectedSimulator.udid, scheme); + let appName = buildProject(xcodeProject, selectedSimulator.udid, scheme); if (!appName) appName = inferredSchemeName; @@ -105,7 +105,7 @@ function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ } function runOnDevice(selectedDevice, scheme, xcodeProject){ - var appName = buildProject(xcodeProject, selectedDevice.udid, scheme); + let appName = buildProject(xcodeProject, selectedDevice.udid, scheme); if (!appName) appName = scheme; const iosDeployInstallArgs = [ @@ -137,11 +137,11 @@ function buildProject(xcodeProject, udid, scheme) { var buildOutput = buildProcess.stdout.toString(); console.log(buildOutput); //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" - var exportFullProductLines = buildOutput.match(new RegExp("export FULL_PRODUCT_NAME=.+\.app")); - if (exportFullProductLines && exportFullProductLines.length) + let productNameMatch = /(export FULL_PRODUCT_NAME=)("*)(.+)(.app)/.exec(buildOutput); + if (productNameMatch && productNameMatch.length && productNameMatch.length > 3) { - return exportFullProductLines[exportFullProductLines.length - 1].replace("\"","").replace("export FULL_PRODUCT_NAME=","").replace(".app","");//strip out everything but the file name - } + return productNameMatch[3];//0 is the full match, 1 is 'export FULL_PRODUCT_NAME=', 2 is possible double quote, 3 is app name and 4 is '.app' + } } function matchingDevice(devices, deviceName) { From ee2b353c71918414e276f87aac5b20fd29e2276e Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Tue, 11 Oct 2016 10:24:51 -0400 Subject: [PATCH 6/8] Promisified runOnX and buildProject functions so buildProject could use child_process.spawn instead of spawnsync, which fixes the problem of build output not being shown in the console. --- local-cli/runIOS/runIOS.js | 176 +++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 74 deletions(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index 365a7fb1460d86..2ef607cefa7201 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -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,87 +64,114 @@ 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 - } - - let appName = buildProject(xcodeProject, selectedSimulator.udid, scheme); - 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'}); + 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){ - let appName = buildProject(xcodeProject, selectedDevice.udid, scheme); - if (!appName) - appName = scheme; - const iosDeployInstallArgs = [ - '--bundle', 'build/Build/Products/Debug-iphoneos/' + appName + '.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; + const iosDeployInstallArgs = [ + '--bundle', 'build/Build/Products/Debug-iphoneos/' + appName + '.app', + '--id' , selectedDevice.udid, + '--justlaunch' + ]; + console.log(`installing and launching your app on ${selectedDevice.name}...`); + let 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(' ')}"`); - var buildProcess = child_process.spawnSync('xcodebuild', xcodebuildArgs, {stdio: 'pipe'}); - var buildOutput = buildProcess.stdout.toString(); - console.log(buildOutput); - //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 > 3) + return new Promise((resolve,reject) => { - return productNameMatch[3];//0 is the full match, 1 is 'export FULL_PRODUCT_NAME=', 2 is possible double quote, 3 is app name and 4 is '.app' - } + 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.log(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 > 3) + { + return resolve(productNameMatch[3]);//0 is the full match, 1 is 'export FULL_PRODUCT_NAME=', 2 is possible double quote, 3 is app name and 4 is '.app' + } + 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]; @@ -152,6 +179,7 @@ function matchingDevice(devices, deviceName) { } } + function matchingDeviceByUdid(devices, udid) { for (let i = devices.length - 1; i >= 0; i--) { if (devices[i].udid === udid) { @@ -202,7 +230,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', From e37439d4e02c558a47ba987071358cddaad75cf9 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Tue, 11 Oct 2016 10:30:33 -0400 Subject: [PATCH 7/8] Fixed build output regex to use a single capture group. --- local-cli/runIOS/runIOS.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index 2ef607cefa7201..9f3151b7abe661 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -155,10 +155,10 @@ function buildProject(xcodeProject, udid, scheme) { }); 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 > 3) + let productNameMatch = /export FULL_PRODUCT_NAME="*(.+).app/.exec(buildOutput); + if (productNameMatch && productNameMatch.length && productNameMatch.length > 1) { - return resolve(productNameMatch[3]);//0 is the full match, 1 is 'export FULL_PRODUCT_NAME=', 2 is possible double quote, 3 is app name and 4 is '.app' + return resolve(productNameMatch[1]);//0 is the full match, 1 is the app name } return buildProcess.error? reject(error) : resolve(); }); From c01f837e448375773177fdf0851f291b05ab6786 Mon Sep 17 00:00:00 2001 From: Stephen Poter Date: Wed, 12 Oct 2016 13:58:43 -0400 Subject: [PATCH 8/8] Few style tweaks --- local-cli/runIOS/runIOS.js | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/local-cli/runIOS/runIOS.js b/local-cli/runIOS/runIOS.js index 9f3151b7abe661..a1fac7952f2237 100644 --- a/local-cli/runIOS/runIOS.js +++ b/local-cli/runIOS/runIOS.js @@ -64,8 +64,7 @@ function runOnDeviceByUdid(udid, scheme, xcodeProject, devices) { } function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ - return new Promise((resolve) => - { + return new Promise((resolve) => { try { var simulators = JSON.parse( child_process.execFileSync('xcrun', ['simctl', 'list', '--json', 'devices'], {encoding: 'utf8'}) @@ -90,11 +89,10 @@ function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ resolve(selectedSimulator.udid) }) .then((udid) => buildProject(xcodeProject, udid, scheme)) - .then((appName) => - { - if (!appName) + .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'}); @@ -112,17 +110,17 @@ function runOnSimulator(xcodeProject, args, inferredSchemeName, scheme){ function runOnDevice(selectedDevice, scheme, xcodeProject){ return buildProject(xcodeProject, selectedDevice.udid, scheme) - .then((appName) => - { - if (!appName) + .then((appName) => { + if (!appName) { appName = scheme; + } const iosDeployInstallArgs = [ '--bundle', 'build/Build/Products/Debug-iphoneos/' + appName + '.app', '--id' , selectedDevice.udid, '--justlaunch' ]; console.log(`installing and launching your app on ${selectedDevice.name}...`); - let iosDeployOutput = child_process.spawnSync('ios-deploy', iosDeployInstallArgs, {encoding: 'utf8'}); + const iosDeployOutput = child_process.spawnSync('ios-deploy', iosDeployInstallArgs, {encoding: 'utf8'}); if (iosDeployOutput.error) { console.log(''); console.log('** INSTALLATION FAILED **'); @@ -151,13 +149,12 @@ function buildProject(xcodeProject, udid, scheme) { buildOutput += data.toString(); }); buildProcess.stderr.on('data', function(data) { - console.log(data.toString()); + 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) - { + 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();