Skip to content

Commit ef8296b

Browse files
committed
fix(cordova): prefer plugged-in devices, be explicit with Cordova
1 parent d6af864 commit ef8296b

File tree

3 files changed

+65
-16
lines changed

3 files changed

+65
-16
lines changed

packages/ionic/src/commands/cordova/run.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Footnote, MetadataGroup } from '@ionic/cli-framework';
22
import { onBeforeExit, sleepForever } from '@ionic/utils-process';
3+
import * as Debug from 'debug';
34
import * as url from 'url';
45

56
import { CommandInstanceInfo, CommandLineInputs, CommandLineOptions, CommandMetadata, CommandMetadataOption, CommandPreRun, IShellRunOptions } from '../../definitions';
@@ -9,12 +10,14 @@ import { FatalException } from '../../lib/errors';
910
import { loadConfigXml } from '../../lib/integrations/cordova/config';
1011
import { getPackagePath } from '../../lib/integrations/cordova/project';
1112
import { filterArgumentsForCordova, generateOptionsForCordovaBuild } from '../../lib/integrations/cordova/utils';
12-
import { SUPPORTED_PLATFORMS, checkNativeRun, createNativeRunArgs, createNativeRunListArgs, runNativeRun } from '../../lib/native-run';
13+
import { SUPPORTED_PLATFORMS, checkNativeRun, createNativeRunArgs, createNativeRunListArgs, getNativeTargets, runNativeRun } from '../../lib/native-run';
1314
import { COMMON_SERVE_COMMAND_OPTIONS, LOCAL_ADDRESSES, serve } from '../../lib/serve';
1415
import { createPrefixedWriteStream } from '../../lib/utils/logger';
1516

1617
import { CORDOVA_BUILD_EXAMPLE_COMMANDS, CORDOVA_RUN_OPTIONS, CordovaCommand } from './base';
1718

19+
const debug = Debug('ionic:commands:run');
20+
1821
const NATIVE_RUN_OPTIONS: readonly CommandMetadataOption[] = [
1922
{
2023
name: 'native-run',
@@ -209,6 +212,21 @@ Just like with ${input('ionic cordova build')}, you can pass additional options
209212
options['native-run'] = false;
210213
}
211214

215+
// If we're using native-run, and if --device and --emulator are not used,
216+
// we can detect if hardware devices are plugged in and prefer them over
217+
// any virtual devices the host has.
218+
if (options['native-run'] && !options['device'] && !options['emulator'] && platform) {
219+
const platformTargets = await getNativeTargets(this.env, platform);
220+
const { devices } = platformTargets;
221+
222+
debug(`Native platform devices: %O`, devices);
223+
224+
if (devices.length > 0) {
225+
this.env.log.info(`Hardware device(s) found for ${input(platform)}. Using ${input('--device')}.`);
226+
options['device'] = true;
227+
}
228+
}
229+
212230
await this.checkForPlatformInstallation(platform);
213231
}
214232

@@ -221,13 +239,13 @@ Just like with ${input('ionic cordova build')}, you can pass additional options
221239
}
222240

