microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.5.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/exponent/exponentPlatform.ts

214lines · 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 { ErrorHelper } from "../../common/error/errorHelper";
5import { InternalErrorCode } from "../../common/error/internalErrorCode";
6import { ExpoHostType, IExponentRunOptions, PlatformType } from "../launchArgs";
7import { GeneralMobilePlatform, MobilePlatformDeps } from "../generalMobilePlatform";
8import { ExponentHelper } from "./exponentHelper";
9import { TelemetryHelper } from "../../common/telemetryHelper";
10import { QRCodeContentProvider } from "../qrCodeContentProvider";
11
12import * as vscode from "vscode";
13import * as XDL from "./xdlInterface";
14import * as url from "url";
15import * as nls from "vscode-nls";
16nls.config({
17 messageFormat: nls.MessageFormat.bundle,
18 bundleFormat: nls.BundleFormat.standalone,
19})();
20const localize = nls.loadMessageBundle();
21
22export class ExponentPlatform extends GeneralMobilePlatform {
23 private exponentTunnelPath: string | null;
24 private exponentHelper: ExponentHelper;
25 private qrCodeContentProvider: QRCodeContentProvider = new QRCodeContentProvider();
26
27 constructor(runOptions: IExponentRunOptions, platformDeps: MobilePlatformDeps = {}) {
28 super(runOptions, platformDeps);
29 this.exponentHelper = this.packager.getExponentHelper();
30 this.exponentTunnelPath = null;
31 }
32
33 public runApp(): Promise<void> {
34 let extProps = {
35 platform: {
36 value: PlatformType.Exponent,
37 isPii: false,
38 },
39 };
40
41 extProps = TelemetryHelper.addPlatformPropertiesToTelemetryProperties(
42 this.runOptions,
43 this.runOptions.reactNativeVersions,
44 extProps,
45 );
46
47 return new Promise((resolve, reject) => {
48 TelemetryHelper.generate("ExponentPlatform.runApp", extProps, () => {
49 return this.loginToExponentOrSkip(this.runOptions.expoHostType)
50 .then(() =>
51 XDL.setOptions(this.projectPath, { packagerPort: this.packager.getPort() }),
52 )
53 .then(() => XDL.startExponentServer(this.projectPath))
54 .then(() => {
55 if (this.runOptions.expoHostType !== "tunnel") {
56 // the purpose of this is to save the same sequence of handling 'adb reverse' command execution as in Expo
57 // https://github.com/expo/expo-cli/blob/1d515d21200841e181518358fd9dc4c7b24c7cd6/packages/xdl/src/Project.ts#L2226-L2370
58 // we added this to be sure that our Expo launching logic doesn't have any negative side effects
59 return XDL.stopAdbReverse(this.projectPath);
60 }
61 return this.prepareExpoTunnels();
62 })
63 .then(() => {
64 if (this.runOptions.expoHostType !== "local") return false;
65 // we need to execute 'adb reverse' command to bind ports used by Expo and RN of local machine to ports of a connected Android device or a running emulator
66 return XDL.startAdbReverse(this.projectPath);
67 })
68 .then(isAdbReversed => {
69 switch (this.runOptions.expoHostType) {
70 case "lan":
71 return XDL.getUrl(this.projectPath, {
72 dev: true,
73 minify: false,
74 hostType: "lan",
75 });
76 case "local":
77 if (isAdbReversed) {
78 this.logger.info(
79 localize(
80 "ExpoStartAdbReverseSuccess",
81 "A device or an emulator was found, 'adb reverse' command successfully executed.",
82 ),
83 );
84 } else {
85 this.logger.warning(
86 localize(
87 "ExpoStartAdbReverseFailure",
88 "Adb reverse command failed. Couldn't find connected over usb device or running emulator. Also please make sure that there is only one currently connected device or running emulator.",
89 ),
90 );
91 }
92
93 return XDL.getUrl(this.projectPath, {
94 dev: true,
95 minify: false,
96 hostType: "localhost",
97 });
98 case "tunnel":
99 default:
100 return XDL.getUrl(this.projectPath, { dev: true, minify: false });
101 }
102 })
103 .then(exponentUrl => {
104 return "exp://" + url.parse(exponentUrl).host;
105 })
106 .then(exponentUrl => {
107 if (this.runOptions.openExpoQR) {
108 let exponentPage = vscode.window.createWebviewPanel(
109 "Expo QR Code",
110 "Expo QR Code",
111 vscode.ViewColumn.Two,
112 {},
113 );
114 exponentPage.webview.html = this.qrCodeContentProvider.provideTextDocumentContent(
115 vscode.Uri.parse(exponentUrl),
116 );
117 }
118 return exponentUrl;
119 })
120 .then(exponentUrl => {
121 if (!exponentUrl) {
122 return reject(
123 ErrorHelper.getInternalError(
124 InternalErrorCode.ExpectedExponentTunnelPath,
125 ),
126 );
127 }
128 this.exponentTunnelPath = exponentUrl;
129 const outputMessage = localize(
130 "ExponentServerIsRunningOpenToSeeIt",
131 "Expo server is running. Open your Expo app at {0} to see it.",
132 this.exponentTunnelPath,
133 );
134 this.logger.info(outputMessage);
135
136 const copyButton = localize("CopyToClipboard", "Copy to clipboard");
137
138 vscode.window
139 .showInformationMessage(outputMessage, copyButton)
140 .then(selection => {
141 if (selection === copyButton) {
142 vscode.env.clipboard.writeText(exponentUrl);
143 }
144 });
145
146 return resolve();
147 })
148 .catch(reason => {
149 return reject(reason);
150 });
151 });
152 });
153 }
154
155 public loginToExponentOrSkip(expoHostType?: ExpoHostType): Promise<any> {
156 if (expoHostType !== "tunnel") {
157 return Promise.resolve();
158 }
159 return this.exponentHelper.loginToExponent(
160 (message, password) => {
161 return new Promise((resolve, reject) => {
162 vscode.window
163 .showInputBox({ placeHolder: message, password: password })
164 .then(login => {
165 resolve(login || "");
166 }, reject);
167 });
168 },
169 message => {
170 return new Promise((resolve, reject) => {
171 const okButton = { title: "Ok" };
172 const cancelButton = { title: "Cancel", isCloseAffordance: true };
173 vscode.window
174 .showInformationMessage(message, { modal: true }, okButton, cancelButton)
175 .then(answer => {
176 if (answer === cancelButton) {
177 reject(
178 ErrorHelper.getInternalError(
179 InternalErrorCode.UserCancelledExpoLogin,
180 ),
181 );
182 }
183 resolve("");
184 }, reject);
185 });
186 },
187 );
188 }
189
190 public beforeStartPackager(): Promise<void> {
191 return this.exponentHelper.configureExponentEnvironment();
192 }
193
194 public enableJSDebuggingMode(): Promise<void> {
195 this.logger.info(
196 localize(
197 "ApplicationIsRunningOnExponentShakeDeviceForRemoteDebugging",
198 "Application is running on Expo. Please shake device and select 'Debug JS Remotely' to enable debugging.",
199 ),
200 );
201 return Promise.resolve();
202 }
203
204 public getRunArguments(): string[] {
205 return [];
206 }
207
208 private prepareExpoTunnels(): Promise<void> {
209 return this.exponentHelper
210 .findOrInstallNgrokGlobally()
211 .then(() => XDL.startTunnels(this.projectPath))
212 .finally(() => this.exponentHelper.removeNodeModulesPathFromEnvIfWasSet());
213 }
214}
215