microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
0.6.17

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/extension/ios/iOSPlatform.ts

211lines · 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 Q from "q";
5import * as path from "path";
df8c800dArtem Egorov8 years ago6import * as semver from "semver";
8a67e140Artem Egorov8 years ago7
8import {ChildProcess} from "../../common/node/childProcess";
9import {CommandExecutor} from "../../common/commandExecutor";
0a68f8dbArtem Egorov8 years ago10import {GeneralMobilePlatform, MobilePlatformDeps, TargetType} from "../generalMobilePlatform";
11import {IIOSRunOptions} from "../launchArgs";
12import {PlistBuddy} from "./plistBuddy";
13import {IOSDebugModeManager} from "./iOSDebugModeManager";
8a67e140Artem Egorov8 years ago14import {OutputVerifier, PatternToFailure} from "../../common/outputVerifier";
0a68f8dbArtem Egorov8 years ago15import {ErrorHelper} from "../../common/error/errorHelper";
a41f5c68Artem Egorov8 years ago16import {SettingsHelper} from "../settingsHelper";
7daed3fcArtem Egorov8 years ago17import {RemoteExtension} from "../../common/remoteExtension";
df8c800dArtem Egorov8 years ago18import {ReactNativeProjectHelper} from "../../common/reactNativeProjectHelper";
031832ffArtem Egorov8 years ago19import {TelemetryHelper} from "../../common/telemetryHelper";
8022afdfVladimir Kotikov8 years ago20
8a67e140Artem Egorov8 years ago21export class IOSPlatform extends GeneralMobilePlatform {
22public static DEFAULT_IOS_PROJECT_RELATIVE_PATH = "ios";
7daed3fcArtem Egorov8 years ago23private static remoteExtension: RemoteExtension;
0a68f8dbArtem Egorov8 years ago24
8a67e140Artem Egorov8 years ago25private plistBuddy = new PlistBuddy();
8022afdfVladimir Kotikov8 years ago26private targetType: TargetType = "simulator";
0db0be15Artem Egorov8 years ago27private iosProjectRoot: string;
7daed3fcArtem Egorov8 years ago28private iosDebugModeManager: IOSDebugModeManager;
29
db6fd42aRuslan Bikkinin7 years ago30private defaultConfiguration: string = "Debug";
31private configurationArgumentName: string = "--configuration";
8a67e140Artem Egorov8 years ago32
0a68f8dbArtem Egorov8 years ago33// We should add the common iOS build/run errors we find to this list
8a67e140Artem Egorov8 years ago34private static RUN_IOS_FAILURE_PATTERNS: PatternToFailure[] = [{
35pattern: "No devices are booted",
3c172a05Artem Egorov8 years ago36message: ErrorHelper.ERROR_STRINGS.IOSSimulatorNotLaunchable,
8a67e140Artem Egorov8 years ago37}, {
38pattern: "FBSOpenApplicationErrorDomain",
3c172a05Artem Egorov8 years ago39message: ErrorHelper.ERROR_STRINGS.IOSSimulatorNotLaunchable,
8a67e140Artem Egorov8 years ago40}, {
41pattern: "ios-deploy",
3c172a05Artem Egorov8 years ago42message: ErrorHelper.ERROR_STRINGS.IOSDeployNotFound,
8a67e140Artem Egorov8 years ago43}];
44
45private static RUN_IOS_SUCCESS_PATTERNS = ["BUILD SUCCEEDED"];
46
db6fd42aRuslan Bikkinin7 years ago47public showDevMenu(deviceId?: string): Q.Promise<void> {
48return IOSPlatform.remote(this.runOptions.projectRoot).showDevMenu(deviceId);
7daed3fcArtem Egorov8 years ago49}
50
db6fd42aRuslan Bikkinin7 years ago51public reloadApp(deviceId?: string): Q.Promise<void> {
52return IOSPlatform.remote(this.runOptions.projectRoot).reloadApp(deviceId);
7daed3fcArtem Egorov8 years ago53}
54
0a68f8dbArtem Egorov8 years ago55constructor(protected runOptions: IIOSRunOptions, platformDeps: MobilePlatformDeps = {}) {
56super(runOptions, platformDeps);
8a67e140Artem Egorov8 years ago57
db6fd42aRuslan Bikkinin7 years ago58this.runOptions.configuration = this.getConfiguration();
59
0db0be15Artem Egorov8 years ago60if (this.runOptions.iosRelativeProjectPath) { // Deprecated option
0a68f8dbArtem Egorov8 years ago61this.logger.warning("'iosRelativeProjectPath' option is deprecated. Please use 'runArguments' instead");
8a67e140Artem Egorov8 years ago62}
63
0a68f8dbArtem Egorov8 years ago64this.iosProjectRoot = path.join(this.projectPath, this.runOptions.iosRelativeProjectPath || IOSPlatform.DEFAULT_IOS_PROJECT_RELATIVE_PATH);
7daed3fcArtem Egorov8 years ago65this.iosDebugModeManager = new IOSDebugModeManager(this.iosProjectRoot);
8a67e140Artem Egorov8 years ago66
db6fd42aRuslan Bikkinin7 years ago67if (this.runArguments && this.runArguments.length > 0) {
68this.targetType = (this.runArguments.indexOf(`--${IOSPlatform.deviceString}`) >= 0) ?
8022afdfVladimir Kotikov8 years ago69IOSPlatform.deviceString : IOSPlatform.simulatorString;
70return;
71}
0db0be15Artem Egorov8 years ago72
8022afdfVladimir Kotikov8 years ago73if (this.runOptions.target && (this.runOptions.target !== IOSPlatform.simulatorString &&
74this.runOptions.target !== IOSPlatform.deviceString)) {
0db0be15Artem Egorov8 years ago75
8022afdfVladimir Kotikov8 years ago76this.targetType = IOSPlatform.simulatorString;
77return;
8a67e140Artem Egorov8 years ago78}
8022afdfVladimir Kotikov8 years ago79
80this.targetType = this.runOptions.target || IOSPlatform.simulatorString;
8a67e140Artem Egorov8 years ago81}
82
83public runApp(): Q.Promise<void> {
031832ffArtem Egorov8 years ago84const extProps = {
85platform: {
86value: "ios",
87isPii: false,
88},
89};
90
91return TelemetryHelper.generate("iOSPlatform.runApp", extProps, () => {
92// Compile, deploy, and launch the app on either a simulator or a device
93const env = this.getEnvArgument();
94
95return ReactNativeProjectHelper.getReactNativeVersion(this.runOptions.projectRoot)
96.then(version => {
97if (!semver.valid(version) /*Custom RN implementations should support this flag*/ || semver.gte(version, IOSPlatform.NO_PACKAGER_VERSION)) {
db6fd42aRuslan Bikkinin7 years ago98this.runArguments.push("--no-packager");
031832ffArtem Egorov8 years ago99}
db6fd42aRuslan Bikkinin7 years ago100const runIosSpawn = new CommandExecutor(this.projectPath, this.logger).spawnReactCommand("run-ios", this.runArguments, {env});
031832ffArtem Egorov8 years ago101return new OutputVerifier(() => this.generateSuccessPatterns(), () => Q(IOSPlatform.RUN_IOS_FAILURE_PATTERNS), "ios")
102.process(runIosSpawn);
103});
104});
8a67e140Artem Egorov8 years ago105}
106
107public enableJSDebuggingMode(): Q.Promise<void> {
108// Configure the app for debugging
109if (this.targetType === IOSPlatform.deviceString) {
110// Note that currently we cannot automatically switch the device into debug mode.
7daed3fcArtem Egorov8 years ago111this.logger.info("Application is running on a device, please shake device and select 'Debug JS Remotely' to enable debugging.");
8a67e140Artem Egorov8 years ago112return Q.resolve<void>(void 0);
113}
114
115// Wait until the configuration file exists, and check to see if debugging is enabled
116return Q.all<boolean | string>([
db6fd42aRuslan Bikkinin7 years ago117this.iosDebugModeManager.getSimulatorRemoteDebuggingSetting(this.runOptions.configuration, this.runOptions.productName),
8a67e140Artem Egorov8 years ago118this.getBundleId(),
119])
120.spread((debugModeEnabled: boolean, bundleId: string) => {
121if (debugModeEnabled) {
122return Q.resolve(void 0);
123}
124
125// Debugging must still be enabled
126// We enable debugging by writing to a plist file that backs a NSUserDefaults object,
127// but that file is written to by the app on occasion. To avoid races, we shut the app
128// down before writing to the file.
129const childProcess = new ChildProcess();
130
131return childProcess.execToString("xcrun simctl spawn booted launchctl list")
132.then((output: string) => {
133// Try to find an entry that looks like UIKitApplication:com.example.myApp[0x4f37]
134const regex = new RegExp(`(\\S+${bundleId}\\S+)`);
135const match = regex.exec(output);
136
137// If we don't find a match, the app must not be running and so we do not need to close it
138return match ? childProcess.exec(`xcrun simctl spawn booted launchctl stop ${match[1]}`) : null;
139})
140.then(() => {
141// Write to the settings file while the app is not running to avoid races
db6fd42aRuslan Bikkinin7 years ago142return this.iosDebugModeManager.setSimulatorRemoteDebuggingSetting(/*enable=*/ true, this.runOptions.configuration, this.runOptions.productName);
8a67e140Artem Egorov8 years ago143})
144.then(() => {
145// Relaunch the app
146return this.runApp();
147});
148});
149}
150
0a68f8dbArtem Egorov8 years ago151public disableJSDebuggingMode(): Q.Promise<void> {
db6fd42aRuslan Bikkinin7 years ago152return this.iosDebugModeManager.setSimulatorRemoteDebuggingSetting(/*enable=*/ false, this.runOptions.configuration, this.runOptions.productName);
0a68f8dbArtem Egorov8 years ago153}
154
8a67e140Artem Egorov8 years ago155public prewarmBundleCache(): Q.Promise<void> {
0a68f8dbArtem Egorov8 years ago156return this.packager.prewarmBundleCache("ios");
8a67e140Artem Egorov8 years ago157}
158
cbc7ac5bArtem Egorov7 years ago159public getRunArguments(): string[] {
8a67e140Artem Egorov8 years ago160let runArguments: string[] = [];
0db0be15Artem Egorov8 years ago161
162if (this.runOptions.runArguments && this.runOptions.runArguments.length > 0) {
b57ea017Artem Egorov8 years ago163runArguments = this.runOptions.runArguments;
164} else {
165if (this.runOptions.target) {
166if (this.runOptions.target === IOSPlatform.deviceString ||
167this.runOptions.target === IOSPlatform.simulatorString) {
168
169runArguments.push(`--${this.runOptions.target}`);
170} else {
171runArguments.push("--simulator", `${this.runOptions.target}`);
172}
173}
8abbd163Artem Egorov8 years ago174
b57ea017Artem Egorov8 years ago175if (this.runOptions.iosRelativeProjectPath) {
176runArguments.push("--project-path", this.runOptions.iosRelativeProjectPath);
8022afdfVladimir Kotikov8 years ago177}
8a67e140Artem Egorov8 years ago178
b57ea017Artem Egorov8 years ago179// provide any defined scheme
180if (this.runOptions.scheme) {
181runArguments.push("--scheme", this.runOptions.scheme);
182}
8a67e140Artem Egorov8 years ago183}
184
185return runArguments;
186}
187
188private generateSuccessPatterns(): Q.Promise<string[]> {
ed8367fdVladimir Kotikov8 years ago189return this.targetType === IOSPlatform.deviceString ?
190Q(IOSPlatform.RUN_IOS_SUCCESS_PATTERNS.concat("INSTALLATION SUCCEEDED")) :
191this.getBundleId()
192.then(bundleId => IOSPlatform.RUN_IOS_SUCCESS_PATTERNS
193.concat([`Launching ${bundleId}\n${bundleId}: `]));
8a67e140Artem Egorov8 years ago194}
195
db6fd42aRuslan Bikkinin7 years ago196private getConfiguration(): string {
197return this.getOptFromRunArgs(this.configurationArgumentName) || this.defaultConfiguration;
198}
199
8a67e140Artem Egorov8 years ago200private getBundleId(): Q.Promise<string> {
db6fd42aRuslan Bikkinin7 years ago201return this.plistBuddy.getBundleId(this.iosProjectRoot, true, this.runOptions.configuration, this.runOptions.productName);
8a67e140Artem Egorov8 years ago202}
7daed3fcArtem Egorov8 years ago203
4edcda70Artem Egorov8 years ago204private static remote(fsPath: string): RemoteExtension {
7daed3fcArtem Egorov8 years ago205if (this.remoteExtension) {
206return this.remoteExtension;
207} else {
4edcda70Artem Egorov8 years ago208return this.remoteExtension = RemoteExtension.atProjectRootPath(SettingsHelper.getReactNativeProjectRoot(fsPath));
7daed3fcArtem Egorov8 years ago209}
210}
8a67e140Artem Egorov8 years ago211}