use cargo_mobile2::{
android::target::Target,
opts::{FilterLevel, NoiseLevel, Profile},
target::TargetTrait,
};
use clap::{ArgAction, Parser};
use std::path::PathBuf;
use super::{configure_cargo, device_prompt, env};
use crate::{
error::Context,
helpers::config::ConfigMetadata,
interface::{DevProcess, WatcherOptions},
mobile::{DevChild, TargetDevice},
ConfigValue, Result,
};
#[derive(Debug, Clone, Parser)]
#[clap(
about = "Run your app in production mode on Android",
long_about = "Run your app in production mode on Android. It makes use of the `build.frontendDist` property from your `tauri.conf.json` file. It also runs your `build.beforeBuildCommand` which usually builds your frontend into `build.frontendDist`."
)]
pub struct Options {
#[clap(short, long)]
pub release: bool,
#[clap(short, long, action = ArgAction::Append, num_args(0..), value_delimiter = ',')]
pub features: Vec<String>,
#[clap(short, long)]
pub config: Vec<ConfigValue>,
#[clap(long)]
pub no_watch: bool,
#[clap(long)]
pub additional_watch_folders: Vec<PathBuf>,
#[clap(short, long)]
pub open: bool,
pub device: Option<String>,
#[clap(last(true))]
pub args: Vec<String>,
#[clap(long)]
pub ignore_version_mismatches: bool,
}
pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> {
let mut env = env(false)?;
let device = if options.open {
None
} else {
match device_prompt(&env, options.device.as_deref()) {
Ok(d) => Some(d),
Err(e) => {
log::error!("{e}");
None
}
}
};
let dirs = crate::helpers::app_paths::resolve_dirs();
let mut tauri_config = crate::helpers::config::get_config(
tauri_utils::platform::Target::Android,
&options
.config
.iter()
.map(|conf| &conf.0)
.collect::<Vec<_>>(),
dirs.tauri,
)?;
let mut built_application = super::build::run(
super::build::Options {
debug: !options.release,
targets: device.as_ref().map(|d| {
vec![Target::all()
.iter()
.find(|(_key, t)| t.arch == d.target().arch)
.map(|(key, _t)| key.to_string())
.expect("Target not found")]
}),
features: options.features,
config: options.config.clone(),
split_per_abi: true,
apk: false,
aab: false,
skip_bundle: false,
open: options.open,
ci: false,
args: options.args,
ignore_version_mismatches: options.ignore_version_mismatches,
target_device: device.as_ref().map(|d| TargetDevice {
id: d.serial_no().to_string(),
name: d.name().to_string(),
}),
},
noise_level,
&dirs,
&tauri_config,
)?;
configure_cargo(&mut env, &built_application.config)?;
if let Some(device) = device {
let config = built_application.config.clone();
let release = options.release;
let runner = move |_tauri_config: &ConfigMetadata| {
device
.run(
&config,
&env,
noise_level,
if !release {
Profile::Debug
} else {
Profile::Release
},
Some(match noise_level {
NoiseLevel::Polite => FilterLevel::Info,
NoiseLevel::LoudAndProud => FilterLevel::Debug,
NoiseLevel::FranklyQuitePedantic => FilterLevel::Verbose,
}),
false,
false,
".MainActivity".into(),
)
.map(|c| Box::new(DevChild::new(c)) as Box<dyn DevProcess + Send>)
.context("failed to run Android app")
};
if options.no_watch {
runner(&tauri_config)?;
} else {
built_application.interface.watch(
&mut tauri_config,
WatcherOptions {
config: options.config,
additional_watch_folders: options.additional_watch_folders,
},
runner,
&dirs,
)?;
}
}
Ok(())
}