mirror of
https://github.com/status-im/react-native.git
synced 2025-01-25 00:39:03 +00:00
891b87e7fb
Summary: Adds support for launching the packager in a new window on Windows. **Test plan (required)** Tested that the packager is launched in a completely independent process. This means that exiting the `react-native run-android` command should not close the packager window and it should exit properly when completed even if the packager window is still opened. Pretty much made sure it behaves exactly like on mac. Also tested that an error in the packager will not close the window immediately to show the error stack trace. Closes https://github.com/facebook/react-native/pull/7129 Differential Revision: D3240628 Pulled By: mkonicek fb-gh-sync-id: 007582250536481d2b2376f9a201f8f415fc1080 fbshipit-source-id: 007582250536481d2b2376f9a201f8f415fc1080
192 lines
5.8 KiB
JavaScript
192 lines
5.8 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
'use strict';
|
|
|
|
const chalk = require('chalk');
|
|
const child_process = require('child_process');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const parseCommandLine = require('../util/parseCommandLine');
|
|
const isPackagerRunning = require('../util/isPackagerRunning');
|
|
const Promise = require('promise');
|
|
const adb = require('./adb');
|
|
|
|
/**
|
|
* Starts the app on a connected Android emulator or device.
|
|
*/
|
|
function runAndroid(argv, config) {
|
|
return new Promise((resolve, reject) => {
|
|
_runAndroid(argv, config, resolve, reject);
|
|
});
|
|
}
|
|
|
|
function _runAndroid(argv, config, resolve, reject) {
|
|
const args = parseCommandLine([{
|
|
command: 'install-debug',
|
|
type: 'string',
|
|
required: false,
|
|
}, {
|
|
command: 'root',
|
|
type: 'string',
|
|
description: 'Override the root directory for the android build (which contains the android directory)',
|
|
}, {
|
|
command: 'flavor',
|
|
type: 'string',
|
|
required: false,
|
|
}], argv);
|
|
|
|
args.root = args.root || '';
|
|
|
|
if (!checkAndroid(args)) {
|
|
console.log(chalk.red('Android project not found. Maybe run react-native android first?'));
|
|
return;
|
|
}
|
|
|
|
resolve(isPackagerRunning().then(result => {
|
|
if (result === 'running') {
|
|
console.log(chalk.bold(`JS server already running.`));
|
|
} else if (result === 'unrecognized') {
|
|
console.warn(chalk.yellow(`JS server not recognized, continuing with build...`));
|
|
} else {
|
|
// result == 'not_running'
|
|
console.log(chalk.bold(`Starting JS server...`));
|
|
startServerInNewWindow();
|
|
}
|
|
buildAndRun(args, reject);
|
|
}));
|
|
}
|
|
|
|
// Verifies this is an Android project
|
|
function checkAndroid(args) {
|
|
return fs.existsSync(path.join(args.root, 'android/gradlew'));
|
|
}
|
|
|
|
// Builds the app and runs it on a connected emulator / device.
|
|
function buildAndRun(args, reject) {
|
|
process.chdir(path.join(args.root, 'android'));
|
|
try {
|
|
const cmd = process.platform.startsWith('win')
|
|
? 'gradlew.bat'
|
|
: './gradlew';
|
|
|
|
const gradleArgs = [];
|
|
if (args['flavor']) {
|
|
gradleArgs.push('install' +
|
|
args['flavor'][0].toUpperCase() + args['flavor'].slice(1)
|
|
);
|
|
} else {
|
|
gradleArgs.push('installDebug');
|
|
}
|
|
|
|
if (args['install-debug']) {
|
|
gradleArgs.push(args['install-debug']);
|
|
}
|
|
|
|
console.log(chalk.bold(
|
|
`Building and installing the app on the device (cd android && ${cmd} ${gradleArgs.join(' ')}...`
|
|
));
|
|
|
|
child_process.execFileSync(cmd, gradleArgs, {
|
|
stdio: [process.stdin, process.stdout, process.stderr],
|
|
});
|
|
} catch (e) {
|
|
console.log(chalk.red(
|
|
'Could not install the app on the device, read the error above for details.\n' +
|
|
'Make sure you have an Android emulator running or a device connected and have\n' +
|
|
'set up your Android development environment:\n' +
|
|
'https://facebook.github.io/react-native/docs/android-setup.html'
|
|
));
|
|
// stderr is automatically piped from the gradle process, so the user
|
|
// should see the error already, there is no need to do
|
|
// `console.log(e.stderr)`
|
|
reject();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const packageName = fs.readFileSync(
|
|
'app/src/main/AndroidManifest.xml',
|
|
'utf8'
|
|
).match(/package="(.+?)"/)[1];
|
|
|
|
const adbPath = process.env.ANDROID_HOME
|
|
? process.env.ANDROID_HOME + '/platform-tools/adb'
|
|
: 'adb';
|
|
|
|
const devices = adb.getDevices();
|
|
|
|
if (devices && devices.length > 0) {
|
|
devices.forEach((device) => {
|
|
|
|
const adbArgs = ['-s', device, 'shell', 'am', 'start', '-n', packageName + '/.MainActivity'];
|
|
|
|
console.log(chalk.bold(
|
|
`Starting the app on ${device} (${adbPath} ${adbArgs.join(' ')})...`
|
|
));
|
|
|
|
child_process.spawnSync(adbPath, adbArgs, {stdio: 'inherit'});
|
|
});
|
|
} else {
|
|
// If we cannot execute based on adb devices output, fall back to
|
|
// shell am start
|
|
const fallbackAdbArgs = [
|
|
'shell', 'am', 'start', '-n', packageName + '/.MainActivity'
|
|
];
|
|
console.log(chalk.bold(
|
|
`Starting the app (${adbPath} ${fallbackAdbArgs.join(' ')}...`
|
|
));
|
|
child_process.spawnSync(adbPath, fallbackAdbArgs, {stdio: 'inherit'});
|
|
}
|
|
|
|
} catch (e) {
|
|
console.log(chalk.red(
|
|
`adb invocation failed. Do you have adb in your PATH?`
|
|
));
|
|
// stderr is automatically piped from the gradle process, so the user
|
|
// should see the error already, there is no need to do
|
|
// `console.log(e.stderr)`
|
|
reject();
|
|
return;
|
|
}
|
|
}
|
|
|
|
function startServerInNewWindow() {
|
|
var yargV = require('yargs').argv;
|
|
|
|
const scriptFile = /^win/.test(process.platform) ?
|
|
'launchPackager.bat' :
|
|
'launchPackager.command';
|
|
|
|
const launchPackagerScript = path.resolve(
|
|
__dirname, '..', '..', 'packager', scriptFile
|
|
);
|
|
|
|
if (process.platform === 'darwin') {
|
|
if (yargV.open) {
|
|
return child_process.spawnSync('open', ['-a', yargV.open, launchPackagerScript]);
|
|
}
|
|
return child_process.spawnSync('open', [launchPackagerScript]);
|
|
|
|
} else if (process.platform === 'linux') {
|
|
if (yargV.open){
|
|
return child_process.spawn(yargV.open,['-e', 'sh', launchPackagerScript], {detached: true});
|
|
}
|
|
return child_process.spawn('sh', [launchPackagerScript],{detached: true});
|
|
|
|
} else if (/^win/.test(process.platform)) {
|
|
return child_process.spawn(
|
|
'cmd.exe', ['/C', 'start', launchPackagerScript], {detached: true, stdio: 'ignore'}
|
|
);
|
|
} else {
|
|
console.log(chalk.red(`Cannot start the packager. Unknown platform ${process.platform}`));
|
|
}
|
|
}
|
|
|
|
module.exports = runAndroid;
|