├── .gitignore ├── LICENSE ├── README.md ├── cli.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Nicholas Pisacane 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-run-android 2 | 3 | Simplified android emulation for react-native apps. 4 | 5 | ## Video of Usage 6 | 7 | [![Example](http://img.youtube.com/vi/IGveUZj5W_k/0.jpg)](http://www.youtube.com/watch?v=IGveUZj5W_k "react-native-run-android usage") 8 | 9 | ## Installation 10 | 11 | ```sh 12 | $ npm i -g react-native-run-android 13 | ``` 14 | 15 | ## Usage 16 | ```sh 17 | # Run in the directory of your react-native project 18 | $ react-native-run-android 19 | ``` 20 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const { spawn, execSync } = require('child_process') 4 | const path = require('path') 5 | const shell = require('shelljs') 6 | const inquirer = require('inquirer') 7 | const chalk = require('chalk') 8 | 9 | const APP_NAME = 'react-native-run-android' 10 | const RN_URI = 'https://facebook.github.io/react-native/docs/getting-started.html' 11 | const REQUIRED_BINS = [ 12 | 'react-native', 13 | 'emulator', 14 | 'adb' 15 | ] 16 | 17 | const whichEmulator = shell.which('emulator') 18 | let emulatorProc = null 19 | let reactNativePackagerProc = null 20 | let reactNativeProc = null 21 | 22 | const showDepFailureMessgae = () => console.error( 23 | chalk.red(`Please refer to `) + chalk.blue(`${RN_URI}`) + 24 | ` for installation/setup instructions` 25 | ) 26 | 27 | const requireBin = bin => { 28 | if (!shell.which(bin)) { 29 | console.error(chalk.red(`${APP_NAME} requires ${bin}.`)) 30 | showDepFailureMessgae() 31 | process.exit(1) 32 | } 33 | } 34 | 35 | const getDevices = () => shell.exec(`emulator -list-avds`).stdout 36 | .split(/\n/) 37 | .map(s => s.trim()) 38 | 39 | const adbDeviceIsRunning = () => /emulator-\d+\s+device/.test( 40 | execSync(`adb devices`).toString() 41 | ) 42 | 43 | const pollADBDevice = (maxTime = 60000) => new Promise((resolve, reject) => { 44 | const start = Date.now() 45 | const timer = setInterval(() => { 46 | if (adbDeviceIsRunning()) { 47 | clearInterval(timer) 48 | resolve() 49 | } 50 | if (Date.now() - start >= maxTime) { 51 | clearInterval(timer) 52 | reject(new Error('No device running')) 53 | } 54 | }) 55 | }) 56 | 57 | const emulateDevice = device => { 58 | console.log(chalk.blue(`Starting emulator for device ${device}`)) 59 | emulatorProc = spawn('emulator', [`@${device}`], { 60 | cwd: path.dirname(whichEmulator.stdout), 61 | stdio: ['pipe', process.stdout, process.stderr] 62 | }) 63 | 64 | return pollADBDevice().then(() => { 65 | console.log(chalk.blue(`Device is running`)) 66 | return true 67 | }) 68 | } 69 | 70 | const startReactNativePackager = () => { 71 | console.log(chalk.blue(`Starting react-native package server`)) 72 | reactNativePacakgerProc = spawn('react-native', ['start'], { 73 | stdio: ['pipe', process.stdout, process.stderr] 74 | }) 75 | 76 | return Promise.resolve() 77 | } 78 | 79 | const startReactNative = () => { 80 | console.log(chalk.blue(`Starting react-native`)) 81 | reactNativeProc = spawn('react-native', ['run-android'], { 82 | stdio: ['pipe', process.stdout, process.stderr] 83 | }) 84 | } 85 | 86 | const main = () => { 87 | REQUIRED_BINS.forEach(requireBin) 88 | 89 | const devices = getDevices() 90 | 91 | if (!devices || !devices.length) { 92 | console.error(chalk.red(`Please create a virtual device`)) 93 | showDepFailureMessgae() 94 | process.exit(1) 95 | } 96 | 97 | inquirer.prompt([ 98 | { 99 | type: 'list', 100 | name: 'device', 101 | message: 'Which device would you like to use?', 102 | choices: devices 103 | } 104 | ]) 105 | .then(answer => { 106 | const { device } = answer 107 | 108 | return Promise.all([ 109 | emulateDevice(device), 110 | startReactNativePackager() 111 | ]) 112 | .then(() => startReactNative()) 113 | }) 114 | .catch(err => { 115 | console.error(chalk.red`Something failed:\n`, err) 116 | }) 117 | } 118 | 119 | main() 120 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-run-android", 3 | "version": "0.0.1", 4 | "description": "Simplified android emulation for react-native apps.", 5 | "main": "cli.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "engines": { 10 | "node": ">=6.10.1" 11 | }, 12 | "bin": { 13 | "react-native-run-android": "cli.js" 14 | }, 15 | "keywords": [ 16 | "react-native", 17 | "react native", 18 | "android" 19 | ], 20 | "author": "Nicholas Pisacane ", 21 | "homepage": "https://github.com/nickpisacane/react-native-run-android", 22 | "repository": { 23 | "type": "git", 24 | "url": "https://github.com/nickpisacane/react-native-run-android" 25 | }, 26 | "license": "MIT", 27 | "dependencies": { 28 | "chalk": "^1.1.3", 29 | "inquirer": "^3.0.6", 30 | "shelljs": "^0.7.7" 31 | } 32 | } 33 | --------------------------------------------------------------------------------