如何阅读`react-native run-android`正在做什么的源代码?

时间:2017-07-06 09:41:40

标签: react-native react-native-android

我想看看react-native run-android正在做什么。我在哪里可以阅读这是做什么的?

2 个答案:

答案 0 :(得分:1)

React Native是开源的,因此您可以在Github上找到CLI的代码:https://github.com/facebook/react-native/blob/master/local-cli/runAndroid/runAndroid.js

如果您希望在本地进行检查,可以在node_modules/react-native/ run-android代码位于local-cli/runAndroid/runAndroid.js的{​​{1}}下的RN项目中找到代码。

答案 1 :(得分:0)

'use strict';

const { getProjectCommands } = require('./core');

import type { RNConfig } from './core';

export type CommandT = {
  name: string,
  description?: string,
  usage?: string,
  func: (argv: Array<string>, config: RNConfig, args: Object) => ?Promise<void>,
  options?: Array<{
    command: string,
    description?: string,
    parse?: (val: string) => any,
    default?: (config: RNConfig) => any | any,
  }>,
  examples?: Array<{
    desc: string,
    cmd: string,
  }>,
  pkg?: {
    version: string,
    name: string,
  },
};

const documentedCommands = [
  require('./server/server'),
  require('./runIOS/runIOS'),
  require('./runAndroid/runAndroid'),
  require('./library/library'),
  require('./bundle/bundle'),
  require('./bundle/unbundle'),
  require('./eject/eject'),
  require('./link/link'),
  require('./link/unlink'),
  require('./install/install'),
  require('./install/uninstall'),
  require('./upgrade/upgrade'),
  require('./logAndroid/logAndroid'),
  require('./logIOS/logIOS'),
  require('./dependencies/dependencies'),
];

// The user should never get here because projects are inited by
// using `react-native-cli` from outside a project directory.
const undocumentedCommands = [
  {
    name: 'init',
    func: () => {
      console.log([
        'Looks like React Native project already exists in the current',
        'folder. Run this command from a different folder or remove node_modules/react-native',
      ].join('\n'));
    },
  },
];

const commands: Array<CommandT> = [
  ...documentedCommands,
  ...undocumentedCommands,
  ...getProjectCommands(),
];

module.exports = commands;

我认为这是你想要的?

'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 isString = require('lodash/isString');
const path = require('path');
const Promise = require('promise');

// Verifies this is an Android project
function checkAndroid(root) {
  return fs.existsSync(path.join(root, 'android/gradlew'));
}

/**
 * Starts the app on a connected Android emulator or device.
 */
function runAndroid(argv, config, args) {
  if (!checkAndroid(args.root)) {
    console.log(chalk.red('Android project not found. Maybe run react-native android first?'));
    return;
  }

  if (!args.packager) {
    return buildAndRun(args);
  }

  return 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();
    }
    return buildAndRun(args);
  });
}

function getAdbPath() {
  return process.env.ANDROID_HOME
    ? process.env.ANDROID_HOME + '/platform-tools/adb'
    : 'adb';
}

// Runs ADB reverse tcp:8081 tcp:8081 to allow loading the jsbundle from the packager
function tryRunAdbReverse(device) {
  try {
    const adbPath = getAdbPath();
    const adbArgs = ['reverse', 'tcp:8081', 'tcp:8081'];

    // If a device is specified then tell adb to use it
    if (device) {
      adbArgs.unshift('-s', device);
    }

    console.log(chalk.bold(
      `Running ${adbPath} ${adbArgs.join(' ')}`
    ));

    child_process.execFileSync(adbPath, adbArgs, {
      stdio: [process.stdin, process.stdout, process.stderr],
    });
  } catch (e) {
    console.log(chalk.yellow(`Could not run adb reverse: ${e.message}`));
  }
}

// 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(
      `${args.appFolder}/src/main/AndroidManifest.xml`,
      'utf8'
    ).match(/package="(.+?)"/)[1];

  const packageNameWithSuffix = args.appIdSuffix ? packageName + '.' + args.appIdSuffix : packageName;

  const adbPath = getAdbPath();
  if (args.deviceId) {
    if (isString(args.deviceId)) {
        runOnSpecificDevice(args, cmd, packageNameWithSuffix, packageName, adbPath);
    } else {
      console.log(chalk.red('Argument missing for parameter --deviceId'));
    }
  } else {
    runOnAllDevices(args, cmd, packageNameWithSuffix, packageName, adbPath);
  }
}

