1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const cli_framework_1 = require("@ionic/cli-framework");
|
4 | const utils_process_1 = require("@ionic/utils-process");
|
5 | const chalk_1 = require("chalk");
|
6 | const lodash = require("lodash");
|
7 | const path = require("path");
|
8 | const color_1 = require("../../lib/color");
|
9 | const errors_1 = require("../../lib/errors");
|
10 | const config_1 = require("../../lib/integrations/capacitor/config");
|
11 | const utils_1 = require("../../lib/integrations/capacitor/utils");
|
12 | const serve_1 = require("../../lib/serve");
|
13 | const base_1 = require("./base");
|
14 | class RunCommand extends base_1.CapacitorCommand {
|
15 | async getMetadata() {
|
16 | const groups = ["beta" ];
|
17 | const exampleCommands = [
|
18 | '',
|
19 | 'android',
|
20 | 'android -l',
|
21 | 'ios --livereload',
|
22 | 'ios --livereload-url=http://localhost:8100',
|
23 | ].sort();
|
24 | let options = [
|
25 |
|
26 | {
|
27 | name: 'build',
|
28 | summary: 'Do not invoke Ionic build',
|
29 | type: Boolean,
|
30 | default: true,
|
31 | },
|
32 | ...serve_1.COMMON_SERVE_COMMAND_OPTIONS.filter(o => !['livereload'].includes(o.name)),
|
33 | {
|
34 | name: 'livereload',
|
35 | summary: 'Spin up dev server to live-reload www files',
|
36 | type: Boolean,
|
37 | aliases: ['l'],
|
38 | },
|
39 | {
|
40 | name: 'livereload-url',
|
41 | summary: 'Provide a custom URL to the dev server',
|
42 | spec: { value: 'url' },
|
43 | },
|
44 | ];
|
45 | const footnotes = [
|
46 | {
|
47 | id: 'remote-debugging-docs',
|
48 | url: 'https://ionicframework.com/docs/developer-resources/developer-tips',
|
49 | shortUrl: 'https://ion.link/remote-debugging-docs',
|
50 | },
|
51 | ];
|
52 | const serveRunner = this.project && await this.project.getServeRunner();
|
53 | const buildRunner = this.project && await this.project.getBuildRunner();
|
54 | if (buildRunner) {
|
55 | const libmetadata = await buildRunner.getCommandMetadata();
|
56 | groups.push(...libmetadata.groups || []);
|
57 | options.push(...libmetadata.options || []);
|
58 | footnotes.push(...libmetadata.footnotes || []);
|
59 | }
|
60 | if (serveRunner) {
|
61 | const libmetadata = await serveRunner.getCommandMetadata();
|
62 | const existingOpts = options.map(o => o.name);
|
63 | groups.push(...libmetadata.groups || []);
|
64 | const runnerOpts = (libmetadata.options || [])
|
65 | .filter(o => !existingOpts.includes(o.name))
|
66 | .map(o => ({ ...o, hint: `${o.hint ? `${o.hint} ` : ''}${color_1.weak('(--livereload)')}` }));
|
67 | options = lodash.uniqWith([...runnerOpts, ...options], (optionA, optionB) => optionA.name === optionB.name);
|
68 | footnotes.push(...libmetadata.footnotes || []);
|
69 | }
|
70 | return {
|
71 | name: 'run',
|
72 | type: 'project',
|
73 | summary: 'Run an Ionic project on a connected device',
|
74 | description: `
|
75 | ${color_1.input('ionic capacitor run')} will do the following:
|
76 | - Perform ${color_1.input('ionic build')} (or run the dev server from ${color_1.input('ionic serve')} with the ${color_1.input('--livereload')} option)
|
77 | - Copy web assets into the specified native platform
|
78 | - Open the IDE for your native project (Xcode for iOS, Android Studio for Android)
|
79 |
|
80 | Once the web assets and configuration are copied into your native project, the app can run on devices and emulators/simulators using the native IDE. Unfortunately, programmatically building and launching the native project is not yet supported.
|
81 |
|
82 | For Android and iOS, you can setup Remote Debugging on your device with browser development tools using these docs[^remote-debugging-docs].
|
83 | `,
|
84 | footnotes,
|
85 | exampleCommands,
|
86 | inputs: [
|
87 | {
|
88 | name: 'platform',
|
89 | summary: `The platform to run (e.g. ${['android', 'ios'].map(v => color_1.input(v)).join(', ')})`,
|
90 | validators: [cli_framework_1.validators.required],
|
91 | },
|
92 | ],
|
93 | options,
|
94 | groups,
|
95 | };
|
96 | }
|
97 | async preRun(inputs, options, runinfo) {
|
98 | await this.preRunChecks(runinfo);
|
99 | if (!inputs[0]) {
|
100 | const platform = await this.env.prompt({
|
101 | type: 'list',
|
102 | name: 'platform',
|
103 | message: 'What platform would you like to run?',
|
104 | choices: ['android', 'ios'],
|
105 | });
|
106 | inputs[0] = platform.trim();
|
107 | }
|
108 | if (options['livereload-url']) {
|
109 | options['livereload'] = true;
|
110 | }
|
111 | if (!options['build'] && options['livereload']) {
|
112 | this.env.log.warn(`No livereload with ${color_1.input('--no-build')}.`);
|
113 | options['livereload'] = false;
|
114 | }
|
115 | await this.checkForPlatformInstallation(inputs[0]);
|
116 | }
|
117 | async run(inputs, options) {
|
118 | if (!this.project) {
|
119 | throw new errors_1.FatalException(`Cannot run ${color_1.input('ionic capacitor run/emulate')} outside a project directory.`);
|
120 | }
|
121 | const [platform] = inputs;
|
122 | try {
|
123 | if (options['livereload']) {
|
124 | await this.runServe(inputs, options);
|
125 | }
|
126 | else {
|
127 | await this.runBuild(inputs, options);
|
128 | }
|
129 | }
|
130 | catch (e) {
|
131 | if (e instanceof errors_1.RunnerException) {
|
132 | throw new errors_1.FatalException(e.message);
|
133 | }
|
134 | throw e;
|
135 | }
|
136 |
|
137 | await this.runCapacitor(['copy', platform]);
|
138 |
|
139 | this.env.log.nl();
|
140 | this.env.log.info('Ready for use in your Native IDE!\n' +
|
141 | `To continue, run your project on a device or ${platform === 'ios' ? 'simulator' : 'emulator'} using ${platform === 'ios' ? 'Xcode' : 'Android Studio'}!`);
|
142 | this.env.log.nl();
|
143 | await this.runCapacitor(['open', platform]);
|
144 | if (options['livereload']) {
|
145 | this.env.log.nl();
|
146 | this.env.log.info('Development server will continue running until manually stopped.\n' +
|
147 | chalk_1.default.yellow('Use Ctrl+C to quit this process'));
|
148 | await utils_process_1.sleepForever();
|
149 | }
|
150 | }
|
151 | async runServe(inputs, options) {
|
152 | if (!this.project) {
|
153 | throw new errors_1.FatalException(`Cannot run ${color_1.input('ionic capacitor run/emulate')} outside a project directory.`);
|
154 | }
|
155 | const runner = await this.project.requireServeRunner();
|
156 | const runnerOpts = runner.createOptionsFromCommandLine(inputs, utils_1.generateOptionsForCapacitorBuild(inputs, options));
|
157 | let serverUrl = options['livereload-url'] ? String(options['livereload-url']) : undefined;
|
158 | if (!serverUrl) {
|
159 | const details = await runner.run(runnerOpts);
|
160 | if (details.externallyAccessible === false) {
|
161 | const extra = serve_1.LOCAL_ADDRESSES.includes(details.externalAddress) ? '\nEnsure you have proper port forwarding setup from your device to your computer.' : '';
|
162 | this.env.log.warn(`Your device or emulator may not be able to access ${color_1.strong(details.externalAddress)}.${extra}\n\n`);
|
163 | }
|
164 | serverUrl = `${details.protocol || 'http'}://${details.externalAddress}:${details.port}`;
|
165 | }
|
166 | const conf = new config_1.CapacitorConfig(path.resolve(this.project.directory, config_1.CAPACITOR_CONFIG_FILE));
|
167 | utils_process_1.onBeforeExit(async () => {
|
168 | conf.resetServerUrl();
|
169 | });
|
170 | conf.setServerUrl(serverUrl);
|
171 | }
|
172 | async runBuild(inputs, options) {
|
173 | if (!this.project) {
|
174 | throw new errors_1.FatalException(`Cannot run ${color_1.input('ionic capacitor run/emulate')} outside a project directory.`);
|
175 | }
|
176 | if (options['build']) {
|
177 | try {
|
178 | const runner = await this.project.requireBuildRunner();
|
179 | const runnerOpts = runner.createOptionsFromCommandLine(inputs, utils_1.generateOptionsForCapacitorBuild(inputs, options));
|
180 | await runner.run(runnerOpts);
|
181 | }
|
182 | catch (e) {
|
183 | if (e instanceof errors_1.RunnerException) {
|
184 | throw new errors_1.FatalException(e.message);
|
185 | }
|
186 | throw e;
|
187 | }
|
188 | }
|
189 | }
|
190 | }
|
191 | exports.RunCommand = RunCommand;
|