microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
df4bce4041caa61af1460ef87f2380820508a455

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/debugger/android/androidPlatform.ts

120lines · 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 {ExtensionMessageSender, ExtensionMessage} from "../../common/extensionMessaging";
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 extensionMessageSender: ExtensionMessageSender;
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({ extensionMessageSender = new ExtensionMessageSender(),
44 deviceHelper = <IDeviceHelper>new DeviceHelper(),
45 reactNative = <IReactNative>new ReactNative(),
46 fileSystem = new FileSystem(),
47 } = {}) {
48 this.extensionMessageSender = extensionMessageSender;
49 this.deviceHelper = deviceHelper;
50 this.reactNative = reactNative;
51 this.fileSystem = fileSystem;
52 }
53
54 public runApp(runOptions: IRunOptions): Q.Promise<void> {
55 const runAndroidSpawn = this.reactNative.runAndroid(runOptions.projectRoot);
56 const output = new OutputVerifier(
57 () =>
58 Q(AndroidPlatform.RUN_ANDROID_SUCCESS_PATTERNS),
59 () =>
60 Q(AndroidPlatform.RUN_ANDROID_FAILURE_PATTERNS)).process(runAndroidSpawn);
61
62 return output
63 .finally(() => {
64 return this.deviceHelper.getConnectedDevices().then(devices => {
65 this.devices = devices;
66 this.debugTarget = this.getTargetEmulator(runOptions, devices);
67 return this.getPackageName(runOptions.projectRoot).then(packageName =>
68 this.packageName = packageName);
69 });
70 }).catch(reason => {
71 if (reason.message === AndroidPlatform.MULTIPLE_DEVICES_ERROR && this.devices.length > 1 && this.debugTarget) {
72 /* If it failed due to multiple devices, we'll apply this workaround to make it work anyways */
73 return this.deviceHelper.launchApp(runOptions.projectRoot, this.packageName, this.debugTarget);
74 } else {
75 return Q.reject<void>(reason);
76 }
77 }).then(() =>
78 this.startMonitoringLogCat(runOptions.logCatArguments).catch(error => // The LogCatMonitor failing won't stop the debugging experience
79 Log.logWarning("Couldn't start LogCat monitor", error)));
80 }
81
82 public enableJSDebuggingMode(runOptions: IRunOptions): Q.Promise<void> {
83 return this.deviceHelper.reloadAppInDebugMode(runOptions.projectRoot, this.packageName, this.debugTarget);
84 }
85
86 private getPackageName(projectRoot: string): Q.Promise<string> {
87 return new Package(projectRoot, { fileSystem: this.fileSystem }).name().then(appName =>
88 new PackageNameResolver(appName).resolvePackageName(projectRoot));
89 }
90
91 /**
92 * Returns the target emulator, using the following logic:
93 * * If an emulator is specified and it is connected, use that one.
94 * * Otherwise, use the first one in the list.
95 */
96 private getTargetEmulator(runOptions: IRunOptions, devices: IDevice[]): string {
97 let activeFilterFunction = (device: IDevice) => {
98 return device.isOnline;
99 };
100
101 let targetFilterFunction = (device: IDevice) => {
102 return device.id === runOptions.target && activeFilterFunction(device);
103 };
104
105 if (runOptions && runOptions.target && devices) {
106 /* check if the specified target is active */
107 if (devices.some(targetFilterFunction)) {
108 return runOptions.target;
109 }
110 }
111
112 /* return the first active device in the list */
113 let activeDevices = devices && devices.filter(activeFilterFunction);
114 return activeDevices && activeDevices[0] && activeDevices[0].id;
115 }
116
117 private startMonitoringLogCat(logCatArguments: string): Q.Promise<void> {
118 return this.extensionMessageSender.sendMessage(ExtensionMessage.START_MONITORING_LOGCAT, [this.debugTarget, logCatArguments]);
119 }
120}