microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
fced706df75baed17e7c94a4b833767cbc0edf9f

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/debugger/android/androidPlatform.ts

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