microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.11.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/ios/iOSPlatform.ts

456lines · 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);
031832ffArtem Egorov8 years ago227});
8a67e140Artem Egorov8 years ago228}
229
0d77292aJiglioNero4 years ago230public async enableJSDebuggingMode(): Promise<void> {
8a67e140Artem Egorov8 years ago231// Configure the app for debugging
4cd25962JiglioNero4 years ago232if (!(await this.getTarget()).isVirtualTarget) {
8a67e140Artem Egorov8 years ago233// Note that currently we cannot automatically switch the device into debug mode.
34472878RedMickey5 years ago234this.logger.info(
235"Application is running on a device, please shake device and select 'Debug JS Remotely' to enable debugging.",
236);
0d77292aJiglioNero4 years ago237return;
8a67e140Artem Egorov8 years ago238}
239
240// Wait until the configuration file exists, and check to see if debugging is enabled
0d77292aJiglioNero4 years ago241const [debugModeEnabled, bundleId] = await Promise.all<boolean | string>([
1c2424f4RedMickey5 years ago242this.iosDebugModeManager.getAppRemoteDebuggingSetting(
34472878RedMickey5 years ago243this.runOptions.configuration,
244this.runOptions.productName,
245),
8a67e140Artem Egorov8 years ago246this.getBundleId(),
0d77292aJiglioNero4 years ago247]);
248if (debugModeEnabled) {
249return;
250}
251// Debugging must still be enabled
252// We enable debugging by writing to a plist file that backs a NSUserDefaults object,
253// but that file is written to by the app on occasion. To avoid races, we shut the app
254// down before writing to the file.
255const childProcess = new ChildProcess();
256const output = await childProcess.execToString("xcrun simctl spawn booted launchctl list");
257// Try to find an entry that looks like UIKitApplication:com.example.myApp[0x4f37]
09f6024fHeniker4 years ago258const regex = new RegExp(`(\\S+${String(bundleId)}\\S+)`);
0d77292aJiglioNero4 years ago259const match = regex.exec(output);
260// If we don't find a match, the app must not be running and so we do not need to close it
261if (match) {
262await childProcess.exec(`xcrun simctl spawn booted launchctl stop ${match[1]}`);
263}
264// Write to the settings file while the app is not running to avoid races
265await this.iosDebugModeManager.setAppRemoteDebuggingSetting(
09f6024fHeniker4 years ago266/* enable=*/ true,
0d77292aJiglioNero4 years ago267this.runOptions.configuration,
268this.runOptions.productName,
269);
270// Relaunch the app
271return await this.runApp();
8a67e140Artem Egorov8 years ago272}
273
0d77292aJiglioNero4 years ago274public async disableJSDebuggingMode(): Promise<void> {
4cd25962JiglioNero4 years ago275if (!(await this.getTarget()).isVirtualTarget) {
0d77292aJiglioNero4 years ago276return;
c73f53cbJiglioNero5 years ago277}
1c2424f4RedMickey5 years ago278return this.iosDebugModeManager.setAppRemoteDebuggingSetting(
09f6024fHeniker4 years ago279/* enable=*/ false,
34472878RedMickey5 years ago280this.runOptions.configuration,
281this.runOptions.productName,
282);
0a68f8dbArtem Egorov8 years ago283}
284
ce5e88eeYuri Skorokhodov5 years ago285public prewarmBundleCache(): Promise<void> {
259c018fYuri Skorokhodov5 years ago286return this.packager.prewarmBundleCache(PlatformType.iOS);
8a67e140Artem Egorov8 years ago287}
288
cbc7ac5bArtem Egorov7 years ago289public getRunArguments(): string[] {
8a67e140Artem Egorov8 years ago290let runArguments: string[] = [];
0db0be15Artem Egorov8 years ago291
292if (this.runOptions.runArguments && this.runOptions.runArguments.length > 0) {
b57ea017Artem Egorov8 years ago293runArguments = this.runOptions.runArguments;
116c3cb0Ruslan Bikkinin7 years ago294if (this.runOptions.scheme) {
34472878RedMickey5 years ago295const schemeFromArgs = IOSPlatform.getOptFromRunArgs(
296runArguments,
297"--scheme",
298false,
299);
116c3cb0Ruslan Bikkinin7 years ago300if (!schemeFromArgs) {
301runArguments.push("--scheme", this.runOptions.scheme);
302} else {
34472878RedMickey5 years ago303this.logger.warning(
304localize(
305"iosSchemeParameterAlreadySetInRunArguments",
306"'--scheme' is set as 'runArguments' configuration parameter value, 'scheme' configuration parameter value will be omitted",
307),
308);
116c3cb0Ruslan Bikkinin7 years ago309}
310}
b57ea017Artem Egorov8 years ago311} else {
312if (this.runOptions.target) {
de838bbfJiglioNero6 years ago313runArguments.push(...this.handleTargetArg(this.runOptions.target));
b57ea017Artem Egorov8 years ago314}
8abbd163Artem Egorov8 years ago315
b57ea017Artem Egorov8 years ago316if (this.runOptions.iosRelativeProjectPath) {
317runArguments.push("--project-path", this.runOptions.iosRelativeProjectPath);
8022afdfVladimir Kotikov8 years ago318}
8a67e140Artem Egorov8 years ago319
b57ea017Artem Egorov8 years ago320// provide any defined scheme
321if (this.runOptions.scheme) {
322runArguments.push("--scheme", this.runOptions.scheme);
323}
8a67e140Artem Egorov8 years ago324}
325
326return runArguments;
327}
328
4cd25962JiglioNero4 years ago329public async getTargetFromRunArgs(): Promise<IOSTarget | undefined> {
330if (this.runOptions.runArguments && this.runOptions.runArguments.length > 0) {
c76b733bJiglioNero4 years ago331const targets = (await this.targetManager.getTargetList()) as IDebuggableIOSTarget[];
332
4cd25962JiglioNero4 years ago333const udid = GeneralMobilePlatform.getOptFromRunArgs(
334this.runOptions.runArguments,
335"--udid",
336);
337if (udid) {
338const target = targets.find(target => target.id === udid);
339if (target) {
340return IOSTarget.fromInterface(target);
341}
09f6024fHeniker4 years ago342this.logger.warning(
343localize(
344"ThereIsNoIosTargetWithSuchUdid",
345"There is no iOS target with such UDID: {0}",
346udid,
347),
348);
4cd25962JiglioNero4 years ago349}
350
351const device = GeneralMobilePlatform.getOptFromRunArgs(
352this.runOptions.runArguments,
353"--device",
354);
355if (device) {
356const target = targets.find(
c76b733bJiglioNero4 years ago357target => !target.isVirtualTarget && target.name === device,
4cd25962JiglioNero4 years ago358);
359if (target) {
360return IOSTarget.fromInterface(target);
361}
09f6024fHeniker4 years ago362this.logger.warning(
363localize(
364"ThereIsNoIosDeviceWithSuchName",
365"There is no iOS device with such name: {0}",
366device,
367),
368);
4cd25962JiglioNero4 years ago369}
370
371const simulator = GeneralMobilePlatform.getOptFromRunArgs(
372this.runOptions.runArguments,
373"--simulator",
374);
375if (simulator) {
376const target = targets.find(
c76b733bJiglioNero4 years ago377target => target.isVirtualTarget && target.name === simulator,
4cd25962JiglioNero4 years ago378);
379if (target) {
380return IOSTarget.fromInterface(target);
381}
09f6024fHeniker4 years ago382this.logger.warning(
383localize(
384"ThereIsNoIosSimulatorWithSuchName",
385"There is no iOS simulator with such name: {0}",
386simulator,
387),
388);
4cd25962JiglioNero4 years ago389}
390}
391
392return undefined;
393}
394
de838bbfJiglioNero6 years ago395private handleTargetArg(target: string): string[] {
09f6024fHeniker4 years ago396return target === TargetType.Device || target === TargetType.Simulator
397? [`--${target}`]
398: ["--udid", target];
de838bbfJiglioNero6 years ago399}
400
0d77292aJiglioNero4 years ago401private async generateSuccessPatterns(version: string): Promise<string[]> {
3021756bYuri Skorokhodov6 years ago402// Clone RUN_IOS_SUCCESS_PATTERNS to avoid its runtime mutation
09f6024fHeniker4 years ago403const successPatterns = [...IOSPlatform.RUN_IOS_SUCCESS_PATTERNS];
4cd25962JiglioNero4 years ago404if (!(await this.getTarget()).isVirtualTarget) {
47927908RedMickey4 years ago405if (
406semver.gte(version, IOSPlatform.NEW_RN_CLI_BEHAVIOUR_VERSION) ||
407ProjectVersionHelper.isCanaryVersion(version)
408) {
3021756bYuri Skorokhodov6 years ago409successPatterns.push("success Installed the app on the device");
410} else {
411successPatterns.push("INSTALLATION SUCCEEDED");
412}
0d77292aJiglioNero4 years ago413return successPatterns;
09f6024fHeniker4 years ago414}
415const bundleId = await this.getBundleId();
47927908RedMickey4 years ago416if (
417semver.gte(version, IOSPlatform.NEW_RN_CLI_BEHAVIOUR_VERSION) ||
418ProjectVersionHelper.isCanaryVersion(version)
419) {
09f6024fHeniker4 years ago420successPatterns.push(`Launching "${bundleId}"\nsuccess Successfully launched the app `);
3021756bYuri Skorokhodov6 years ago421} else {
09f6024fHeniker4 years ago422successPatterns.push(`Launching ${bundleId}\n${bundleId}: `);
3021756bYuri Skorokhodov6 years ago423}
09f6024fHeniker4 years ago424return successPatterns;
8a67e140Artem Egorov8 years ago425}
426
db6fd42aRuslan Bikkinin7 years ago427private getConfiguration(): string {
34472878RedMickey5 years ago428return (
429IOSPlatform.getOptFromRunArgs(this.runArguments, this.configurationArgumentName) ||
430this.defaultConfiguration
431);
db6fd42aRuslan Bikkinin7 years ago432}
433
ce5e88eeYuri Skorokhodov5 years ago434private getBundleId(): Promise<string> {
116c3cb0Ruslan Bikkinin7 years ago435let scheme = this.runOptions.scheme;
436if (!scheme) {
34472878RedMickey5 years ago437const schemeFromArgs = IOSPlatform.getOptFromRunArgs(
438this.runArguments,
439"--scheme",
440false,
441);
116c3cb0Ruslan Bikkinin7 years ago442if (schemeFromArgs) {
443scheme = schemeFromArgs;
444}
445}
34472878RedMickey5 years ago446return this.plistBuddy.getBundleId(
447this.iosProjectRoot,
448this.projectPath,
1c2424f4RedMickey5 years ago449PlatformType.iOS,
34472878RedMickey5 years ago450true,
451this.runOptions.configuration,
452this.runOptions.productName,
453scheme,
454);
8a67e140Artem Egorov8 years ago455}
456}