microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2166bdab04078d2a37e6331ce43e869d0ed0b7a4

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/debugger/android/androidPlatform.ts

112lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as Q from "q";
5
6import {IAppPlatform} from "../platformResolver";
7import {CommandExecutor} from "../../common/commandExecutor";
8import {ExtensionMessageSender, ExtensionMessage} from "../../common/extensionMessaging";
9import {IRunOptions} from "../../common/launchArgs";
10import {Log} from "../../common/log/log";
11import {PackageNameResolver} from "../../common/android/packageNameResolver";
12import {OutputVerifier, PatternToFailure} from "../../common/outputVerifier";
13import {DeviceHelper, IDevice} from "../../common/android/deviceHelper";
14import {Package} from "../../common/node/package";
15
16/**
17 * Android specific platform implementation for debugging RN applications.
18 */
19export class AndroidPlatform implements IAppPlatform {
20 private extensionMessageSender: ExtensionMessageSender;
21
22 private static MULTIPLE_DEVICES_ERROR = "error: more than one device/emulator";
23
24 // We should add the common Android build/run erros we find to this list
25 private static RUN_ANDROID_FAILURE_PATTERNS: PatternToFailure = {
26 "Failed to install on any devices": "Could not install the app on any available device. Make sure you have a correctly"
27 + " configured device or emulator running. See https://facebook.github.io/react-native/docs/android-setup.html",
28 "com.android.ddmlib.ShellCommandUnresponsiveException": "An Android shell command timed-out. Please retry the operation.",
29 "Android project not found": "Android project not found.",
30 "error: more than one device/emulator": AndroidPlatform.MULTIPLE_DEVICES_ERROR };
31
32 private static RUN_ANDROID_SUCCESS_PATTERNS: string[] = ["BUILD SUCCESSFUL", "Starting the app", "Starting: Intent"];
33
34 private debugTarget: string;
35 private devices: IDevice[];
36 private packageName: string;
37 private deviceHelper: DeviceHelper;
38
39 constructor({ extensionMessageSender = new ExtensionMessageSender()} = {}) {
40 this.extensionMessageSender = extensionMessageSender;
41 this.deviceHelper = new DeviceHelper();
42 }
43
44 public runApp(runOptions: IRunOptions): Q.Promise<void> {
45 let cexec = new CommandExecutor(runOptions.projectRoot);
46
47 const runAndroidSpawn = cexec.spawnChildReactCommandProcess("run-android");
48 const output = new OutputVerifier(
49 () =>
50 Q(AndroidPlatform.RUN_ANDROID_SUCCESS_PATTERNS),
51 () =>
52 Q(AndroidPlatform.RUN_ANDROID_FAILURE_PATTERNS)).process(runAndroidSpawn);
53
54 return output
55 .finally(() => {
56 return this.deviceHelper.getConnectedDevices().then(devices => {
57 this.devices = devices;
58 this.debugTarget = this.getTargetEmulator(runOptions, devices);
59 return this.getPackageName(runOptions.projectRoot).then(packageName =>
60 this.packageName = packageName);
61 });
62 }).catch(reason => {
63 if (reason.message === AndroidPlatform.MULTIPLE_DEVICES_ERROR && this.devices.length > 1 && this.debugTarget) {
64 /* If it failed due to multiple devices, we'll apply this workaround to make it work anyways */
65 return this.deviceHelper.launchApp(runOptions.projectRoot, this.packageName, this.debugTarget);
66 } else {
67 return Q.reject<void>(reason);
68 }
69 }).then(() =>
70 this.startMonitoringLogCat(runOptions.logCatArguments).catch(error => // The LogCatMonitor failing won't stop the debugging experience
71 Log.logWarning("Couldn't start LogCat monitor", error)));
72 }
73
74 public enableJSDebuggingMode(runOptions: IRunOptions): Q.Promise<void> {
75 return this.deviceHelper.reloadAppInDebugMode(runOptions.projectRoot, this.packageName, this.debugTarget);
76 }
77
78 private getPackageName(projectRoot: string): Q.Promise<string> {
79 return new Package(projectRoot).name().then(appName =>
80 new PackageNameResolver(appName).resolvePackageName(projectRoot));
81 }
82
83 /**
84 * Returns the target emulator, using the following logic:
85 * * If an emulator is specified and it is connected, use that one.
86 * * Otherwise, use the first one in the list.
87 */
88 private getTargetEmulator(runOptions: IRunOptions, devices: IDevice[]): string {
89 let activeFilterFunction = (device: IDevice) => {
90 return device.isOnline;
91 };
92
93 let targetFilterFunction = (device: IDevice) => {
94 return device.id === runOptions.target && activeFilterFunction(device);
95 };
96
97 if (runOptions && runOptions.target && devices) {
98 /* check if the specified target is active */
99 if (devices.some(targetFilterFunction)) {
100 return runOptions.target;
101 }
102 }
103
104 /* return the first active device in the list */
105 let activeDevices = devices && devices.filter(activeFilterFunction);
106 return activeDevices && activeDevices[0] && activeDevices[0].id;
107 }
108
109 private startMonitoringLogCat(logCatArguments: string): Q.Promise<void> {
110 return this.extensionMessageSender.sendMessage(ExtensionMessage.START_MONITORING_LOGCAT, [this.debugTarget, logCatArguments]);
111 }
112}