microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
smoke-actionbar-timeout-assertion

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/ios/iOSPlatform.ts

454lines · 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 ago69const iosProjectFolderPath = IOSPlatform.getOptFromRunArgs(
70this.runArguments,
71"--project-path",
72false,
73);
74this.iosProjectRoot = path.join(
75this.projectPath,
14a3206cConnorQi011 months ago76iosProjectFolderPath || IOSPlatform.DEFAULT_IOS_PROJECT_RELATIVE_PATH,
34472878RedMickey5 years ago77);
116c3cb0Ruslan Bikkinin7 years ago78const schemeFromArgs = IOSPlatform.getOptFromRunArgs(this.runArguments, "--scheme", false);
34472878RedMickey5 years ago79this.iosDebugModeManager = new IOSDebugModeManager(
80this.iosProjectRoot,
81this.projectPath,
82schemeFromArgs ? schemeFromArgs : this.runOptions.scheme,
83);
4cd25962JiglioNero4 years ago84}
8a67e140Artem Egorov8 years ago85
4cd25962JiglioNero4 years ago86public async getTarget(): Promise<IOSTarget> {
87if (!this.target) {
88const targetFromRunArgs = await this.getTargetFromRunArgs();
89if (targetFromRunArgs) {
90this.target = targetFromRunArgs;
91} else {
09f6024fHeniker4 years ago92const targets =
93(await this.targetManager.getTargetList()) as IDebuggableIOSTarget[];
4cd25962JiglioNero4 years ago94const targetsBySpecifiedType = targets.filter(target => {
95switch (this.runOptions.target) {
96case TargetType.Simulator:
97return target.isVirtualTarget;
98case TargetType.Device:
99return !target.isVirtualTarget;
100case undefined:
101case "":
102return true;
103default:
104return (
105target.id === this.runOptions.target ||
106target.name === this.runOptions.target
107);
108}
109});
110if (targetsBySpecifiedType.length) {
111this.target = IOSTarget.fromInterface(targetsBySpecifiedType[0]);
112} else if (targets.length) {
113this.logger.warning(
114localize(
115"ThereIsNoTargetWithSpecifiedTargetType",
116"There is no any target with specified target type '{0}'. Continue with any target.",
117this.runOptions.target,
118),
119);
120this.target = IOSTarget.fromInterface(targets[0]);
121} else {
122throw ErrorHelper.getInternalError(
123InternalErrorCode.IOSThereIsNoAnyDebuggableTarget,
124);
125}
126}
8022afdfVladimir Kotikov8 years ago127}
4cd25962JiglioNero4 years ago128return this.target;
129}
0db0be15Artem Egorov8 years ago130
4cd25962JiglioNero4 years ago131public async showDevMenu(appLauncher: AppLauncher): Promise<void> {
132const worker = appLauncher.getAppWorker();
133if (worker) {
134worker.showDevMenuCommand();
8a67e140Artem Egorov8 years ago135}
136}
137
4cd25962JiglioNero4 years ago138public async reloadApp(appLauncher: AppLauncher): Promise<void> {
139const worker = appLauncher.getAppWorker();
140if (worker) {
141worker.reloadAppCommand();
119d7878JiglioNero5 years ago142}
143}
144
0d77292aJiglioNero4 years ago145public async runApp(): Promise<void> {
e7a2c40dRedMickey4 years ago146let extProps: any = {
031832ffArtem Egorov8 years ago147platform: {
259c018fYuri Skorokhodov5 years ago148value: PlatformType.iOS,
031832ffArtem Egorov8 years ago149isPii: false,
150},
151};
152
e7a2c40dRedMickey4 years ago153if (this.runOptions.isDirect) {
154extProps.isDirect = {
155value: true,
156isPii: false,
157};
158this.projectObserver?.updateRNIosHermesProjectState(true);
159}
160
34472878RedMickey5 years ago161extProps = TelemetryHelper.addPlatformPropertiesToTelemetryProperties(
162this.runOptions,
163this.runOptions.reactNativeVersions,
164extProps,
165);
ba953e9fRedMickey6 years ago166
0d77292aJiglioNero4 years ago167await TelemetryHelper.generate("iOSPlatform.runApp", extProps, async () => {
031832ffArtem Egorov8 years ago168// Compile, deploy, and launch the app on either a simulator or a device
34472878RedMickey5 years ago169const env = GeneralMobilePlatform.getEnvArgument(
170process.env,
171this.runOptions.env,
172this.runOptions.envFile,
173);
174
175if (
176!semver.valid(
177this.runOptions.reactNativeVersions.reactNativeVersion,
09f6024fHeniker4 years ago178) /* Custom RN implementations should support this flag*/ ||
34472878RedMickey5 years ago179semver.gte(
180this.runOptions.reactNativeVersions.reactNativeVersion,
181IOSPlatform.NO_PACKAGER_VERSION,
47927908RedMickey4 years ago182) ||
183ProjectVersionHelper.isCanaryVersion(
184this.runOptions.reactNativeVersions.reactNativeVersion,
34472878RedMickey5 years ago185)
186) {
7fa90b3bRedMickey6 years ago187this.runArguments.push("--no-packager");
188}
189// Since @react-native-community/cli@2.1.0 build output are hidden by default
190// we are using `--verbose` to show it as it contains `BUILD SUCCESSFUL` and other patterns
47927908RedMickey4 years ago191if (
192semver.gte(
193this.runOptions.reactNativeVersions.reactNativeVersion,
194IOSPlatform.NEW_RN_CLI_BEHAVIOUR_VERSION,
195) ||
196ProjectVersionHelper.isCanaryVersion(
197this.runOptions.reactNativeVersions.reactNativeVersion,
198)
199) {
7fa90b3bRedMickey6 years ago200this.runArguments.push("--verbose");
201}
34472878RedMickey5 years ago202const runIosSpawn = new CommandExecutor(
4dfb1c4cetatanova5 years ago203this.runOptions.nodeModulesRoot,
34472878RedMickey5 years ago204this.projectPath,
205this.logger,
206).spawnReactCommand("run-ios", this.runArguments, { env });
0d77292aJiglioNero4 years ago207await new OutputVerifier(
ce5e88eeYuri Skorokhodov5 years ago208() =>
34472878RedMickey5 years ago209this.generateSuccessPatterns(
210this.runOptions.reactNativeVersions.reactNativeVersion,
211),
212() => Promise.resolve(IOSPlatform.RUN_IOS_FAILURE_PATTERNS),
213PlatformType.iOS,
214).process(runIosSpawn);
80dcd561ConnorQi013 months ago215
1a12db81ConnorQi3 months ago216// Save target info for status indicator
80dcd561ConnorQi013 months ago217if (!this.target) {
1a12db81ConnorQi3 months ago218const target = await this.getTarget();
219if (target && target.name) {
220this.target = new IOSTarget(
221target.isOnline,
222target.isVirtualTarget,
223target.id,
224target.name,
225target.system,
226);
227}
80dcd561ConnorQi013 months ago228}
031832ffArtem Egorov8 years ago229});
8a67e140Artem Egorov8 years ago230}
231
0d77292aJiglioNero4 years ago232public async enableJSDebuggingMode(): Promise<void> {
8a67e140Artem Egorov8 years ago233// Configure the app for debugging
4cd25962JiglioNero4 years ago234if (!(await this.getTarget()).isVirtualTarget) {
8a67e140Artem Egorov8 years ago235// Note that currently we cannot automatically switch the device into debug mode.
34472878RedMickey5 years ago236this.logger.info(
237"Application is running on a device, please shake device and select 'Debug JS Remotely' to enable debugging.",
238);
0d77292aJiglioNero4 years ago239return;
8a67e140Artem Egorov8 years ago240}
241
242// Wait until the configuration file exists, and check to see if debugging is enabled
0d77292aJiglioNero4 years ago243const [debugModeEnabled, bundleId] = await Promise.all<boolean | string>([
1c2424f4RedMickey5 years ago244this.iosDebugModeManager.getAppRemoteDebuggingSetting(
34472878RedMickey5 years ago245this.runOptions.configuration,
246this.runOptions.productName,
247),
8a67e140Artem Egorov8 years ago248this.getBundleId(),
0d77292aJiglioNero4 years ago249]);
250if (debugModeEnabled) {
251return;
252}
253// Debugging must still be enabled
254// We enable debugging by writing to a plist file that backs a NSUserDefaults object,
255// but that file is written to by the app on occasion. To avoid races, we shut the app
256// down before writing to the file.
257const childProcess = new ChildProcess();
258const output = await childProcess.execToString("xcrun simctl spawn booted launchctl list");
259// Try to find an entry that looks like UIKitApplication:com.example.myApp[0x4f37]
09f6024fHeniker4 years ago260const regex = new RegExp(`(\\S+${String(bundleId)}\\S+)`);
0d77292aJiglioNero4 years ago261const match = regex.exec(output);
262// If we don't find a match, the app must not be running and so we do not need to close it
263if (match) {
264await childProcess.exec(`xcrun simctl spawn booted launchctl stop ${match[1]}`);
265}
266// Write to the settings file while the app is not running to avoid races
267await this.iosDebugModeManager.setAppRemoteDebuggingSetting(
09f6024fHeniker4 years ago268/* enable=*/ true,
0d77292aJiglioNero4 years ago269this.runOptions.configuration,
270this.runOptions.productName,
271);
272// Relaunch the app
273return await this.runApp();
8a67e140Artem Egorov8 years ago274}
275
0d77292aJiglioNero4 years ago276public async disableJSDebuggingMode(): Promise<void> {
4cd25962JiglioNero4 years ago277if (!(await this.getTarget()).isVirtualTarget) {
0d77292aJiglioNero4 years ago278return;
c73f53cbJiglioNero5 years ago279}
1c2424f4RedMickey5 years ago280return this.iosDebugModeManager.setAppRemoteDebuggingSetting(
09f6024fHeniker4 years ago281/* enable=*/ false,
34472878RedMickey5 years ago282this.runOptions.configuration,
283this.runOptions.productName,
284);
0a68f8dbArtem Egorov8 years ago285}
286
ce5e88eeYuri Skorokhodov5 years ago287public prewarmBundleCache(): Promise<void> {
259c018fYuri Skorokhodov5 years ago288return this.packager.prewarmBundleCache(PlatformType.iOS);
8a67e140Artem Egorov8 years ago289}
290
cbc7ac5bArtem Egorov7 years ago291public getRunArguments(): string[] {
8a67e140Artem Egorov8 years ago292let runArguments: string[] = [];
0db0be15Artem Egorov8 years ago293
294if (this.runOptions.runArguments && this.runOptions.runArguments.length > 0) {
b57ea017Artem Egorov8 years ago295runArguments = this.runOptions.runArguments;
116c3cb0Ruslan Bikkinin7 years ago296if (this.runOptions.scheme) {
34472878RedMickey5 years ago297const schemeFromArgs = IOSPlatform.getOptFromRunArgs(
298runArguments,
299"--scheme",
300false,
301);
116c3cb0Ruslan Bikkinin7 years ago302if (!schemeFromArgs) {
303runArguments.push("--scheme", this.runOptions.scheme);
304} else {
34472878RedMickey5 years ago305this.logger.warning(
306localize(
307"iosSchemeParameterAlreadySetInRunArguments",
308"'--scheme' is set as 'runArguments' configuration parameter value, 'scheme' configuration parameter value will be omitted",
309),
310);
116c3cb0Ruslan Bikkinin7 years ago311}
312}
b57ea017Artem Egorov8 years ago313} else {
314if (this.runOptions.target) {
de838bbfJiglioNero6 years ago315runArguments.push(...this.handleTargetArg(this.runOptions.target));
b57ea017Artem Egorov8 years ago316}
8abbd163Artem Egorov8 years ago317
b57ea017Artem Egorov8 years ago318// provide any defined scheme
319if (this.runOptions.scheme) {
320runArguments.push("--scheme", this.runOptions.scheme);
321}
8a67e140Artem Egorov8 years ago322}
323
324return runArguments;
325}
326
4cd25962JiglioNero4 years ago327public async getTargetFromRunArgs(): Promise<IOSTarget | undefined> {
328if (this.runOptions.runArguments && this.runOptions.runArguments.length > 0) {
c76b733bJiglioNero4 years ago329const targets = (await this.targetManager.getTargetList()) as IDebuggableIOSTarget[];
330
4cd25962JiglioNero4 years ago331const udid = GeneralMobilePlatform.getOptFromRunArgs(
332this.runOptions.runArguments,
333"--udid",
334);
335if (udid) {
336const target = targets.find(target => target.id === udid);
337if (target) {
338return IOSTarget.fromInterface(target);
339}
09f6024fHeniker4 years ago340this.logger.warning(
341localize(
342"ThereIsNoIosTargetWithSuchUdid",
343"There is no iOS target with such UDID: {0}",
344udid,
345),
346);
4cd25962JiglioNero4 years ago347}
348
349const device = GeneralMobilePlatform.getOptFromRunArgs(
350this.runOptions.runArguments,
351"--device",
352);
353if (device) {
354const target = targets.find(
c76b733bJiglioNero4 years ago355target => !target.isVirtualTarget && target.name === device,
4cd25962JiglioNero4 years ago356);
357if (target) {
358return IOSTarget.fromInterface(target);
359}
09f6024fHeniker4 years ago360this.logger.warning(
361localize(
362"ThereIsNoIosDeviceWithSuchName",
363"There is no iOS device with such name: {0}",
364device,
365),
366);
4cd25962JiglioNero4 years ago367}
368
369const simulator = GeneralMobilePlatform.getOptFromRunArgs(
370this.runOptions.runArguments,
371"--simulator",
372);
373if (simulator) {
374const target = targets.find(
c76b733bJiglioNero4 years ago375target => target.isVirtualTarget && target.name === simulator,
4cd25962JiglioNero4 years ago376);
377if (target) {
378return IOSTarget.fromInterface(target);
379}
09f6024fHeniker4 years ago380this.logger.warning(
381localize(
382"ThereIsNoIosSimulatorWithSuchName",
383"There is no iOS simulator with such name: {0}",
384simulator,
385),
386);
4cd25962JiglioNero4 years ago387}
388}
389
390return undefined;
391}
392
de838bbfJiglioNero6 years ago393private handleTargetArg(target: string): string[] {
09f6024fHeniker4 years ago394return target === TargetType.Device || target === TargetType.Simulator
395? [`--${target}`]
396: ["--udid", target];
de838bbfJiglioNero6 years ago397}
398
0d77292aJiglioNero4 years ago399private async generateSuccessPatterns(version: string): Promise<string[]> {
3021756bYuri Skorokhodov7 years ago400// Clone RUN_IOS_SUCCESS_PATTERNS to avoid its runtime mutation
09f6024fHeniker4 years ago401const successPatterns = [...IOSPlatform.RUN_IOS_SUCCESS_PATTERNS];
4cd25962JiglioNero4 years ago402if (!(await this.getTarget()).isVirtualTarget) {
47927908RedMickey4 years ago403if (
404semver.gte(version, IOSPlatform.NEW_RN_CLI_BEHAVIOUR_VERSION) ||
405ProjectVersionHelper.isCanaryVersion(version)
406) {
3021756bYuri Skorokhodov7 years ago407successPatterns.push("success Installed the app on the device");
408} else {
409successPatterns.push("INSTALLATION SUCCEEDED");
410}
0d77292aJiglioNero4 years ago411return successPatterns;
09f6024fHeniker4 years ago412}
413const bundleId = await this.getBundleId();
47927908RedMickey4 years ago414if (
415semver.gte(version, IOSPlatform.NEW_RN_CLI_BEHAVIOUR_VERSION) ||
416ProjectVersionHelper.isCanaryVersion(version)
417) {
cf6a88fclexie0112 years ago418successPatterns.push(`Launching "${bundleId}"\nsuccess Successfully launched the app`);
3021756bYuri Skorokhodov7 years ago419} else {
09f6024fHeniker4 years ago420successPatterns.push(`Launching ${bundleId}\n${bundleId}: `);
3021756bYuri Skorokhodov7 years ago421}
09f6024fHeniker4 years ago422return successPatterns;
8a67e140Artem Egorov8 years ago423}
424
db6fd42aRuslan Bikkinin7 years ago425private getConfiguration(): string {
34472878RedMickey5 years ago426return (
427IOSPlatform.getOptFromRunArgs(this.runArguments, this.configurationArgumentName) ||
428this.defaultConfiguration
429);
db6fd42aRuslan Bikkinin7 years ago430}
431
ce5e88eeYuri Skorokhodov5 years ago432private getBundleId(): Promise<string> {
116c3cb0Ruslan Bikkinin7 years ago433let scheme = this.runOptions.scheme;
434if (!scheme) {
34472878RedMickey5 years ago435const schemeFromArgs = IOSPlatform.getOptFromRunArgs(
436this.runArguments,
437"--scheme",
438false,
439);
116c3cb0Ruslan Bikkinin7 years ago440if (schemeFromArgs) {
441scheme = schemeFromArgs;
442}
443}
34472878RedMickey5 years ago444return this.plistBuddy.getBundleId(
445this.iosProjectRoot,
446this.projectPath,
1c2424f4RedMickey5 years ago447PlatformType.iOS,
34472878RedMickey5 years ago448true,
449this.runOptions.configuration,
450this.runOptions.productName,
451scheme,
452);
8a67e140Artem Egorov8 years ago453}
454}