Skip to content
13 changes: 10 additions & 3 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,6 @@ Builds your app and starts it on a connected Android emulator or device.

#### Options

#### `--install-debug`

#### `--root [string]`

Override the root directory for the Android build (which contains the android directory)'.
Expand All @@ -272,6 +270,8 @@ Override the root directory for the Android build (which contains the android di

> default: 'debug'

Specify your app's build variant.

#### `--appFolder [string]`

> default: 'app'
Expand Down Expand Up @@ -302,14 +302,21 @@ Do not launch packager while building.

#### `--port [number]`

> default: process.env.RCT_METRO_PORT || 8081,
> default: process.env.RCT_METRO_PORT || 8081

#### `--terminal [string]`

> default: process.env.REACT_TERMINAL || process.env.TERM_PROGRAM

Launches the Metro Bundler in a new window using the specified terminal path.

#### `--tasks [list]`

> default: 'installDebug'

Run custom gradle tasks. If this argument is provided, then `--variant` option is ignored.
Example: `yarn react-native run-android --tasks clean,installDebug`.

### `run-ios`

Usage:
Expand Down
7 changes: 2 additions & 5 deletions packages/cli/src/tools/copyFiles.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function copyFile(srcPath: string, destPath: string) {
*/
function copyBinaryFile(srcPath, destPath, cb) {
let cbCalled = false;
// const {mode} = fs.statSync(srcPath);
const {mode} = fs.statSync(srcPath);
const readStream = fs.createReadStream(srcPath);
const writeStream = fs.createWriteStream(destPath);
readStream.on('error', err => {
Expand All @@ -64,10 +64,7 @@ function copyBinaryFile(srcPath, destPath, cb) {
});
readStream.on('close', () => {
done();
// We may revisit setting mode to original later, however this fn is used
// before "replace placeholder in template" step, which expects files to be
// writable.
// fs.chmodSync(destPath, mode);
fs.chmodSync(destPath, mode);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated bugfix: while testing I noticed that gradlew is not executable in newly init projects, so brought chmod back (we're not copying Pods anymore anyway, so we should be fine)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, thanks for explaining this particular change!

});
readStream.pipe(writeStream);
function done(err) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,68 +21,62 @@ describe('--appFolder', () => {
jest.clearAllMocks();
});

it('uses installDebug as default if no arguments', () => {
runOnAllDevices({});
it('uses task "install[Variant]" as default task', () => {
runOnAllDevices({
variant: 'debug',
});

expect(execFileSync.mock.calls[0][1]).toContain('installDebug');
});

it('uses appFolder and default variant', () => {
runOnAllDevices({
appFolder: 'someApp',
variant: 'debug',
});

expect(execFileSync.mock.calls[0][1]).toContain('someApp:installDebug');
});

it('uses appFolder and variant', () => {
runOnAllDevices({
appFolder: 'app',
variant: 'debug',
});

expect(execFileSync.mock.calls[0][1]).toContain('app:installDebug');

runOnAllDevices({
appFolder: 'anotherApp',
variant: 'debug',
});

expect(execFileSync.mock.calls[1][1]).toContain('anotherApp:installDebug');

it('uses appFolder and custom variant', () => {
runOnAllDevices({
appFolder: 'anotherApp',
variant: 'staging',
});

expect(execFileSync.mock.calls[2][1]).toContain(
expect(execFileSync.mock.calls[0][1]).toContain(
'anotherApp:installStaging',
);
});

it('uses appFolder and flavor', () => {
it('uses only task argument', () => {
runOnAllDevices({
appFolder: 'app',
flavor: 'someFlavor',
tasks: ['someTask'],
variant: 'debug',
});

expect(execFileSync.mock.calls[0][1]).toContain('app:installSomeFlavor');
expect(execFileSync.mock.calls[0][1]).toContain('someTask');
});

it('uses only installDebug argument', () => {
it('uses appFolder and custom task argument', () => {
runOnAllDevices({
installDebug: 'someCommand',
appFolder: 'anotherApp',
tasks: ['someTask'],
variant: 'debug',
});

expect(execFileSync.mock.calls[0][1]).toContain('someCommand');
expect(execFileSync.mock.calls[0][1]).toContain('anotherApp:someTask');
});

it('uses appFolder and custom installDebug argument', () => {
it('uses multiple tasks', () => {
runOnAllDevices({
appFolder: 'anotherApp',
installDebug: 'someCommand',
appFolder: 'app',
tasks: ['clean', 'someTask'],
});

expect(execFileSync.mock.calls[0][1]).toContain('anotherApp:someCommand');
expect(execFileSync.mock.calls[0][1]).toContain(
'app:clean',
'app:someTask',
);
});
});
1 change: 0 additions & 1 deletion packages/platform-android/src/commands/runAndroid/adb.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ function getAvailableCPUs(adbPath: string, device: string): Array<string> {
}

export default {
parseDevicesResult,
getDevices,
getAvailableCPUs,
};
90 changes: 45 additions & 45 deletions packages/platform-android/src/commands/runAndroid/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,24 @@ function checkAndroid(root) {
return fs.existsSync(path.join(root, 'android/gradlew'));
}

export type FlagsT = {|
tasks?: Array<string>,
root: string,
variant: string,
appFolder: string,
appId: string,
appIdSuffix: string,
mainActivity: string,
deviceId?: string,
packager: boolean,
port: number,
terminal: string,
|};

/**
* Starts the app on a connected Android emulator or device.
*/
function runAndroid(argv: Array<string>, ctx: ConfigT, args: Object) {
function runAndroid(argv: Array<string>, config: ConfigT, args: FlagsT) {
if (!checkAndroid(args.root)) {
logger.error(
'Android project not found. Are you sure this is a React Native project?',
Expand All @@ -53,7 +67,7 @@ function runAndroid(argv: Array<string>, ctx: ConfigT, args: Object) {
} else {
// result == 'not_running'
logger.info('Starting JS server...');
startServerInNewWindow(args.port, args.terminal, ctx.reactNativePath);
startServerInNewWindow(args.port, args.terminal, config.reactNativePath);
}
return buildAndRun(args);
});
Expand Down Expand Up @@ -90,16 +104,13 @@ function buildAndRun(args) {

const adbPath = getAdbPath();
if (args.deviceId) {
if (typeof args.deviceId === 'string') {
return runOnSpecificDevice(
args,
cmd,
packageNameWithSuffix,
packageName,
adbPath,
);
}
logger.error('Argument missing for parameter --deviceId');
return runOnSpecificDevice(
args,
cmd,
packageNameWithSuffix,
packageName,
adbPath,
);
} else {
return runOnAllDevices(
args,
Expand All @@ -119,21 +130,20 @@ function runOnSpecificDevice(
adbPath,
) {
const devices = adb.getDevices(adbPath);
if (devices && devices.length > 0) {
if (devices.indexOf(args.deviceId) !== -1) {
const {deviceId} = args;
if (devices.length > 0 && deviceId) {
if (devices.indexOf(deviceId) !== -1) {
buildApk(gradlew);
installAndLaunchOnDevice(
args,
args.deviceId,
deviceId,
packageNameWithSuffix,
packageName,
adbPath,
);
} else {
logger.error(
`Could not find device with the id: "${
args.deviceId
}". Choose one of the following:`,
`Could not find device with the id: "${deviceId}". Please choose one of the following:`,
...devices,
);
}
Expand All @@ -144,17 +154,13 @@ function runOnSpecificDevice(

function buildApk(gradlew) {
try {
logger.info('Building the app...');

// using '-x lint' in order to ignore linting errors while building the apk
execFileSync(gradlew, ['build', '-x', 'lint'], {
stdio: [process.stdin, process.stdout, process.stderr],
});
const gradleArgs = ['build', '-x', 'lint'];
logger.info('Building the app...');
logger.debug(`Running command "${gradlew} ${gradleArgs.join(' ')}"`);
execFileSync(gradlew, gradleArgs, {stdio: 'inherit'});
} catch (error) {
throw new CLIError(
'Could not build the app, read the error above for details',
error,
);
throw new CLIError('Failed to build the app.', error);
}
}

Expand All @@ -174,18 +180,13 @@ function tryInstallAppOnDevice(args, adbPath, device) {

const pathToApk = `${buildDirectory}/${apkFile}`;
const adbArgs = ['-s', device, 'install', '-r', '-d', pathToApk];
logger.info(
`Installing the app on the device (cd android && adb -s ${device} install -r -d ${pathToApk}`,
);
execFileSync(adbPath, adbArgs, {
stdio: [process.stdin, process.stdout, process.stderr],
});
} catch (e) {
logger.error(
`${
e.message
}\nCould not install the app on the device, read the error above for details.`,
logger.info(`Installing the app on the device "${device}"...`);
logger.debug(
`Running command "cd android && adb -s ${device} install -r -d ${pathToApk}"`,
);
execFileSync(adbPath, adbArgs, {stdio: 'inherit'});
} catch (error) {
throw new CLIError('Failed to install the app on the device.', error);
}
}

Expand Down Expand Up @@ -305,21 +306,15 @@ export default {
'builds your app and starts it on a connected Android emulator or device',
func: runAndroid,
options: [
{
name: '--install-debug',
},
{
name: '--root [string]',
description:
'Override the root directory for the android build (which contains the android directory)',
default: '',
},
{
name: '--flavor [string]',
description: '--flavor has been deprecated. Use --variant instead',
},
{
name: '--variant [string]',
description: "Specify your app's build variant",
default: 'debug',
},
{
Expand Down Expand Up @@ -364,5 +359,10 @@ export default {
'Launches the Metro Bundler in a new window using the specified terminal path.',
default: getDefaultUserTerminal,
},
{
name: '--tasks [list]',
description: 'Run custom Gradle tasks. By default it\'s "installDebug"',
parse: (val: string) => val.split(','),
},
],
};
Loading