mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-22 10:11:32 +03:00
feat(cli): add option to run on specific Android emulator/device (#5093)
This commit is contained in:
parent
e22d21beaf
commit
82e8751ae8
2
tooling/cli/Cargo.lock
generated
2
tooling/cli/Cargo.lock
generated
@ -293,7 +293,7 @@ checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "cargo-mobile"
|
name = "cargo-mobile"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/tauri-apps/cargo-mobile?branch=dev#228f0eb83ccbc7bfeb0103d2f68b6664691a289d"
|
source = "git+https://github.com/tauri-apps/cargo-mobile?branch=dev#909edf9337ec0cb42c76e0a34af61e99b15ccfe0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cocoa",
|
"cocoa",
|
||||||
"colored 1.9.3",
|
"colored 1.9.3",
|
||||||
|
@ -7,6 +7,7 @@ use cargo_mobile::{
|
|||||||
adb,
|
adb,
|
||||||
config::{Config as AndroidConfig, Metadata as AndroidMetadata, Raw as RawAndroidConfig},
|
config::{Config as AndroidConfig, Metadata as AndroidMetadata, Raw as RawAndroidConfig},
|
||||||
device::Device,
|
device::Device,
|
||||||
|
emulator,
|
||||||
env::Env,
|
env::Env,
|
||||||
target::Target,
|
target::Target,
|
||||||
},
|
},
|
||||||
@ -17,7 +18,11 @@ use cargo_mobile::{
|
|||||||
util::prompt,
|
util::prompt,
|
||||||
};
|
};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use std::env::set_var;
|
use std::{
|
||||||
|
env::set_var,
|
||||||
|
thread::{sleep, spawn},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
ensure_init, get_app,
|
ensure_init, get_app,
|
||||||
@ -136,11 +141,21 @@ fn delete_codegen_vars() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<adb::device_list::Error>> {
|
fn adb_device_prompt<'a>(
|
||||||
|
env: &'_ Env,
|
||||||
|
target: Option<&str>,
|
||||||
|
) -> Result<Device<'a>, PromptError<adb::device_list::Error>> {
|
||||||
let device_list =
|
let device_list =
|
||||||
adb::device_list(env).map_err(|cause| PromptError::detection_failed("Android", cause))?;
|
adb::device_list(env).map_err(|cause| PromptError::detection_failed("Android", cause))?;
|
||||||
if !device_list.is_empty() {
|
if !device_list.is_empty() {
|
||||||
let index = if device_list.len() > 1 {
|
let index = if device_list.len() > 1 {
|
||||||
|
if let Some(t) = target {
|
||||||
|
let t = t.to_lowercase();
|
||||||
|
device_list
|
||||||
|
.iter()
|
||||||
|
.position(|d| d.name().to_lowercase().starts_with(&t))
|
||||||
|
.unwrap_or_default()
|
||||||
|
} else {
|
||||||
prompt::list(
|
prompt::list(
|
||||||
concat!("Detected ", "Android", " devices"),
|
concat!("Detected ", "Android", " devices"),
|
||||||
device_list.iter(),
|
device_list.iter(),
|
||||||
@ -149,6 +164,7 @@ fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<adb::device
|
|||||||
"Device",
|
"Device",
|
||||||
)
|
)
|
||||||
.map_err(|cause| PromptError::prompt_failed("Android", cause))?
|
.map_err(|cause| PromptError::prompt_failed("Android", cause))?
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
@ -164,8 +180,67 @@ fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, PromptError<adb::device
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emulator_prompt(
|
||||||
|
env: &'_ Env,
|
||||||
|
target: Option<&str>,
|
||||||
|
) -> Result<emulator::Emulator, PromptError<adb::device_list::Error>> {
|
||||||
|
let emulator_list = emulator::avd_list(env).unwrap_or_default();
|
||||||
|
if emulator_list.is_empty() {
|
||||||
|
Err(PromptError::none_detected("Android emulator"))
|
||||||
|
} else {
|
||||||
|
let index = if emulator_list.len() > 1 {
|
||||||
|
if let Some(t) = target {
|
||||||
|
let t = t.to_lowercase();
|
||||||
|
emulator_list
|
||||||
|
.iter()
|
||||||
|
.position(|d| d.name().to_lowercase().starts_with(&t))
|
||||||
|
.unwrap_or_default()
|
||||||
|
} else {
|
||||||
|
prompt::list(
|
||||||
|
concat!("Detected ", "Android", " emulators"),
|
||||||
|
emulator_list.iter(),
|
||||||
|
"emulator",
|
||||||
|
None,
|
||||||
|
"Emulator",
|
||||||
|
)
|
||||||
|
.map_err(|cause| PromptError::prompt_failed("Android emulator", cause))?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(emulator_list.iter().nth(index).cloned().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn device_prompt<'a>(
|
||||||
|
env: &'_ Env,
|
||||||
|
target: Option<&str>,
|
||||||
|
) -> Result<Device<'a>, PromptError<adb::device_list::Error>> {
|
||||||
|
if let Ok(device) = adb_device_prompt(env, target) {
|
||||||
|
Ok(device)
|
||||||
|
} else {
|
||||||
|
let emulator = emulator_prompt(env, target)?;
|
||||||
|
let handle = emulator.start(env).map_err(|e| {
|
||||||
|
PromptError::prompt_failed(
|
||||||
|
"Android emulator",
|
||||||
|
std::io::Error::new(std::io::ErrorKind::Other, e.to_string()),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
spawn(move || {
|
||||||
|
let _ = handle.wait();
|
||||||
|
});
|
||||||
|
loop {
|
||||||
|
sleep(Duration::from_secs(2));
|
||||||
|
if let Ok(device) = adb_device_prompt(env, Some(emulator.name())) {
|
||||||
|
return Ok(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> {
|
fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> {
|
||||||
device_prompt(env).map(|device| device.target()).ok()
|
device_prompt(env, None).map(|device| device.target()).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_and_wait(config: &AndroidConfig, env: &Env) -> ! {
|
fn open_and_wait(config: &AndroidConfig, env: &Env) -> ! {
|
||||||
@ -174,6 +249,6 @@ fn open_and_wait(config: &AndroidConfig, env: &Env) -> ! {
|
|||||||
log::error!("{}", e);
|
log::error!("{}", e);
|
||||||
}
|
}
|
||||||
loop {
|
loop {
|
||||||
std::thread::sleep(std::time::Duration::from_secs(24 * 60 * 60));
|
sleep(Duration::from_secs(24 * 60 * 60));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,18 @@ use cargo_mobile::{
|
|||||||
adb,
|
adb,
|
||||||
config::{Config as AndroidConfig, Metadata as AndroidMetadata},
|
config::{Config as AndroidConfig, Metadata as AndroidMetadata},
|
||||||
device::RunError as DeviceRunError,
|
device::RunError as DeviceRunError,
|
||||||
|
emulator,
|
||||||
env::Env,
|
env::Env,
|
||||||
},
|
},
|
||||||
config::app::App,
|
config::app::App,
|
||||||
opts::{NoiseLevel, Profile},
|
opts::{NoiseLevel, Profile},
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::env::set_var;
|
use std::{
|
||||||
|
env::set_var,
|
||||||
|
thread::{sleep, spawn},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
const WEBVIEW_CLIENT_CLASS_EXTENSION: &str = "
|
const WEBVIEW_CLIENT_CLASS_EXTENSION: &str = "
|
||||||
@android.annotation.SuppressLint(\"WebViewClientOnReceivedSslError\")
|
@android.annotation.SuppressLint(\"WebViewClientOnReceivedSslError\")
|
||||||
@ -50,6 +55,8 @@ pub struct Options {
|
|||||||
/// Open Android Studio instead of trying to run on a connected device
|
/// Open Android Studio instead of trying to run on a connected device
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub open: bool,
|
pub open: bool,
|
||||||
|
/// Runs on the given device name
|
||||||
|
pub device: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Options> for crate::dev::Options {
|
impl From<Options> for crate::dev::Options {
|
||||||
@ -112,9 +119,29 @@ fn run_dev(
|
|||||||
let env = env()?;
|
let env = env()?;
|
||||||
init_dot_cargo(app, Some((&env, config)))?;
|
init_dot_cargo(app, Some((&env, config)))?;
|
||||||
|
|
||||||
|
if let Some(device) = &options.device {
|
||||||
|
let emulators = emulator::avd_list(&env).unwrap_or_default();
|
||||||
|
for emulator in emulators {
|
||||||
|
if emulator
|
||||||
|
.name()
|
||||||
|
.to_lowercase()
|
||||||
|
.starts_with(&device.to_lowercase())
|
||||||
|
{
|
||||||
|
log::info!("Starting emulator {}", emulator.name());
|
||||||
|
let handle = emulator.start(&env)?;
|
||||||
|
spawn(move || {
|
||||||
|
let _ = handle.wait();
|
||||||
|
});
|
||||||
|
sleep(Duration::from_secs(3));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let open = options.open;
|
let open = options.open;
|
||||||
let exit_on_panic = options.exit_on_panic;
|
let exit_on_panic = options.exit_on_panic;
|
||||||
let no_watch = options.no_watch;
|
let no_watch = options.no_watch;
|
||||||
|
let device = options.device;
|
||||||
interface.mobile_dev(
|
interface.mobile_dev(
|
||||||
MobileOptions {
|
MobileOptions {
|
||||||
debug: true,
|
debug: true,
|
||||||
@ -135,7 +162,14 @@ fn run_dev(
|
|||||||
if open {
|
if open {
|
||||||
open_and_wait(config, &env)
|
open_and_wait(config, &env)
|
||||||
} else {
|
} else {
|
||||||
match run(options, config, &env, metadata, noise_level) {
|
match run(
|
||||||
|
device.as_deref(),
|
||||||
|
options,
|
||||||
|
config,
|
||||||
|
&env,
|
||||||
|
metadata,
|
||||||
|
noise_level,
|
||||||
|
) {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
crate::dev::wait_dev_process(c.clone(), move |status, reason| {
|
crate::dev::wait_dev_process(c.clone(), move |status, reason| {
|
||||||
crate::dev::on_app_exit(status, reason, exit_on_panic, no_watch)
|
crate::dev::on_app_exit(status, reason, exit_on_panic, no_watch)
|
||||||
@ -162,6 +196,7 @@ enum RunError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
|
device: Option<&str>,
|
||||||
options: MobileOptions,
|
options: MobileOptions,
|
||||||
config: &AndroidConfig,
|
config: &AndroidConfig,
|
||||||
env: &Env,
|
env: &Env,
|
||||||
@ -176,7 +211,7 @@ fn run(
|
|||||||
|
|
||||||
let build_app_bundle = metadata.asset_packs().is_some();
|
let build_app_bundle = metadata.asset_packs().is_some();
|
||||||
|
|
||||||
device_prompt(env)
|
device_prompt(env, device)
|
||||||
.map_err(RunError::FailedToPromptForDevice)?
|
.map_err(RunError::FailedToPromptForDevice)?
|
||||||
.run(
|
.run(
|
||||||
config,
|
config,
|
||||||
|
Loading…
Reference in New Issue
Block a user