function runOnSpecificDevice(args, gradlew, packageNameWithSuffix, packageName, adbPath) {
  let devices = adb.getDevices();
  if (devices && devices.length > 0) {
    if (devices.indexOf(args.deviceId) !== -1) {
      buildApk(gradlew);
      installAndLaunchOnDevice(args, args.deviceId, packageNameWithSuffix, 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 {
    console.log(chalk.bold('Building the app...'));

    // 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, read the error above for details.\n'));
  }
}

function tryInstallAppOnDevice(args, device) {
  try {
    const pathToApk = `${args.appFolder}/build/outputs/apk/${args.appFolder}-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, packageNameWithSuffix, packageName, adbPath, mainActivity) {
  try {
    const adbArgs = ['-s', device, 'shell', 'am', 'start', '-n', packageNameWithSuffix + '/' + 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, packageNameWithSuffix, packageName, adbPath) {
  tryRunAdbReverse(selectedDevice);
  tryInstallAppOnDevice(args, selectedDevice);
  tryLaunchAppOnDevice(selectedDevice, packageNameWithSuffix, packageName, adbPath, args.mainActivity);
}

function runOnAllDevices(args, cmd, packageNameWithSuffix, packageName, adbPath){
  try {
    const gradleArgs = [];
    if (args.variant) {
      gradleArgs.push('install' +
        args.variant[0].toUpperCase() + args.variant.slice(1)
      );
    } else if (args.flavor) {
      console.warn(chalk.yellow(
        '--flavor has been deprecated. Use --variant instead'
      ));
      gradleArgs.push('install' +
        args.flavor[0].toUpperCase() + args.flavor.slice(1)
      );
    } else {
      gradleArgs.push('installDebug');
    }

    if (args.installDebug) {
      gradleArgs.push(args.installDebug);
    }

    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)`
    return Promise.reject();
  }
    const devices = adb.getDevices();
    if (devices && devices.length > 0) {
      devices.forEach((device) => {
        tryRunAdbReverse(device);
        tryLaunchAppOnDevice(device, packageNameWithSuffix, packageName, adbPath, args.mainActivity);
      });
    } else {
      try {
        // If we cannot execute based on adb devices output, fall back to
        // shell am start
        const fallbackAdbArgs = [
          'shell', 'am', 'start', '-n', packageNameWithSuffix + '/' + 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();
      }
    }
}

function startServerInNewWindow() {
  const yargV = require('yargs').argv;
  const scriptFile = /^win/.test(process.platform) ?
    'launchPackager.bat' :
    'launchPackager.command';
  const packagerDir = path.resolve(__dirname, '..', '..', 'packager');
  const launchPackagerScript = path.resolve(packagerDir, scriptFile);
  const procConfig = {cwd: packagerDir};

  if (process.platform === 'darwin') {
    if (yargV.open) {
      return child_process.spawnSync('open', ['-a', yargV.open, launchPackagerScript], procConfig);
    }
    return child_process.spawnSync('open', [launchPackagerScript], procConfig);

  } else if (process.platform === 'linux') {
    procConfig.detached = true;
    if (yargV.open){
      return child_process.spawn(yargV.open,['-e', 'sh', launchPackagerScript], procConfig);
    }
    return child_process.spawn('sh', [launchPackagerScript], procConfig);

  } else if (/^win/.test(process.platform)) {
    procConfig.detached = true;
    procConfig.stdio = 'ignore';
    return child_process.spawn('cmd.exe', ['/C', launchPackagerScript], procConfig);
  } else {
    console.log(chalk.red(`Cannot start the packager. Unknown platform ${process.platform}`));
  }
}

module.exports = {
  name: 'run-android',
  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)',
    default: '',
  }, {
    command: '--flavor [string]',
    description: '--flavor has been deprecated. Use --variant instead',
  }, {
    command: '--variant [string]',
  }, {
    command: '--appFolder [string]',
    description: 'Specify a different application folder name for the android source.',
    default: 'app',
  }, {
    command: '--appIdSuffix [string]',
    description: 'Specify an applicationIdSuffix to launch after build.',
    default: '',
  }, {
    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).',
  }, {
    command: '--no-packager',
    description: 'Do not launch packager while building',
  }],
};

它们位于/ node_modules / react-native