microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
align-android-launch-command

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/ios/iOSPlatform.ts

470lines · modeblame

8a67e140Artem Egorov8 years ago1// 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 path from "path";
df8c800dArtem Egorov8 years ago5import * as semver from "semver";
8a67e140Artem Egorov8 years ago6
09f6024fHeniker4 years ago7import * as nls from "vscode-nls";
34472878RedMickey5 years ago8import { ChildProcess } from "../../common/node/childProcess";
9import { CommandExecutor } from "../../common/commandExecutor";
4cd25962JiglioNero4 years ago10import { MobilePlatformDeps, TargetType } from "../generalPlatform";
34472878RedMickey5 years ago11import { IIOSRunOptions, PlatformType } from "../launchArgs";
12import { OutputVerifier, PatternToFailure } from "../../common/outputVerifier";
13import { TelemetryHelper } from "../../common/telemetryHelper";
fc602bb6Yuri Skorokhodov7 years ago14import { InternalErrorCode } from "../../common/error/internalErrorCode";
7e74daf7Yuri Skorokhodov6 years ago15import { AppLauncher } from "../appLauncher";
4cd25962JiglioNero4 years ago16import { GeneralMobilePlatform } from "../generalMobilePlatform";
17import { ErrorHelper } from "../../common/error/errorHelper";
47927908RedMickey4 years ago18import { ProjectVersionHelper } from "../../common/projectVersionHelper";
09f6024fHeniker4 years ago19import { IDebuggableIOSTarget, IOSTarget, IOSTargetManager } from "./iOSTargetManager";
20import { IOSDebugModeManager } from "./iOSDebugModeManager";
21import { PlistBuddy } from "./plistBuddy";
22
34472878RedMickey5 years ago23nls.config({
24messageFormat: nls.MessageFormat.bundle,
25bundleFormat: nls.BundleFormat.standalone,
26})();
d7d405aeYuri Skorokhodov7 years ago27const localize = nls.loadMessageBundle();
8022afdfVladimir Kotikov8 years ago28
8a67e140Artem Egorov8 years ago29export class IOSPlatform extends GeneralMobilePlatform {
30public static DEFAULT_IOS_PROJECT_RELATIVE_PATH = "ios";
0a68f8dbArtem Egorov8 years ago31
47927908RedMickey4 years ago32private static readonly NEW_RN_CLI_BEHAVIOUR_VERSION = "0.60.0";
33
8a67e140Artem Egorov8 years ago34private plistBuddy = new PlistBuddy();
0db0be15Artem Egorov8 years ago35private iosProjectRoot: string;
7daed3fcArtem Egorov8 years ago36private iosDebugModeManager: IOSDebugModeManager;
37
db6fd42aRuslan Bikkinin7 years ago38private defaultConfiguration: string = "Debug";
39private configurationArgumentName: string = "--configuration";
8a67e140Artem Egorov8 years ago40
4cd25962JiglioNero4 years ago41protected target?: IOSTarget;
42
0a68f8dbArtem Egorov8 years ago43// We should add the common iOS build/run errors we find to this list
34472878RedMickey5 years ago44private static RUN_IOS_FAILURE_PATTERNS: PatternToFailure[] = [
45{
46pattern: "No devices are booted",
47errorCode: InternalErrorCode.IOSSimulatorNotLaunchable,
48},
49{
50pattern: "FBSOpenApplicationErrorDomain",
51errorCode: InternalErrorCode.IOSSimulatorNotLaunchable,
52},
53{
54pattern: "ios-deploy",
55errorCode: InternalErrorCode.IOSDeployNotFound,
56},
57];
8a67e140Artem Egorov8 years ago58
9fbbf669RedMickey4 years ago59private static readonly RUN_IOS_SUCCESS_PATTERNS = [
60"BUILD SUCCEEDED|success Successfully built the app",
61];
8a67e140Artem Egorov8 years ago62
0a68f8dbArtem Egorov8 years ago63constructor(protected runOptions: IIOSRunOptions, platformDeps: MobilePlatformDeps = {}) {
64super(runOptions, platformDeps);
8a67e140Artem Egorov8 years ago65
4cd25962JiglioNero4 years ago66this.targetManager = new IOSTargetManager();
db6fd42aRuslan Bikkinin7 years ago67this.runOptions.configuration = this.getConfiguration();
68
34472878RedMickey5 years ago69if (this.runOptions.iosRelativeProjectPath) {
70// Deprecated option
71this.logger.warning(
72localize(
73"iosRelativeProjectPathOptionIsDeprecatedUseRunArgumentsInstead",
74"'iosRelativeProjectPath' option is deprecated. Please use 'runArguments' instead.",
75),
76);
8a67e140Artem Egorov8 years ago77}
78
34472878RedMickey5 years ago79const iosProjectFolderPath = IOSPlatform.getOptFromRunArgs(
80this.runArguments,
81"--project-path",
82false,
83);
84this.iosProjectRoot = path.join(
85this.projectPath,
86iosProjectFolderPath ||
87this.runOptions.iosRelativeProjectPath ||
88IOSPlatform.DEFAULT_IOS_PROJECT_RELATIVE_PATH,
89);
116c3cb0Ruslan Bikkinin7 years ago90const schemeFromArgs = IOSPlatform.getOptFromRunArgs(this.runArguments, "--scheme", false);
34472878RedMickey5 years ago91this.iosDebugModeManager = new IOSDebugModeManager(
92this.iosProjectRoot,
93this.projectPath,
94schemeFromArgs ? schemeFromArgs : this.runOptions.scheme,
95);
4cd25962JiglioNero4 years ago96}
8a67e140Artem Egorov8 years ago97
4cd25962JiglioNero4 years ago98public async getTarget(): Promise<IOSTarget> {
99if (!this.target) {
100const targetFromRunArgs = await this.getTargetFromRunArgs();
101if (targetFromRunArgs) {
102this.target = targetFromRunArgs;
103} else {
09f6024fHeniker4 years ago104const targets =
105(await this.targetManager.getTargetList()) as IDebuggableIOSTarget[];
4cd25962JiglioNero4 years ago106const targetsBySpecifiedType = targets.filter(target => {
107switch (this.runOptions.target) {
108case TargetType.Simulator:
109return target.isVirtualTarget;
110case TargetType.Device:
111return !target.isVirtualTarget;
112case undefined:
113case "":
114return true;
115default:
116return (
117target.id === this.runOptions.target ||
118target.name === this.runOptions.target
119);
120}
121});
122if (targetsBySpecifiedType.length) {
123this.target = IOSTarget.fromInterface(targetsBySpecifiedType[0]);
124} else if (targets.length) {
125this.logger.warning(
126localize(
127"ThereIsNoTargetWithSpecifiedTargetType",
128"There is no any target with specified target type '{0}'. Continue with any target.",
129this.runOptions.target,
130),
131);
132this.target = IOSTarget.fromInterface(targets[0]);
133} else {
134throw ErrorHelper.getInternalError(
135InternalErrorCode.IOSThereIsNoAnyDebuggableTarget,
136);
137}
138}
8022afdfVladimir Kotikov8 years ago139}
4cd25962JiglioNero4 years ago140return this.target;
141}
0db0be15Artem Egorov8 years ago142
4cd25962JiglioNero4 years ago143public async showDevMenu(appLauncher: AppLauncher): Promise<void> {
144const worker = appLauncher.getAppWorker();
145if (worker) {
146worker.showDevMenuCommand();
8a67e140Artem Egorov8 years ago147}
148}
149
4cd25962JiglioNero4 years ago150public async reloadApp(appLauncher: AppLauncher): Promise<void> {
151const worker = appLauncher.getAppWorker();
152if (worker) {
153worker.reloadAppCommand();
119d7878JiglioNero5 years ago154}
155}
156
0d77292aJiglioNero4 years ago157public async runApp(): Promise<void> {
e7a2c40dRedMickey4 years ago158let extProps: any = {
031832ffArtem Egorov8 years ago159platform: {
259c018fYuri Skorokhodov5 years ago160value: PlatformType.iOS,
031832ffArtem Egorov8 years ago161isPii: false,
162},
163};
164
e7a2c40dRedMickey4 years ago165if (this.runOptions.isDirect) {
166extProps.isDirect = {
167value: true,
168isPii: false,
169};
170this.projectObserver?.updateRNIosHermesProjectState(true);
171}
172
34472878RedMickey5 years ago173extProps = TelemetryHelper.addPlatformPropertiesToTelemetryProperties(
174this.runOptions,
175this.runOptions.reactNativeVersions,
176extProps,
177);
ba953e9fRedMickey6 years ago178
0d77292aJiglioNero4 years ago179await TelemetryHelper.generate("iOSPlatform.runApp", extProps, async () => {
031832ffArtem Egorov8 years ago180// Compile, deploy, and launch the app on either a simulator or a device
34472878RedMickey5 years ago181const env = GeneralMobilePlatform.getEnvArgument(
182process.env,
183this.runOptions.env,
184this.runOptions.envFile,
185);
186
187if (
188!semver.valid(
189this.runOptions.reactNativeVersions.reactNativeVersion,
09f6024fHeniker4 years ago190) /* Custom RN implementations should support this flag*/ ||
34472878RedMickey5 years ago191semver.gte(
192this.runOptions.reactNativeVersions.reactNativeVersion,
193IOSPlatform.NO_PACKAGER_VERSION,
47927908RedMickey4 years ago194) ||
195ProjectVersionHelper.isCanaryVersion(
196this.runOptions.reactNativeVersions.reactNativeVersion,
34472878RedMickey5 years ago197)
198) {
7fa90b3bRedMickey6 years ago199this.runArguments.push("--no-packager");
200}
201// Since @react-native-community/cli@2.1.0 build output are hidden by default
202// we are using `--verbose` to show it as it contains `BUILD SUCCESSFUL` and other patterns
47927908RedMickey4 years ago203if (
204semver.gte(
205this.runOptions.reactNativeVersions.reactNativeVersion,
206IOSPlatform.NEW_RN_CLI_BEHAVIOUR_VERSION,
207) ||
208ProjectVersionHelper.isCanaryVersion(
209this.runOptions.reactNativeVersions.reactNativeVersion,
210)
211) {
7fa90b3bRedMickey6 years ago212this.runArguments.push("--verbose");
213}
34472878RedMickey5 years ago214const runIosSpawn = new CommandExecutor(
4dfb1c4cetatanova5 years ago215this.runOptions.nodeModulesRoot,
34472878RedMickey5 years ago216this.projectPath,
217this.logger,
218).spawnReactCommand("run-ios", this.runArguments, { env });
0d77292aJiglioNero4 years ago219await new OutputVerifier(
ce5e88eeYuri Skorokhodov5 years ago220() =>
34472878RedMickey5 years ago221this.generateSuccessPatterns(
222this.runOptions.reactNativeVersions.reactNativeVersion,
223),
224() => Promise.resolve(IOSPlatform.RUN_IOS_FAILURE_PATTERNS),
225PlatformType.iOS,
226).process(runIosSpawn);
80dcd561ConnorQi013 months ago227
1a12db81ConnorQi3 months ago228// Save target info for status indicator
80dcd561ConnorQi013 months ago229if (!this.target) {
1a12db81ConnorQi3 months ago230const target = await this.getTarget();
231if (target && target.name) {
232this.target = new IOSTarget(
233target.isOnline,
234target.isVirtualTarget,
235target.id,
236target.name,
237target.system,
238);
239}
80dcd561ConnorQi013 months ago240}
031832ffArtem Egorov8 years ago241});
8a67e140Artem Egorov8 years ago242}
243
0d77292aJiglioNero4 years ago244public async enableJSDebuggingMode(): Promise<void> {
8a67e140Artem Egorov8 years ago245// Configure the app for debugging
4cd25962JiglioNero4 years ago246if (!(await this.getTarget()).isVirtualTarget) {
8a67e140Artem Egorov8 years ago247// Note that currently we cannot automatically switch the device into debug mode.
34472878RedMickey5 years ago248this.logger.info(
249"Application is running on a device, please shake device and select 'Debug JS Remotely' to enable debugging.",
250);
0d77292aJiglioNero4 years ago251return;
8a67e140Artem Egorov8 years ago252}
253
254// Wait until the configuration file exists, and check to see if debugging is enabled
0d77292aJiglioNero4 years ago255const [debugModeEnabled, bundleId] = await Promise.all<boolean | string>([
1c2424f4RedMickey5 years ago256this.iosDebugModeManager.getAppRemoteDebuggingSetting(
34472878RedMickey5 years ago257this.runOptions.configuration,
258this.runOptions.productName,
259),
8a67e140Artem Egorov8 years ago260this.getBundleId(),
0d77292aJiglioNero4 years ago261]);
262if (debugModeEnabled) {
263return;
264}
265// Debugging must still be enabled
266// We enable debugging by writing to a plist file that backs a NSUserDefaults object,
267// but that file is written to by the app on occasion. To avoid races, we shut the app
268// down before writing to the file.
269const childProcess = new ChildProcess();
270const output = await childProcess.execToString("xcrun simctl spawn booted launchctl list");
271// Try to find an entry that looks like UIKitApplication:com.example.myApp[0x4f37]
09f6024fHeniker4 years ago272const regex = new RegExp(`(\\S+${String(bundleId)}\\S+)`);
0d77292aJiglioNero4 years ago273const match = regex.exec(output);
274// If we don't find a match, the app must not be running and so we do not need to close it
275if (match) {
276await childProcess.exec(`xcrun simctl spawn booted launchctl stop ${match[1]}`);
277}
278// Write to the settings file while the app is not running to avoid races
279await this.iosDebugModeManager.setAppRemoteDebuggingSetting(
09f6024fHeniker4 years ago280/* enable=*/ true,
0d77292aJiglioNero4 years ago281this.runOptions.configuration,
282this.runOptions.productName,
283);
284// Relaunch the app
285return await this.runApp();
8a67e140Artem Egorov8 years ago286}
287
0d77292aJiglioNero4 years ago288public async disableJSDebuggingMode(): Promise<void> {
4cd25962JiglioNero4 years ago289if (!(await this.getTarget()).isVirtualTarget) {
0d77292aJiglioNero4 years ago290return;
c73f53cbJiglioNero5 years ago291}
1c2424f4RedMickey5 years ago292return this.iosDebugModeManager.setAppRemoteDebuggingSetting(
09f6024fHeniker4 years ago293/* enable=*/ false,
34472878RedMickey5 years ago294this.runOptions.configuration,
295this.runOptions.productName,
296);
0a68f8dbArtem Egorov8 years ago297}
298
ce5e88eeYuri Skorokhodov5 years ago299public prewarmBundleCache(): Promise<void> {
259c018fYuri Skorokhodov5 years ago300return this.packager.prewarmBundleCache(PlatformType.iOS);
8a67e140Artem Egorov8 years ago301}
302
cbc7ac5bArtem Egorov7 years ago303public getRunArguments(): string[] {
8a67e140Artem Egorov8 years ago304let runArguments: string[] = [];
0db0be15Artem Egorov8 years ago305
306if (this.runOptions.runArguments && this.runOptions.runArguments.length > 0) {
b57ea017Artem Egorov8 years ago307runArguments = this.runOptions.runArguments;
116c3cb0Ruslan Bikkinin7 years ago308if (this.runOptions.scheme) {
34472878RedMickey5 years ago309const schemeFromArgs = IOSPlatform.getOptFromRunArgs(
310runArguments,
311"--scheme",
312false,
313);
116c3cb0Ruslan Bikkinin7 years ago314if (!schemeFromArgs) {
315runArguments.push("--scheme", this.runOptions.scheme);
316} else {
34472878RedMickey5 years ago317this.logger.warning(
318localize(
319"iosSchemeParameterAlreadySetInRunArguments",
320"'--scheme' is set as 'runArguments' configuration parameter value, 'scheme' configuration parameter value will be omitted",
321),
322);
116c3cb0Ruslan Bikkinin7 years ago323}
324}
b57ea017Artem Egorov8 years ago325} else {
326if (this.runOptions.target) {
de838bbfJiglioNero6 years ago327runArguments.push(...this.handleTargetArg(this.runOptions.target));
b57ea017Artem Egorov8 years ago328}
8abbd163Artem Egorov8 years ago329
b57ea017Artem Egorov8 years ago330if (this.runOptions.iosRelativeProjectPath) {
331runArguments.push("--project-path", this.runOptions.iosRelativeProjectPath);
8022afdfVladimir Kotikov8 years ago332}
8a67e140Artem Egorov8 years ago333
b57ea017Artem Egorov8 years ago334// provide any defined scheme
335if (this.runOptions.scheme) {
336runArguments.push("--scheme", this.runOptions.scheme);
337}
8a67e140Artem Egorov8 years ago338}
339
340return runArguments;
341}
342
4cd25962JiglioNero4 years ago343public async getTargetFromRunArgs(): Promise<IOSTarget | undefined> {
344if (this.runOptions.runArguments && this.runOptions.runArguments.length > 0) {
c76b733bJiglioNero4 years ago345const targets = (await this.targetManager.getTargetList()) as IDebuggableIOSTarget[];
346
4cd25962JiglioNero4 years ago347const udid = GeneralMobilePlatform.getOptFromRunArgs(
348this.runOptions.runArguments,
349"--udid",
350);
351if (udid) {
352const target = targets.find(target => target.id === udid);
353if (target) {
354return IOSTarget.fromInterface(target);
355}
09f6024fHeniker4 years ago356this.logger.warning(
357localize(
358"ThereIsNoIosTargetWithSuchUdid",
359"There is no iOS target with such UDID: {0}",
360udid,
361),
362);
4cd25962JiglioNero4 years ago363}
364
365const device = GeneralMobilePlatform.getOptFromRunArgs(
366this.runOptions.runArguments,
367"--device",
368);
369if (device) {
370const target = targets.find(
c76b733bJiglioNero4 years ago371target => !target.isVirtualTarget && target.name === device,
4cd25962JiglioNero4 years ago372);
373if (target) {
374return IOSTarget.fromInterface(target);
375}
09f6024fHeniker4 years ago376this.logger.warning(
377localize(
378"ThereIsNoIosDeviceWithSuchName",
379"There is no iOS device with such name: {0}",
380device,
381),
382);
4cd25962JiglioNero4 years ago383}
384
385const simulator = GeneralMobilePlatform.getOptFromRunArgs(
386this.runOptions.runArguments,
387"--simulator",
388);
389if (simulator) {
390const target = targets.find(
c76b733bJiglioNero4 years ago391target => target.isVirtualTarget && target.name === simulator,
4cd25962JiglioNero4 years ago392);
393if (target) {
394return IOSTarget.fromInterface(target);
395}
09f6024fHeniker4 years ago396this.logger.warning(
397localize(
398"ThereIsNoIosSimulatorWithSuchName",
399"There is no iOS simulator with such name: {0}",
400simulator,
401),
402);
4cd25962JiglioNero4 years ago403}
404}
405
406return undefined;
407}
408
de838bbfJiglioNero6 years ago409private handleTargetArg(target: string): string[] {
09f6024fHeniker4 years ago410return target === TargetType.Device || target === TargetType.Simulator
411? [`--${target}`]
412: ["--udid", target];
de838bbfJiglioNero6 years ago413}
414
0d77292aJiglioNero4 years ago415private async generateSuccessPatterns(version: string): Promise<string[]> {
3021756bYuri Skorokhodov6 years ago416// Clone RUN_IOS_SUCCESS_PATTERNS to avoid its runtime mutation
09f6024fHeniker4 years ago417const successPatterns = [...IOSPlatform.RUN_IOS_SUCCESS_PATTERNS];
4cd25962JiglioNero4 years ago418if (!(await this.getTarget()).isVirtualTarget) {
47927908RedMickey4 years ago419if (
420semver.gte(version, IOSPlatform.NEW_RN_CLI_BEHAVIOUR_VERSION) ||
421ProjectVersionHelper.isCanaryVersion(version)
422) {
3021756bYuri Skorokhodov6 years ago423successPatterns.push("success Installed the app on the device");
424} else {
425successPatterns.push("INSTALLATION SUCCEEDED");
426}
0d77292aJiglioNero4 years ago427return successPatterns;
09f6024fHeniker4 years ago428}
429const bundleId = await this.getBundleId();
47927908RedMickey4 years ago430if (
431semver.gte(version, IOSPlatform.NEW_RN_CLI_BEHAVIOUR_VERSION) ||
432ProjectVersionHelper.isCanaryVersion(version)
433) {
cf6a88fclexie0112 years ago434successPatterns.push(`Launching "${bundleId}"\nsuccess Successfully launched the app`);
3021756bYuri Skorokhodov6 years ago435} else {
09f6024fHeniker4 years ago436successPatterns.push(`Launching ${bundleId}\n${bundleId}: `);
3021756bYuri Skorokhodov6 years ago437}
09f6024fHeniker4 years ago438return successPatterns;
8a67e140Artem Egorov8 years ago439}
440
db6fd42aRuslan Bikkinin7 years ago441private getConfiguration(): string {
34472878RedMickey5 years ago442return (
443IOSPlatform.getOptFromRunArgs(this.runArguments, this.configurationArgumentName) ||
444this.defaultConfiguration
445);
db6fd42aRuslan Bikkinin7 years ago446}
447
ce5e88eeYuri Skorokhodov5 years ago448private getBundleId(): Promise<string> {
116c3cb0Ruslan Bikkinin7 years ago449let scheme = this.runOptions.scheme;
450if (!scheme) {
34472878RedMickey5 years ago451const schemeFromArgs = IOSPlatform.getOptFromRunArgs(
452this.runArguments,
453"--scheme",
454false,
455);
116c3cb0Ruslan Bikkinin7 years ago456if (schemeFromArgs) {
457scheme = schemeFromArgs;
458}
459}
34472878RedMickey5 years ago460return this.plistBuddy.getBundleId(
461this.iosProjectRoot,
462this.projectPath,
1c2424f4RedMickey5 years ago463PlatformType.iOS,
34472878RedMickey5 years ago464true,
465this.runOptions.configuration,
466this.runOptions.productName,
467scheme,
468);
8a67e140Artem Egorov8 years ago469}
470}