-
Notifications
You must be signed in to change notification settings - Fork 25.1k
run-android-on-specific-device #9568
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,12 +8,13 @@ | |
| */ | ||
| 'use strict'; | ||
|
|
||
| const adb = require('./adb'); | ||
| const chalk = require('chalk'); | ||
| const child_process = require('child_process'); | ||
| const fs = require('fs'); | ||
| const isPackagerRunning = require('../util/isPackagerRunning'); | ||
| const path = require('path'); | ||
| const isPackagerRunning = require('../util/isPackagerRunning'); | ||
| const Promise = require('promise'); | ||
| const adb = require('./adb'); | ||
|
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. alphasort |
||
|
|
||
| // Verifies this is an Android project | ||
| function checkAndroid(root) { | ||
|
|
@@ -76,9 +77,98 @@ function tryRunAdbReverse(device) { | |
|
|
||
| // Builds the app and runs it on a connected emulator / device. | ||
| function buildAndRun(args) { | ||
| process.chdir(path.join(args.root, 'android')); | ||
| const cmd = process.platform.startsWith('win') | ||
| ? 'gradlew.bat' | ||
| : './gradlew'; | ||
|
|
||
| const packageName = fs.readFileSync( | ||
| 'app/src/main/AndroidManifest.xml', | ||
| 'utf8' | ||
| ).match(/package="(.+?)"/)[1]; | ||
|
|
||
| const adbPath = getAdbPath(); | ||
| if (args.deviceId) { | ||
| runOnSpecificDevice(args, cmd, packageName, adbPath); | ||
| } else { | ||
| runOnAllDevices(args, cmd, packageName, adbPath); | ||
| } | ||
|
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. Cool, the logic here is good, easily readable 👍 |
||
| } | ||
|
|
||
| function runOnSpecificDevice(args, gradlew, packageName, adbPath) { | ||
| let devices = adb.getDevices(); | ||
| if (devices && devices.length > 0) { | ||
| if (devices.indexOf(args.deviceId) !== -1) { | ||
| buildApk(gradlew); | ||
| installAndLaunchOnDevice(args, args.deviceId, packageName, adbPath); | ||
| } else { | ||
| console.log('Could not find device with the id: "' + args.deviceId + '".'); | ||
| console.log('Choose one of the following:'); | ||
| console.log(devices); | ||
| } | ||
| } else { | ||
| console.log('No Android devices connected.'); | ||
| } | ||
| } | ||
|
|
||
| function buildApk(gradlew) { | ||
| try { | ||
| adb.getDevices().map((device) => tryRunAdbReverse(device)); | ||
| console.log(chalk.bold( | ||
| 'Building the app...' | ||
| )); | ||
|
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. This can be on single line. |
||
|
|
||
| // using '-x lint' in order to ignore linting errors while building the apk | ||
| child_process.execFileSync(gradlew, ['build', '-x', 'lint'], { | ||
| stdio: [process.stdin, process.stdout, process.stderr], | ||
| }); | ||
| } catch (e) { | ||
| console.log(chalk.red( | ||
| 'Could not build the app on the device, read the error above for details.\n' | ||
|
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. We are not building the app on the device. We are either building the app, or installing it on device. |
||
| )); | ||
| } | ||
| } | ||
|
|
||
| function tryInstallAppOnDevice(args, device) { | ||
| try { | ||
| const pathToApk = 'app/build/outputs/apk/app-debug.apk'; | ||
| const adbPath = getAdbPath(); | ||
| const adbArgs = ['-s', device, 'install', pathToApk]; | ||
| console.log(chalk.bold( | ||
| `Installing the app on the device (cd android && adb -s ${device} install ${pathToApk}` | ||
| )); | ||
| child_process.execFileSync(adbPath, adbArgs, { | ||
| stdio: [process.stdin, process.stdout, process.stderr], | ||
| }); | ||
| } catch (e) { | ||
| console.log(e.message); | ||
| console.log(chalk.red( | ||
| 'Could not install the app on the device, read the error above for details.\n' | ||
| )); | ||
| } | ||
| } | ||
|
|
||
| function tryLaunchAppOnDevice(device, packageName, adbPath) { | ||
| try { | ||
| 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'}); | ||
| } catch (e) { | ||
| console.log(chalk.red( | ||
| 'adb invocation failed. Do you have adb in your PATH?' | ||
| )); | ||
| } | ||
| } | ||
|
|
||
| function installAndLaunchOnDevice(args, selectedDevice, packageName, adbPath) { | ||
| tryRunAdbReverse(selectedDevice); | ||
| tryInstallAppOnDevice(args, selectedDevice); | ||
| tryLaunchAppOnDevice(selectedDevice, packageName, adbPath); | ||
| } | ||
|
|
||
| function runOnAllDevices(args, cmd, packageName, adbPath){ | ||
| try { | ||
| const gradleArgs = []; | ||
| if (args.variant) { | ||
| gradleArgs.push('install' + | ||
|
|
@@ -92,46 +182,15 @@ function buildAndRun(args) { | |
| args.flavor[0].toUpperCase() + args.flavor.slice(1) | ||
| ); | ||
| } else { | ||
| gradleArgs.push('install'); | ||
| gradleArgs.push('installDebug'); | ||
| } | ||
|
|
||
| // Append the build type to the current gradle install configuration. | ||
| // By default it will generate `installDebug`. | ||
| gradleArgs[0] = | ||
| gradleArgs[0] + args.configuration[0].toUpperCase() + args.configuration.slice(1); | ||
|
|
||
| // Get the Android project directory. | ||
| const androidProjectDir = path.join(args.root, 'android'); | ||
|
|
||
| if (args.configuration.toUpperCase() === 'RELEASE') { | ||
| console.log(chalk.bold( | ||
| 'Generating the bundle for the release build...' | ||
| )); | ||
|
|
||
| child_process.execSync( | ||
| 'react-native bundle ' + | ||
| '--platform android ' + | ||
| '--dev false ' + | ||
| '--entry-file index.android.js ' + | ||
| `--bundle-output ${androidProjectDir}/app/src/main/assets/index.android.bundle ` + | ||
| `--assets-dest ${androidProjectDir}/app/src/main/res/`, | ||
| { | ||
| stdio: [process.stdin, process.stdout, process.stderr], | ||
| } | ||
| ); | ||
| if (args.installDebug) { | ||
| gradleArgs.push(args.installDebug); | ||
| } | ||
|
|
||
| // Change to the Android directory. | ||
| process.chdir(androidProjectDir); | ||
|
|
||
| // Get the gradle binary for the current platform. | ||
| const cmd = process.platform.startsWith('win') | ||
| ? 'gradlew.bat' | ||
| : './gradlew'; | ||
|
|
||
| console.log(chalk.bold( | ||
| 'Building and installing the app on the device ' + | ||
| `(cd android && ${cmd} ${gradleArgs.join(' ')})...` | ||
| `Building and installing the app on the device (cd android && ${cmd} ${gradleArgs.join(' ')}...` | ||
| )); | ||
|
|
||
| child_process.execFileSync(cmd, gradleArgs, { | ||
|
|
@@ -149,50 +208,33 @@ function buildAndRun(args) { | |
| // `console.log(e.stderr)` | ||
| return Promise.reject(); | ||
| } | ||
|
|
||
| try { | ||
| const packageName = fs.readFileSync( | ||
| 'app/src/main/AndroidManifest.xml', | ||
| 'utf8' | ||
| ).match(/package="(.+?)"/)[1]; | ||
|
|
||
| const adbPath = getAdbPath(); | ||
|
|
||
| const devices = adb.getDevices(); | ||
|
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. If we look for and validate |
||
|
|
||
| if (devices && devices.length > 0) { | ||
| devices.forEach((device) => { | ||
|
|
||
| const adbArgs = | ||
| ['-s', device, 'shell', 'am', 'start', '-n', packageName + '/.' + args.mainActivity]; | ||
|
|
||
| console.log(chalk.bold( | ||
| `Starting the app on ${device} (${adbPath} ${adbArgs.join(' ')})...` | ||
| )); | ||
|
|
||
| child_process.spawnSync(adbPath, adbArgs, {stdio: 'inherit'}); | ||
| tryRunAdbReverse(device); | ||
| tryLaunchAppOnDevice(device, packageName, adbPath); | ||
| }); | ||
| } 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'}); | ||
| try { | ||
| // 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)` | ||
| return Promise.reject(); | ||
| } | ||
| } | ||
|
|
||
| } 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)` | ||
| return Promise.reject(); | ||
| } | ||
| } | ||
|
|
||
| function startServerInNewWindow() { | ||
|
|
@@ -206,9 +248,7 @@ function startServerInNewWindow() { | |
|
|
||
| if (process.platform === 'darwin') { | ||
| if (yargV.open) { | ||
| return ( | ||
| child_process.spawnSync('open', ['-a', yargV.open, launchPackagerScript], procConfig) | ||
| ); | ||
| return child_process.spawnSync('open', ['-a', yargV.open, launchPackagerScript], procConfig); | ||
| } | ||
| return child_process.spawnSync('open', [launchPackagerScript], procConfig); | ||
|
|
||
|
|
@@ -233,27 +273,19 @@ module.exports = { | |
| description: 'builds your app and starts it on a connected Android emulator or device', | ||
| func: runAndroid, | ||
| options: [{ | ||
| command: '--install-debug', | ||
| }, { | ||
| command: '--root [string]', | ||
| description: | ||
| 'Override the root directory for the android build ' + | ||
| '(which contains the android directory)', | ||
| description: 'Override the root directory for the android build (which contains the android directory)', | ||
| default: '', | ||
| }, { | ||
| command: '--flavor [string]', | ||
| description: '--flavor has been deprecated. Use --variant instead', | ||
| }, { | ||
| command: '--configuration [string]', | ||
| description: | ||
| 'You can use `Release` or `Debug`. ' + | ||
| 'This creates a build based on the selected configuration. ' + | ||
| 'If you want to use the `Release` configuration make sure you have the ' + | ||
| '`signingConfig` configured at `app/build.gradle`.', | ||
| default: 'Debug' | ||
| }, { | ||
| command: '--variant [string]', | ||
| }, { | ||
| command: '--main-activity [string]', | ||
| description: 'Name of the activity to start', | ||
| default: 'MainActivity' | ||
| command: '--deviceId [string]', | ||
| description: 'builds your app and starts it on a specific device/simulator with the ' + | ||
| 'given device id (listed by running "adb devices" on the command line).', | ||
| }], | ||
| }; | ||
| }; | ||
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.
alphasort these please