UNPKG

10.7 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8function _path() {
9 const data = _interopRequireDefault(require("path"));
10
11 _path = function () {
12 return data;
13 };
14
15 return data;
16}
17
18function _execa() {
19 const data = _interopRequireDefault(require("execa"));
20
21 _execa = function () {
22 return data;
23 };
24
25 return data;
26}
27
28function _chalk() {
29 const data = _interopRequireDefault(require("chalk"));
30
31 _chalk = function () {
32 return data;
33 };
34
35 return data;
36}
37
38function _fs() {
39 const data = _interopRequireDefault(require("fs"));
40
41 _fs = function () {
42 return data;
43 };
44
45 return data;
46}
47
48var _adb = _interopRequireDefault(require("./adb"));
49
50var _runOnAllDevices = _interopRequireDefault(require("./runOnAllDevices"));
51
52var _tryRunAdbReverse = _interopRequireDefault(require("./tryRunAdbReverse"));
53
54var _tryLaunchAppOnDevice = _interopRequireDefault(require("./tryLaunchAppOnDevice"));
55
56var _getAdbPath = _interopRequireDefault(require("./getAdbPath"));
57
58function _cliTools() {
59 const data = require("@react-native-community/cli-tools");
60
61 _cliTools = function () {
62 return data;
63 };
64
65 return data;
66}
67
68var _getAndroidProject = require("../../config/getAndroidProject");
69
70function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
71
72/**
73 * Copyright (c) Facebook, Inc. and its affiliates.
74 *
75 * This source code is licensed under the MIT license found in the
76 * LICENSE file in the root directory of this source tree.
77 *
78 */
79
80/**
81 * Starts the app on a connected Android emulator or device.
82 */
83async function runAndroid(_argv, config, args) {
84 const androidProject = (0, _getAndroidProject.getAndroidProject)(config);
85
86 if (args.jetifier) {
87 _cliTools().logger.info(`Running ${_chalk().default.bold('jetifier')} to migrate libraries to AndroidX. ${_chalk().default.dim('You can disable it using "--no-jetifier" flag.')}`);
88
89 try {
90 await (0, _execa().default)(require.resolve('jetifier/bin/jetify'), {
91 stdio: 'inherit'
92 });
93 } catch (error) {
94 throw new (_cliTools().CLIError)('Failed to run jetifier.', error);
95 }
96 }
97
98 if (!args.packager) {
99 return buildAndRun(args, androidProject);
100 }
101
102 return (0, _cliTools().isPackagerRunning)(args.port).then(result => {
103 if (result === 'running') {
104 _cliTools().logger.info('JS server already running.');
105 } else if (result === 'unrecognized') {
106 _cliTools().logger.warn('JS server not recognized, continuing with build...');
107 } else {
108 // result == 'not_running'
109 _cliTools().logger.info('Starting JS server...');
110
111 try {
112 startServerInNewWindow(args.port, args.terminal, config.reactNativePath);
113 } catch (error) {
114 _cliTools().logger.warn(`Failed to automatically start the packager server. Please run "react-native start" manually. Error details: ${error.message}`);
115 }
116 }
117
118 return buildAndRun(args, androidProject);
119 });
120} // Builds the app and runs it on a connected emulator / device.
121
122
123function buildAndRun(args, androidProject) {
124 process.chdir(androidProject.sourceDir);
125 const cmd = process.platform.startsWith('win') ? 'gradlew.bat' : './gradlew';
126 const adbPath = (0, _getAdbPath.default)();
127
128 if (args.deviceId) {
129 return runOnSpecificDevice(args, cmd, adbPath, androidProject);
130 } else {
131 return (0, _runOnAllDevices.default)(args, cmd, adbPath, androidProject);
132 }
133}
134
135function runOnSpecificDevice(args, gradlew, adbPath, androidProject) {
136 const devices = _adb.default.getDevices(adbPath);
137
138 const {
139 deviceId
140 } = args;
141
142 if (devices.length > 0 && deviceId) {
143 if (devices.indexOf(deviceId) !== -1) {
144 buildApk(gradlew, androidProject.sourceDir);
145 installAndLaunchOnDevice(args, deviceId, adbPath, androidProject);
146 } else {
147 _cliTools().logger.error(`Could not find device with the id: "${deviceId}". Please choose one of the following:`, ...devices);
148 }
149 } else {
150 _cliTools().logger.error('No Android device or emulator connected.');
151 }
152}
153
154function buildApk(gradlew, sourceDir) {
155 try {
156 // using '-x lint' in order to ignore linting errors while building the apk
157 const gradleArgs = ['build', '-x', 'lint'];
158
159 _cliTools().logger.info('Building the app...');
160
161 _cliTools().logger.debug(`Running command "${gradlew} ${gradleArgs.join(' ')}"`);
162
163 _execa().default.sync(gradlew, gradleArgs, {
164 stdio: 'inherit',
165 cwd: sourceDir
166 });
167 } catch (error) {
168 throw new (_cliTools().CLIError)('Failed to build the app.', error);
169 }
170}
171
172function tryInstallAppOnDevice(args, adbPath, device, androidProject) {
173 try {
174 // "app" is usually the default value for Android apps with only 1 app
175 const {
176 appName,
177 sourceDir
178 } = androidProject;
179 const variant = args.variant.toLowerCase();
180 const buildDirectory = `${sourceDir}/${appName}/build/outputs/apk/${variant}`;
181 const apkFile = getInstallApkName(appName, adbPath, variant, device, buildDirectory);
182 const pathToApk = `${buildDirectory}/${apkFile}`;
183 const adbArgs = ['-s', device, 'install', '-r', '-d', pathToApk];
184
185 _cliTools().logger.info(`Installing the app on the device "${device}"...`);
186
187 _cliTools().logger.debug(`Running command "cd android && adb -s ${device} install -r -d ${pathToApk}"`);
188
189 _execa().default.sync(adbPath, adbArgs, {
190 stdio: 'inherit'
191 });
192 } catch (error) {
193 throw new (_cliTools().CLIError)('Failed to install the app on the device.', error);
194 }
195}
196
197function getInstallApkName(appName, adbPath, variant, device, buildDirectory) {
198 const availableCPUs = _adb.default.getAvailableCPUs(adbPath, device); // check if there is an apk file like app-armeabi-v7a-debug.apk
199
200
201 for (const availableCPU of availableCPUs.concat('universal')) {
202 const apkName = `${appName}-${availableCPU}-${variant}.apk`;
203
204 if (_fs().default.existsSync(`${buildDirectory}/${apkName}`)) {
205 return apkName;
206 }
207 } // check if there is a default file like app-debug.apk
208
209
210 const apkName = `${appName}-${variant}.apk`;
211
212 if (_fs().default.existsSync(`${buildDirectory}/${apkName}`)) {
213 return apkName;
214 }
215
216 throw new (_cliTools().CLIError)('Could not find the correct install APK file.');
217}
218
219function installAndLaunchOnDevice(args, selectedDevice, adbPath, androidProject) {
220 (0, _tryRunAdbReverse.default)(args.port, selectedDevice);
221 tryInstallAppOnDevice(args, adbPath, selectedDevice, androidProject);
222 (0, _tryLaunchAppOnDevice.default)(selectedDevice, androidProject.packageName, adbPath, args);
223}
224
225function startServerInNewWindow(port, terminal, reactNativePath) {
226 /**
227 * Set up OS-specific filenames and commands
228 */
229 const isWindows = /^win/.test(process.platform);
230 const scriptFile = isWindows ? 'launchPackager.bat' : 'launchPackager.command';
231 const packagerEnvFilename = isWindows ? '.packager.bat' : '.packager.env';
232 const portExportContent = isWindows ? `set RCT_METRO_PORT=${port}` : `export RCT_METRO_PORT=${port}`;
233 /**
234 * Set up the `.packager.(env|bat)` file to ensure the packager starts on the right port.
235 */
236
237 const launchPackagerScript = _path().default.join(reactNativePath, `scripts/${scriptFile}`);
238 /**
239 * Set up the `launchpackager.(command|bat)` file.
240 * It lives next to `.packager.(bat|env)`
241 */
242
243
244 const scriptsDir = _path().default.dirname(launchPackagerScript);
245
246 const packagerEnvFile = _path().default.join(scriptsDir, packagerEnvFilename);
247
248 const procConfig = {
249 cwd: scriptsDir
250 };
251 /**
252 * Ensure we overwrite file by passing the `w` flag
253 */
254
255 _fs().default.writeFileSync(packagerEnvFile, portExportContent, {
256 encoding: 'utf8',
257 flag: 'w'
258 });
259
260 if (process.platform === 'darwin') {
261 try {
262 return _execa().default.sync('open', ['-a', terminal, launchPackagerScript], procConfig);
263 } catch (error) {
264 return _execa().default.sync('open', [launchPackagerScript], procConfig);
265 }
266 }
267
268 if (process.platform === 'linux') {
269 try {
270 return _execa().default.sync(terminal, ['-e', `sh ${launchPackagerScript}`], { ...procConfig,
271 detached: true
272 });
273 } catch (error) {
274 // By default, the child shell process will be attached to the parent
275 return _execa().default.sync('sh', [launchPackagerScript], procConfig);
276 }
277 }
278
279 if (/^win/.test(process.platform)) {
280 // Awaiting this causes the CLI to hang indefinitely, so this must execute without await.
281 return (0, _execa().default)('cmd.exe', ['/C', launchPackagerScript], { ...procConfig,
282 detached: true,
283 stdio: 'ignore'
284 });
285 }
286
287 _cliTools().logger.error(`Cannot start the packager. Unknown platform ${process.platform}`);
288
289 return;
290}
291
292var _default = {
293 name: 'run-android',
294 description: 'builds your app and starts it on a connected Android emulator or device',
295 func: runAndroid,
296 options: [{
297 name: '--variant <string>',
298 description: "Specify your app's build variant",
299 default: 'debug'
300 }, {
301 name: '--appId <string>',
302 description: 'Specify an applicationId to launch after build. If not specified, `package` from AndroidManifest.xml will be used.',
303 default: ''
304 }, {
305 name: '--appIdSuffix <string>',
306 description: 'Specify an applicationIdSuffix to launch after build.',
307 default: ''
308 }, {
309 name: '--main-activity <string>',
310 description: 'Name of the activity to start',
311 default: 'MainActivity'
312 }, {
313 name: '--deviceId <string>',
314 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).'
315 }, {
316 name: '--no-packager',
317 description: 'Do not launch packager while building'
318 }, {
319 name: '--port <number>',
320 default: process.env.RCT_METRO_PORT || 8081,
321 parse: Number
322 }, {
323 name: '--terminal <string>',
324 description: 'Launches the Metro Bundler in a new window using the specified terminal path.',
325 default: (0, _cliTools().getDefaultUserTerminal)()
326 }, {
327 name: '--tasks <list>',
328 description: 'Run custom Gradle tasks. By default it\'s "installDebug"',
329 parse: val => val.split(',')
330 }, {
331 name: '--no-jetifier',
332 description: 'Do not run "jetifier" – the AndroidX transition tool. By default it runs before Gradle to ease working with libraries that don\'t support AndroidX yet. See more at: https://www.npmjs.com/package/jetifier.'
333 }, {
334 name: '--active-arch-only',
335 description: 'Build native libraries only for the current device architecture for debug builds.',
336 default: false
337 }]
338};
339exports.default = _default;
340
341//# sourceMappingURL=index.js.map
\No newline at end of file