From 9bfd6741f063bcd6aa83317589afadc2cb5bcb1a Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Mon, 15 Sep 2025 14:41:13 -0500 Subject: [PATCH 01/10] add ability to select device target by name --- cli/src/android/run.ts | 13 +++++++++++-- cli/src/common.ts | 16 +++++++++++++++- cli/src/index.ts | 17 ++++++++++++++++- cli/src/ios/run.ts | 13 +++++++++++-- cli/src/tasks/run.ts | 1 + 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/cli/src/android/run.ts b/cli/src/android/run.ts index f93040ec3..c578c870a 100644 --- a/cli/src/android/run.ts +++ b/cli/src/android/run.ts @@ -12,9 +12,18 @@ const debug = Debug('capacitor:android:run'); export async function runAndroid( config: Config, - { target: selectedTarget, flavor: selectedFlavor, forwardPorts: selectedPorts }: RunCommandOptions, + { + target: selectedTarget, + targetName: selectedTargetName, + flavor: selectedFlavor, + forwardPorts: selectedPorts, + }: RunCommandOptions, ): Promise { - const target = await promptForPlatformTarget(await getPlatformTargets('android'), selectedTarget); + const target = await promptForPlatformTarget( + await getPlatformTargets('android'), + selectedTarget ?? selectedTargetName, + selectedTargetName !== undefined, + ); const runFlavor = selectedFlavor || config.android?.flavor || ''; diff --git a/cli/src/common.ts b/cli/src/common.ts index 0040789b4..415bc6f94 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -378,6 +378,7 @@ export interface PlatformTarget { export async function promptForPlatformTarget( targets: PlatformTarget[], selectedTarget?: string, + selectByName?: boolean, ): Promise { const { prompt } = await import('prompts'); const validTargets = targets.filter((t) => t.id !== undefined); @@ -404,10 +405,23 @@ export async function promptForPlatformTarget( } } + console.log('Select by name', selectByName); + const targetID = selectedTarget.trim(); - const target = targets.find((t) => t.id === targetID); + const target = targets.find((t) => { + if (selectByName === true) { + return t.name === targetID; + } + + t.id === targetID; + }); if (!target) { + if (selectByName) { + fatal( + `Invalid target name: ${c.input(targetID)}.\n` + `Valid targets are: ${targets.map((t) => t.name).join(', ')}`, + ); + } fatal(`Invalid target ID: ${c.input(targetID)}.\n` + `Valid targets are: ${targets.map((t) => t.id).join(', ')}`); } diff --git a/cli/src/index.ts b/cli/src/index.ts index 9bf9a49a6..c793df784 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -234,6 +234,7 @@ export function runProgram(config: Config): void { .option('--list', 'list targets, then quit') .addOption(new Option('--json').hideHelp()) .option('--target ', 'use a specific target') + .option('--target-name ', 'use a specific target by name') .option('--no-sync', `do not run ${c.input('sync')}`) .option('--forwardPorts ', 'Automatically run "adb reverse" for better live-reloading support') .option('-l, --live-reload', 'Enable Live Reload') @@ -246,7 +247,20 @@ export function runProgram(config: Config): void { config, async ( platform, - { scheme, flavor, list, json, target, sync, forwardPorts, liveReload, host, port, configuration }, + { + scheme, + flavor, + list, + json, + target, + targetName, + sync, + forwardPorts, + liveReload, + host, + port, + configuration, + }, ) => { const { runCommand } = await import('./tasks/run'); await runCommand(config, platform, { @@ -255,6 +269,7 @@ export function runProgram(config: Config): void { list, json, target, + targetName, sync, forwardPorts, liveReload, diff --git a/cli/src/ios/run.ts b/cli/src/ios/run.ts index 0c414494a..4a6de8d0f 100644 --- a/cli/src/ios/run.ts +++ b/cli/src/ios/run.ts @@ -13,9 +13,18 @@ const debug = Debug('capacitor:ios:run'); export async function runIOS( config: Config, - { target: selectedTarget, scheme: selectedScheme, configuration: selectedConfiguration }: RunCommandOptions, + { + target: selectedTarget, + targetName: selectedTargetName, + scheme: selectedScheme, + configuration: selectedConfiguration, + }: RunCommandOptions, ): Promise { - const target = await promptForPlatformTarget(await getPlatformTargets('ios'), selectedTarget); + const target = await promptForPlatformTarget( + await getPlatformTargets('ios'), + selectedTarget ?? selectedTargetName, + selectedTargetName !== undefined, + ); const runScheme = selectedScheme || config.ios.scheme; const configuration = selectedConfiguration || 'Debug'; diff --git a/cli/src/tasks/run.ts b/cli/src/tasks/run.ts index 7217d6123..84da99932 100644 --- a/cli/src/tasks/run.ts +++ b/cli/src/tasks/run.ts @@ -26,6 +26,7 @@ export interface RunCommandOptions { list?: boolean; json?: boolean; target?: string; + targetName?: string; sync?: boolean; forwardPorts?: string; liveReload?: boolean; From 19be785c030a957740991e15c5df20e9dc331ec1 Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Tue, 28 Oct 2025 09:44:47 -0500 Subject: [PATCH 02/10] removing log --- cli/src/common.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/cli/src/common.ts b/cli/src/common.ts index 415bc6f94..bc7689020 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -405,8 +405,6 @@ export async function promptForPlatformTarget( } } - console.log('Select by name', selectByName); - const targetID = selectedTarget.trim(); const target = targets.find((t) => { if (selectByName === true) { From 653db49a7f8abbb20f6f6d773bcdf8fe39084da8 Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Mon, 3 Nov 2025 08:45:31 -0600 Subject: [PATCH 03/10] Adding missing return --- cli/src/common.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/common.ts b/cli/src/common.ts index bc7689020..8bf775966 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -411,7 +411,7 @@ export async function promptForPlatformTarget( return t.name === targetID; } - t.id === targetID; + return t.id === targetID; }); if (!target) { From 5c4b8723846c3c8a36fb8b36f038167ddca87f10 Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Tue, 4 Nov 2025 11:19:25 -0600 Subject: [PATCH 04/10] Adding ability to further filter device target names by sdk version --- cli/src/android/run.ts | 2 ++ cli/src/common.ts | 8 +++++++- cli/src/index.ts | 3 +++ cli/src/ios/run.ts | 2 ++ cli/src/tasks/run.ts | 1 + 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cli/src/android/run.ts b/cli/src/android/run.ts index c578c870a..ed688f22d 100644 --- a/cli/src/android/run.ts +++ b/cli/src/android/run.ts @@ -15,6 +15,7 @@ export async function runAndroid( { target: selectedTarget, targetName: selectedTargetName, + targetNameSdkVersion: selectedTargetSdkVersion, flavor: selectedFlavor, forwardPorts: selectedPorts, }: RunCommandOptions, @@ -22,6 +23,7 @@ export async function runAndroid( const target = await promptForPlatformTarget( await getPlatformTargets('android'), selectedTarget ?? selectedTargetName, + selectedTargetSdkVersion, selectedTargetName !== undefined, ); diff --git a/cli/src/common.ts b/cli/src/common.ts index 8bf775966..ee70893c1 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -378,6 +378,7 @@ export interface PlatformTarget { export async function promptForPlatformTarget( targets: PlatformTarget[], selectedTarget?: string, + selectedTargetSdkVersion?: string, selectByName?: boolean, ): Promise { const { prompt } = await import('prompts'); @@ -408,6 +409,10 @@ export async function promptForPlatformTarget( const targetID = selectedTarget.trim(); const target = targets.find((t) => { if (selectByName === true) { + if (selectedTargetSdkVersion) { + return t.name === targetID && t.sdkVersion === selectedTargetSdkVersion; + } + return t.name === targetID; } @@ -417,7 +422,8 @@ export async function promptForPlatformTarget( if (!target) { if (selectByName) { fatal( - `Invalid target name: ${c.input(targetID)}.\n` + `Valid targets are: ${targets.map((t) => t.name).join(', ')}`, + `Invalid target name: ${c.input(targetID)}.\n` + + `Valid targets are: ${targets.map((t) => `${t.name} [${t.sdkVersion}]`).join(', ')}`, ); } fatal(`Invalid target ID: ${c.input(targetID)}.\n` + `Valid targets are: ${targets.map((t) => t.id).join(', ')}`); diff --git a/cli/src/index.ts b/cli/src/index.ts index f41260a53..74fae1643 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -235,6 +235,7 @@ export function runProgram(config: Config): void { .addOption(new Option('--json').hideHelp()) .option('--target ', 'use a specific target') .option('--target-name ', 'use a specific target by name') + .option('--target-name-sdk-version ', 'use a specific sdk version when using --target-name') .option('--no-sync', `do not run ${c.input('sync')}`) .option('--forwardPorts ', 'Automatically run "adb reverse" for better live-reloading support') .option('-l, --live-reload', 'Enable Live Reload') @@ -254,6 +255,7 @@ export function runProgram(config: Config): void { json, target, targetName, + targetNameSdkVersion, sync, forwardPorts, liveReload, @@ -270,6 +272,7 @@ export function runProgram(config: Config): void { json, target, targetName, + targetNameSdkVersion, sync, forwardPorts, liveReload, diff --git a/cli/src/ios/run.ts b/cli/src/ios/run.ts index 4a6de8d0f..13a031f39 100644 --- a/cli/src/ios/run.ts +++ b/cli/src/ios/run.ts @@ -16,6 +16,7 @@ export async function runIOS( { target: selectedTarget, targetName: selectedTargetName, + targetNameSdkVersion: selectedTargetSdkVersion, scheme: selectedScheme, configuration: selectedConfiguration, }: RunCommandOptions, @@ -23,6 +24,7 @@ export async function runIOS( const target = await promptForPlatformTarget( await getPlatformTargets('ios'), selectedTarget ?? selectedTargetName, + selectedTargetSdkVersion, selectedTargetName !== undefined, ); diff --git a/cli/src/tasks/run.ts b/cli/src/tasks/run.ts index 84da99932..97413cb09 100644 --- a/cli/src/tasks/run.ts +++ b/cli/src/tasks/run.ts @@ -27,6 +27,7 @@ export interface RunCommandOptions { json?: boolean; target?: string; targetName?: string; + targetNameSdkVersion?: string; sync?: boolean; forwardPorts?: string; liveReload?: boolean; From eadeb91d596082a5e9cbef60eb20ba8dcf78d2b4 Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Tue, 11 Nov 2025 15:54:44 -0600 Subject: [PATCH 05/10] adding examples to option description --- cli/src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cli/src/index.ts b/cli/src/index.ts index 74fae1643..999fb0c1a 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -235,7 +235,10 @@ export function runProgram(config: Config): void { .addOption(new Option('--json').hideHelp()) .option('--target ', 'use a specific target') .option('--target-name ', 'use a specific target by name') - .option('--target-name-sdk-version ', 'use a specific sdk version when using --target-name') + .option( + '--target-name-sdk-version ', + 'use a specific sdk version when using --target-name, ex: 26.0 (for iOS 26) or 35 (for Android API 35)', + ) .option('--no-sync', `do not run ${c.input('sync')}`) .option('--forwardPorts ', 'Automatically run "adb reverse" for better live-reloading support') .option('-l, --live-reload', 'Enable Live Reload') From e870cefc283fd5945f9aab7beed93b0c896e941a Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Wed, 12 Nov 2025 10:26:46 -0600 Subject: [PATCH 06/10] Improving valid target list display --- cli/src/common.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/src/common.ts b/cli/src/common.ts index ee70893c1..da1eb9a96 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -423,10 +423,10 @@ export async function promptForPlatformTarget( if (selectByName) { fatal( `Invalid target name: ${c.input(targetID)}.\n` + - `Valid targets are: ${targets.map((t) => `${t.name} [${t.sdkVersion}]`).join(', ')}`, + `Valid targets are:\n ${targets.map((t) => `${t.name} [${t.sdkVersion}]`).join('\n')}`, ); } - fatal(`Invalid target ID: ${c.input(targetID)}.\n` + `Valid targets are: ${targets.map((t) => t.id).join(', ')}`); + fatal(`Invalid target ID: ${c.input(targetID)}.\n` + `Valid targets are:\n ${targets.map((t) => t.id).join('\n')}`); } return target; From c74442048ab55f6dbb6d7e51395d659d67040d46 Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Wed, 12 Nov 2025 10:55:18 -0600 Subject: [PATCH 07/10] Use target name or model --- cli/src/common.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cli/src/common.ts b/cli/src/common.ts index da1eb9a96..e646f94f1 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -409,11 +409,13 @@ export async function promptForPlatformTarget( const targetID = selectedTarget.trim(); const target = targets.find((t) => { if (selectByName === true) { + const name = t.name ?? t.model; + if (selectedTargetSdkVersion) { - return t.name === targetID && t.sdkVersion === selectedTargetSdkVersion; + return name === targetID && t.sdkVersion === selectedTargetSdkVersion; } - return t.name === targetID; + return name === targetID; } return t.id === targetID; From d2f559ee18c1d0af5be26b1630b5d5cc529a6520 Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Wed, 12 Nov 2025 11:03:49 -0600 Subject: [PATCH 08/10] =?UTF-8?q?Stripping=20=E2=80=9Csmart=20quotes?= =?UTF-8?q?=E2=80=9D=20from=20device=20name=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/src/common.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cli/src/common.ts b/cli/src/common.ts index e646f94f1..617a576e4 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -409,7 +409,10 @@ export async function promptForPlatformTarget( const targetID = selectedTarget.trim(); const target = targets.find((t) => { if (selectByName === true) { - const name = t.name ?? t.model; + let name = t.name ?? t.model; + if (name) { + name = name.replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"'); + } if (selectedTargetSdkVersion) { return name === targetID && t.sdkVersion === selectedTargetSdkVersion; From 6c09c2ea679ceae1755e8c64f9f7324afc34b1af Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Wed, 12 Nov 2025 11:11:39 -0600 Subject: [PATCH 09/10] Clarifying invalid target name and sdk version --- cli/src/common.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cli/src/common.ts b/cli/src/common.ts index 617a576e4..3eff7c9aa 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -426,8 +426,12 @@ export async function promptForPlatformTarget( if (!target) { if (selectByName) { + let invalidTargetName = targetID; + if (selectedTargetSdkVersion) { + invalidTargetName += ` [${selectedTargetSdkVersion}]`; + } fatal( - `Invalid target name: ${c.input(targetID)}.\n` + + `Invalid target name: ${c.input(invalidTargetName)}.\n` + `Valid targets are:\n ${targets.map((t) => `${t.name} [${t.sdkVersion}]`).join('\n')}`, ); } From bbf00d6bc9662576dd0023f44ce9da01d5ec7ebc Mon Sep 17 00:00:00 2001 From: Joseph Pender Date: Wed, 12 Nov 2025 13:13:12 -0600 Subject: [PATCH 10/10] More tweaks --- cli/src/common.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/src/common.ts b/cli/src/common.ts index 3eff7c9aa..dbd4d629d 100644 --- a/cli/src/common.ts +++ b/cli/src/common.ts @@ -411,6 +411,8 @@ export async function promptForPlatformTarget( if (selectByName === true) { let name = t.name ?? t.model; if (name) { + // Apple device names may have "smart quotes" in the name, + // strip them and replace them with the "straight" versions name = name.replace(/[\u2018\u2019]/g, "'").replace(/[\u201C\u201D]/g, '"'); } @@ -432,7 +434,7 @@ export async function promptForPlatformTarget( } fatal( `Invalid target name: ${c.input(invalidTargetName)}.\n` + - `Valid targets are:\n ${targets.map((t) => `${t.name} [${t.sdkVersion}]`).join('\n')}`, + `Valid targets are:\n ${targets.map((t) => `${t.name ?? t.model} [${t.sdkVersion}]`).join('\n')}`, ); } fatal(`Invalid target ID: ${c.input(targetID)}.\n` + `Valid targets are:\n ${targets.map((t) => t.id).join('\n')}`);