microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.7.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/exponent/exponentPlatform.ts

195lines · 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 async 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 await TelemetryHelper.generate("ExponentPlatform.runApp", extProps, async () => {
48 await this.loginToExponentOrSkip(this.runOptions.expoHostType);
49 await XDL.setOptions(this.projectPath, { packagerPort: this.packager.getPort() });
50 await XDL.startExponentServer(this.projectPath);
51
52 // the purpose of this is to save the same sequence of handling 'adb reverse' command execution as in Expo
53 // https://github.com/expo/expo-cli/blob/1d515d21200841e181518358fd9dc4c7b24c7cd6/packages/xdl/src/Project.ts#L2226-L2370
54 // we added this to be sure that our Expo launching logic doesn't have any negative side effects
55
56 if (this.runOptions.expoHostType === "tunnel") {
57 await this.prepareExpoTunnels();
58 } else {
59 await XDL.stopAdbReverse(this.projectPath);
60 }
61
62 const isAdbReversed =
63 this.runOptions.expoHostType !== "local"
64 ? 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 await XDL.startAdbReverse(this.projectPath);
67 let exponentUrl = "";
68 switch (this.runOptions.expoHostType) {
69 case "lan":
70 exponentUrl = await XDL.getUrl(this.projectPath, {
71 dev: true,
72 minify: false,
73 hostType: "lan",
74 });
75 break;
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 exponentUrl = await XDL.getUrl(this.projectPath, {
94 dev: true,
95 minify: false,
96 hostType: "localhost",
97 });
98 break;
99 case "tunnel":
100 default:
101 exponentUrl = await XDL.getUrl(this.projectPath, { dev: true, minify: false });
102 }
103 exponentUrl = "exp://" + url.parse(exponentUrl).host;
104
105 if (!exponentUrl) {
106 throw ErrorHelper.getInternalError(InternalErrorCode.ExpectedExponentTunnelPath);
107 }
108
109 if (this.runOptions.openExpoQR) {
110 let exponentPage = vscode.window.createWebviewPanel(
111 "Expo QR Code",
112 "Expo QR Code",
113 vscode.ViewColumn.Two,
114 {},
115 );
116 exponentPage.webview.html = this.qrCodeContentProvider.provideTextDocumentContent(
117 vscode.Uri.parse(exponentUrl),
118 );
119 }
120
121 this.exponentTunnelPath = exponentUrl;
122 const outputMessage = localize(
123 "ExponentServerIsRunningOpenToSeeIt",
124 "Expo server is running. Open your Expo app at {0} to see it.",
125 this.exponentTunnelPath,
126 );
127 this.logger.info(outputMessage);
128
129 const copyButton = localize("CopyToClipboard", "Copy to clipboard");
130
131 vscode.window.showInformationMessage(outputMessage, copyButton).then(selection => {
132 if (selection === copyButton) {
133 vscode.env.clipboard.writeText(exponentUrl);
134 }
135 });
136 });
137 }
138
139 public async loginToExponentOrSkip(expoHostType?: ExpoHostType): Promise<any> {
140 if (expoHostType !== "tunnel") {
141 return;
142 }
143
144 return await this.exponentHelper.loginToExponent(
145 async (message, password) => {
146 return (
147 (await vscode.window.showInputBox({
148 placeHolder: message,
149 password: password,
150 })) || ""
151 );
152 },
153 async message => {
154 const okButton = { title: "Ok" };
155 const cancelButton = { title: "Cancel", isCloseAffordance: true };
156 const answer = await vscode.window.showInformationMessage(
157 message,
158 { modal: true },
159 okButton,
160 cancelButton,
161 );
162 if (answer === cancelButton) {
163 throw ErrorHelper.getInternalError(InternalErrorCode.UserCancelledExpoLogin);
164 }
165 return "";
166 },
167 );
168 }
169
170 public async beforeStartPackager(): Promise<void> {
171 return this.exponentHelper.configureExponentEnvironment();
172 }
173
174 public async enableJSDebuggingMode(): Promise<void> {
175 this.logger.info(
176 localize(
177 "ApplicationIsRunningOnExponentShakeDeviceForRemoteDebugging",
178 "Application is running on Expo. Please shake device and select 'Debug JS Remotely' to enable debugging.",
179 ),
180 );
181 }
182
183 public getRunArguments(): string[] {
184 return [];
185 }
186
187 private async prepareExpoTunnels(): Promise<void> {
188 try {
189 await this.exponentHelper.findOrInstallNgrokGlobally();
190 await XDL.startTunnels(this.projectPath);
191 } finally {
192 this.exponentHelper.removeNodeModulesPathFromEnvIfWasSet();
193 }
194 }
195}