Skip to content

Commit 81b32bc

Browse files
authored
feat: add open ios/android (#5779)
1 parent 5e311bf commit 81b32bc

File tree

6 files changed

+191
-24
lines changed

6 files changed

+191
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<% if (isJekyll) { %>---
2+
title: ns open android
3+
position: 10
4+
---<% } %>
5+
6+
# ns open android
7+
8+
### Description
9+
10+
Opens the Android native project from the corresponding `platforms` directory.
11+
12+
If the native project has not already been generated, the `prepare` command will be issued to generate the project, and the project will then be opened.
13+
14+
### Commands
15+
16+
Usage | Synopsis
17+
------|-------
18+
Open the project in Android Studio | `$ ns open android`
19+
20+
<% if(isHtml) { %>
21+
22+
### Related Commands
23+
24+
Command | Description
25+
----------|----------
26+
[prepare](prepare.html) | Copies common and relevant platform-specific content from the app directory to the subdirectory for the selected target platform in the platforms directory.
27+
<% } %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<% if (isJekyll) { %>---
2+
title: ns open ios
3+
position: 10
4+
---<% } %>
5+
6+
# ns open ios
7+
8+
### Description
9+
10+
Opens the iOS native project from the corresponding `platforms` directory.
11+
12+
If the native project has not already been generated, the `prepare` command will be issued to generate the project, and the project will then be opened.
13+
14+
### Commands
15+
16+
Usage | Synopsis
17+
------|-------
18+
Open the project in Xcode | `$ ns open ios`
19+
20+
<% if(isHtml) { %>
21+
22+
### Command Limitations
23+
24+
* You can run `$ ns open ios` only on macOS systems.
25+
26+
### Related Commands
27+
28+
Command | Description
29+
----------|----------
30+
[prepare](prepare.html) | Copies common and relevant platform-specific content from the app directory to the subdirectory for the selected target platform in the platforms directory.
31+
<% } %>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<% if (isJekyll) { %>---
2+
title: ns open
3+
position: 10
4+
---<% } %>
5+
6+
# ns open
7+
8+
### Description
9+
10+
Opens the iOS/Android native project from the corresponding `platforms` directory.
11+
12+
If the native project has not already been generated, the `prepare` command will be issued to generate the project, and the project will then be opened.
13+
14+
### Commands
15+
16+
Usage | Synopsis
17+
------|-------
18+
<% if((isConsole && isMacOS) || isHtml) { %>General | `$ ns open <Platform>`<% } %><% if(isConsole && (isLinux || isWindows)) { %>General | `$ ns open android`<% } %>
19+
20+
<% if(isMacOS) { %>### Arguments
21+
`<Platform>` is the target mobile platform for which you want to open the native project. You can set the following target platforms.
22+
* `android` - Opens the Android project in Android Studio.
23+
* `ios` - Opens native iOS project in Xcode.<% } %>
24+
25+
<% if(isHtml) { %>
26+
27+
### Command Limitations
28+
29+
* You can run `$ ns open ios` only on macOS systems.
30+
31+
### Related Commands
32+
33+
Command | Description
34+
----------|----------
35+
[prepare](prepare.html) | Copies common and relevant platform-specific content from the app directory to the subdirectory for the selected target platform in the platforms directory.
36+
<% } %>

docs/man_pages/start.md

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Command | Description
4949
[test `<Platform>`](project/testing/test.html) | Runs the unit tests in your project on a connected physical or virtual device.
5050
[install](project/configuration/install.html) | Installs all platforms and dependencies described in the `package.json` file in the current directory.
5151
[plugin](lib-management/plugin.html) | Lets you manage the plugins for your project.
52+
[open](project/configuration/open.md) | Opens the native project in Xcode/Android Studio.
5253

5354
## Publishing Commands
5455
Command | Description

lib/key-commands/bootstrap.ts

+2
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ injector.requireKeyCommand("n", path);
1515

1616
injector.requireKeyCommand(SpecialKeys.QuestionMark, path);
1717
injector.requireKeyCommand(SpecialKeys.CtrlC, path);
18+
injector.requireCommand("open|ios", path);
19+
injector.requireCommand("open|android", path);

lib/key-commands/index.ts

+94-24
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { platform as currentPlatform } from "os";
33
import * as path from "path";
44
import { color } from "../color";
55
import { PrepareCommand } from "../commands/prepare";
6-
import { IChildProcess } from "../common/declarations";
6+
import { IChildProcess, IXcodeSelectService } from "../common/declarations";
77
import { ICommand } from "../common/definitions/commands";
88
import {
99
IKeyCommand,
@@ -16,6 +16,8 @@ import {
1616
import { injector } from "../common/yok";
1717
import { IProjectData } from "../definitions/project";
1818
import { IStartService } from "../definitions/start-service";
19+
import { IOSProjectService } from "../services/ios-project-service";
20+
import { IOptions } from "../declarations";
1921

2022
export class A implements IKeyCommand {
2123
key: IValidKeyName = "a";
@@ -38,7 +40,7 @@ export class ShiftA implements IKeyCommand {
3840
platform: IKeyCommandPlatform = "Android";
3941
description: string = "Open android project in Android Studio";
4042
willBlockKeyCommandExecution: boolean = true;
41-
43+
protected isInteractive: boolean = true;
4244
constructor(
4345
private $logger: ILogger,
4446
private $liveSyncCommandHelper: ILiveSyncCommandHelper,
@@ -56,7 +58,9 @@ export class ShiftA implements IKeyCommand {
5658
"prepare"
5759
) as PrepareCommand;
5860
await prepareCommand.execute([this.platform]);
59-
process.stdin.resume();
61+
if (this.isInteractive) {
62+
process.stdin.resume();
63+
}
6064
}
6165

6266
const os = currentPlatform();
@@ -93,7 +97,11 @@ export class ShiftA implements IKeyCommand {
9397
return;
9498
}
9599

96-
this.$childProcess.exec(`"${studioPath}" "${androidDir}"`);
100+
const child = this.$childProcess.spawn(studioPath, [androidDir], {
101+
detached: true,
102+
stdio: "ignore",
103+
});
104+
child.unref();
97105
} else if (os === "linux") {
98106
if (!fs.existsSync(`/usr/local/android-studio/bin/studio.sh`)) {
99107
this.$logger.error("Android Studio is not installed");
@@ -105,6 +113,22 @@ export class ShiftA implements IKeyCommand {
105113
}
106114
}
107115
}
116+
export class OpenAndroidCommand extends ShiftA {
117+
constructor(
118+
$logger: ILogger,
119+
$liveSyncCommandHelper: ILiveSyncCommandHelper,
120+
$childProcess: IChildProcess,
121+
$projectData: IProjectData,
122+
private $options: IOptions
123+
) {
124+
super($logger, $liveSyncCommandHelper, $childProcess, $projectData);
125+
this.isInteractive = false;
126+
}
127+
async execute(): Promise<void> {
128+
this.$options.watch = false;
129+
super.execute();
130+
}
131+
}
108132

109133
export class I implements IKeyCommand {
110134
key: IValidKeyName = "i";
@@ -127,40 +151,83 @@ export class ShiftI implements IKeyCommand {
127151
platform: IKeyCommandPlatform = "iOS";
128152
description: string = "Open iOS project in Xcode";
129153
willBlockKeyCommandExecution: boolean = true;
154+
protected isInteractive: boolean = true;
130155

131156
constructor(
157+
private $iOSProjectService: IOSProjectService,
132158
private $logger: ILogger,
133159
private $childProcess: IChildProcess,
134-
private $projectData: IProjectData
160+
private $projectData: IProjectData,
161+
private $xcodeSelectService: IXcodeSelectService,
162+
private $xcodebuildArgsService: IXcodebuildArgsService
135163
) {}
136164

137165
async execute(): Promise<void> {
138-
this.$projectData.initializeProjectData();
139-
const iosDir = path.resolve(this.$projectData.platformsDir, "ios");
140-
141-
// TODO: reuse logic for resolving the xcode project file.
142-
const xcprojectFile = path.resolve(iosDir);
143-
144-
if (!fs.existsSync(iosDir)) {
145-
const prepareCommand = injector.resolveCommand(
146-
"prepare"
147-
) as PrepareCommand;
148-
await prepareCommand.execute(["ios"]);
149-
process.stdin.resume();
150-
}
151-
152166
const os = currentPlatform();
153167
if (os === "darwin") {
154-
// TODO: remove this, and just use "open path/to/ios/xcworkspace or xcproject".
155-
if (!fs.existsSync("/Applications/Xcode.app")) {
156-
this.$logger.error("Xcode is not installed");
157-
return;
168+
this.$projectData.initializeProjectData();
169+
const iosDir = path.resolve(this.$projectData.platformsDir, "ios");
170+
171+
if (!fs.existsSync(iosDir)) {
172+
const prepareCommand = injector.resolveCommand(
173+
"prepare"
174+
) as PrepareCommand;
175+
176+
await prepareCommand.execute(["ios"]);
177+
if (this.isInteractive) {
178+
process.stdin.resume();
179+
}
158180
}
159-
this.$childProcess.exec(`open ${xcprojectFile}`);
181+
const platformData = this.$iOSProjectService.getPlatformData(
182+
this.$projectData
183+
);
184+
const xcprojectFile = this.$xcodebuildArgsService.getXcodeProjectArgs(
185+
platformData.projectRoot,
186+
this.$projectData
187+
)[1];
188+
189+
if (fs.existsSync(xcprojectFile)) {
190+
this.$xcodeSelectService
191+
.getDeveloperDirectoryPath()
192+
.then(() => this.$childProcess.exec(`open ${xcprojectFile}`, {}))
193+
.catch((e) => {
194+
this.$logger.error(e.message);
195+
});
196+
} else {
197+
this.$logger.error(`Unable to open project file: ${xcprojectFile}`);
198+
}
199+
} else {
200+
this.$logger.error("Opening a project in XCode requires macOS.");
160201
}
161202
}
162203
}
163204

205+
export class OpenIOSCommand extends ShiftI {
206+
constructor(
207+
$iOSProjectService: IOSProjectService,
208+
$logger: ILogger,
209+
$childProcess: IChildProcess,
210+
$projectData: IProjectData,
211+
$xcodeSelectService: IXcodeSelectService,
212+
$xcodebuildArgsService: IXcodebuildArgsService,
213+
private $options: IOptions
214+
) {
215+
super(
216+
$iOSProjectService,
217+
$logger,
218+
$childProcess,
219+
$projectData,
220+
$xcodeSelectService,
221+
$xcodebuildArgsService
222+
);
223+
this.isInteractive = false;
224+
}
225+
async execute(): Promise<void> {
226+
this.$options.watch = false;
227+
super.execute();
228+
}
229+
}
230+
164231
export class R implements IKeyCommand {
165232
key: IValidKeyName = "r";
166233
platform: IKeyCommandPlatform = "all";
@@ -317,3 +384,6 @@ injector.registerKeyCommand("A", ShiftA);
317384
injector.registerKeyCommand("n", N);
318385
injector.registerKeyCommand(SpecialKeys.QuestionMark, QuestionMark);
319386
injector.registerKeyCommand(SpecialKeys.CtrlC, CtrlC);
387+
388+
injector.registerCommand("open|ios", OpenIOSCommand);
389+
injector.registerCommand("open|android", OpenAndroidCommand);

0 commit comments

Comments
 (0)