223241
protected async runServeDeploy(inputs: CommandLineInputs, options: CommandLineOptions) {
224-
if (!this.project) {
225-
throw new FatalException(`Cannot run ${input('ionic cordova run/emulate')} outside a project directory.`);
226-
}
227-
228242
const conf = await loadConfigXml(this.integration);
229243
const metadata = await this.getMetadata();
230244

245+
if (!this.project) {
246+
throw new FatalException(`Cannot run ${input(`ionic cordova ${metadata.name}`)} outside a project directory.`);
247+
}
248+
231249
let livereloadUrl = options['livereload-url'] ? String(options['livereload-url']) : undefined;
232250

233251
if (!livereloadUrl) {
@@ -254,7 +272,7 @@ Just like with ${input('ionic cordova build')}, you can pass additional options
254272

255273
if (options['native-run']) {
256274
const [ platform ] = inputs;
257-
const packagePath = await getPackagePath(conf.getProjectInfo().name, platform, options['emulator'] as boolean);
275+
const packagePath = await getPackagePath(conf.getProjectInfo().name, platform, !options['device']);
258276
const { port: portForward } = url.parse(livereloadUrl);
259277

260278
const buildOpts: IShellRunOptions = { stream: cordovalogws };
@@ -272,21 +290,21 @@ Just like with ${input('ionic cordova build')}, you can pass additional options
272290
}
273291

274292
protected async runBuildDeploy(inputs: CommandLineInputs, options: CommandLineOptions) {
275-
if (!this.project) {
276-
throw new FatalException(`Cannot run ${input('ionic cordova run/emulate')} outside a project directory.`);
277-
}
278-
279293
const conf = await loadConfigXml(this.integration);
280294
const metadata = await this.getMetadata();
281295

296+
if (!this.project) {
297+
throw new FatalException(`Cannot run ${input(`ionic cordova ${metadata.name}`)} outside a project directory.`);
298+
}
299+
282300
if (options.build) {
283301
// TODO: use runner directly
284302
await build({ config: this.env.config, log: this.env.log, shell: this.env.shell, prompt: this.env.prompt, project: this.project }, inputs, generateOptionsForCordovaBuild(metadata, inputs, options));
285303
}
286304

287305
if (options['native-run']) {
288306
const [ platform ] = inputs;
289-
const packagePath = await getPackagePath(conf.getProjectInfo().name, platform, options['emulator'] as boolean);
307+
const packagePath = await getPackagePath(conf.getProjectInfo().name, platform, !options['device']);
290308

291309
await this.runCordova(filterArgumentsForCordova({ ...metadata, name: 'build' }, options));
292310
await this.runNativeRun(createNativeRunArgs({ packagePath, platform }, { ...options, connect: false }));

packages/ionic/src/lib/integrations/cordova/project.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { filter } from '@ionic/utils-array';
22
import { readdirSafe, statSafe } from '@ionic/utils-fs';
33
import * as path from 'path';
44

5+
import { input } from '../../color';
6+
import { FatalException } from '../../errors';
7+
58
const CORDOVA_ANDROID_PACKAGE_PATH = 'platforms/android/app/build/outputs/apk/';
69
const CORDOVA_IOS_SIMULATOR_PACKAGE_PATH = 'platforms/ios/build/emulator';
710
const CORDOVA_IOS_DEVICE_PACKAGE_PATH = 'platforms/ios/build/device';
@@ -17,15 +20,18 @@ export async function getPlatforms(projectDir: string): Promise<string[]> {
1720
return platforms;
1821
}
1922

20-
export async function getPackagePath(appName: string, platform: string, emulator: boolean): Promise<string> {
23+
export async function getPackagePath(appName: string, platform: string, emulator = false): Promise<string> {
2124
if (platform === 'android') {
2225
// TODO: don't hardcode this/support multiple build paths (ex: multiple arch builds)
2326
// use app/build/outputs/apk/debug/output.json?
2427
return path.join(CORDOVA_ANDROID_PACKAGE_PATH, 'debug', 'app-debug.apk');
25-
}
26-
if (platform === 'ios' && emulator) {
27-
return path.join(CORDOVA_IOS_SIMULATOR_PACKAGE_PATH, `${appName}.app`);
28-
} else {
28+
} else if (platform === 'ios') {
29+
if (emulator) {
30+
return path.join(CORDOVA_IOS_SIMULATOR_PACKAGE_PATH, `${appName}.app`);
31+
}
32+
2933
return path.join(CORDOVA_IOS_DEVICE_PACKAGE_PATH, `${appName}.ipa`);
3034
}
35+
36+
throw new FatalException(`Unknown package path for ${input(appName)} on ${input(platform)}.`);
3137
}

packages/ionic/src/lib/native-run.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,28 @@ async function createNativeRunNotFoundError(npmClient: NpmClient): Promise<Fatal
119119
`${input(installArgs.join(' '))}\n`
120120
);
121121
}
122+
123+
export interface NativeDeviceTarget {
124+
platform: string;
125+
id: string;
126+
model: string;
127+
sdkVersion: string;
128+
}
129+
130+
export interface NativeVirtualDeviceTarget {
131+
platform: string;
132+
id: string;
133+
name: string;
134+
sdkVersion: string;
135+
}
136+
137+
export interface NativeTargetPlatform {
138+
devices: NativeDeviceTarget[];
139+
virtualDevices: NativeVirtualDeviceTarget[];
140+
}
141+
142+
export async function getNativeTargets({ shell }: RunNativeRunDeps, platform: string): Promise<NativeTargetPlatform> {
143+
const output = await shell.output('native-run', [platform, '--list', '--json'], { showCommand: false });
144+
145+
return JSON.parse(output);
146+
}

0 commit comments

Comments
 (0)