mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-02-06 11:22:04 +00:00
feat(cli): enhance Android dev port forwarding, use host IP for android devices, closes #11137 (#11185)
* feat(cli): enhance Android dev port forwarding, closes #11137 this changes the `android dev` port forwarding (that is actually handled by the `android-studio-script` command - triggered by our Gradle plugin) with some enhancements: - make the whole process more resilient by checking if the port was actually forwarded and rerunning the `adb reverse` command until it tells us the forward is ready - if the `adb devices` list is empty, retry a few times (waiting a few seconds) to tolerate devices being booted - slows down "raw builds" (Build Project Android Studio menu for instance) that shouldn't happen often anyway - if you're running `android dev` you're usually running the app on a device instead of simply testing builds * use host IP to run on android physical device
This commit is contained in:
parent
6cfe7edf63
commit
a08e6ffa6f
6
.changes/enhance-android-port-forwarding.md
Normal file
6
.changes/enhance-android-port-forwarding.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
'tauri-cli': 'patch:enhance'
|
||||
'@tauri-apps/cli': 'patch:enhance'
|
||||
---
|
||||
|
||||
Enhance port forwarding on `android dev` to be more resilient and tolerate delays when booting up devices.
|
||||
@ -6,6 +6,7 @@ use super::{detect_target_ok, ensure_init, env, get_app, get_config, read_option
|
||||
use crate::{
|
||||
helpers::config::get as get_tauri_config,
|
||||
interface::{AppInterface, Interface},
|
||||
mobile::CliOptions,
|
||||
Result,
|
||||
};
|
||||
use clap::{ArgAction, Parser};
|
||||
@ -87,36 +88,17 @@ pub fn command(options: Options) -> Result<()> {
|
||||
.dev_url
|
||||
.clone();
|
||||
|
||||
if let Some(port) = dev_url.and_then(|url| url.port_or_known_default()) {
|
||||
let forward = format!("tcp:{port}");
|
||||
log::info!("Forwarding port {port} with adb");
|
||||
if let Some(url) = dev_url {
|
||||
let localhost = match url.host() {
|
||||
Some(url::Host::Domain(d)) => d == "localhost",
|
||||
Some(url::Host::Ipv4(i)) => i == std::net::Ipv4Addr::LOCALHOST,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
let devices = adb::device_list(&env).unwrap_or_default();
|
||||
|
||||
// clear port forwarding for all devices
|
||||
for device in &devices {
|
||||
remove_adb_reverse(&env, device.serial_no(), &forward);
|
||||
}
|
||||
|
||||
// if there's a known target, we should force use it
|
||||
if let Some(target_device) = &cli_options.target_device {
|
||||
run_adb_reverse(&env, &target_device.id, &forward, &forward).with_context(|| {
|
||||
format!(
|
||||
"failed to forward port with adb, is the {} device connected?",
|
||||
target_device.name,
|
||||
)
|
||||
})?;
|
||||
} else if devices.len() == 1 {
|
||||
let device = devices.first().unwrap();
|
||||
run_adb_reverse(&env, device.serial_no(), &forward, &forward).with_context(|| {
|
||||
format!(
|
||||
"failed to forward port with adb, is the {} device connected?",
|
||||
device.name(),
|
||||
)
|
||||
})?;
|
||||
} else if devices.len() > 1 {
|
||||
anyhow::bail!("Multiple Android devices are connected ({}), please disconnect devices you do not intend to use so Tauri can determine which to use",
|
||||
devices.iter().map(|d| d.name()).collect::<Vec<_>>().join(", "));
|
||||
if localhost {
|
||||
if let Some(port) = url.port_or_known_default() {
|
||||
adb_forward_port(port, &env, &cli_options)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,6 +162,102 @@ fn validate_lib(path: &Path) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn adb_forward_port(
|
||||
port: u16,
|
||||
env: &cargo_mobile2::android::env::Env,
|
||||
cli_options: &CliOptions,
|
||||
) -> Result<()> {
|
||||
let forward = format!("tcp:{port}");
|
||||
log::info!("Forwarding port {port} with adb");
|
||||
|
||||
let mut devices = adb::device_list(env).unwrap_or_default();
|
||||
// if we could not detect any running device, let's wait a few seconds, it might be booting up
|
||||
if devices.is_empty() {
|
||||
log::warn!(
|
||||
"ADB device list is empty, waiting a few seconds to see if there's any booting device..."
|
||||
);
|
||||
|
||||
let max = 5;
|
||||
let mut count = 0;
|
||||
loop {
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
|
||||
devices = adb::device_list(env).unwrap_or_default();
|
||||
if !devices.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
count += 1;
|
||||
if count == max {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let target_device = if let Some(target_device) = &cli_options.target_device {
|
||||
Some((target_device.id.clone(), target_device.name.clone()))
|
||||
} else if devices.len() == 1 {
|
||||
let device = devices.first().unwrap();
|
||||
Some((device.serial_no().to_string(), device.name().to_string()))
|
||||
} else if devices.len() > 1 {
|
||||
anyhow::bail!("Multiple Android devices are connected ({}), please disconnect devices you do not intend to use so Tauri can determine which to use",
|
||||
devices.iter().map(|d| d.name()).collect::<Vec<_>>().join(", "));
|
||||
} else {
|
||||
// when building the app without running to a device, we might have an empty devices list
|
||||
None
|
||||
};
|
||||
|
||||
if let Some((target_device_serial_no, target_device_name)) = target_device {
|
||||
let mut already_forwarded = false;
|
||||
|
||||
// clear port forwarding for all devices
|
||||
for device in &devices {
|
||||
let reverse_list_output = adb_reverse_list(env, device.serial_no())?;
|
||||
|
||||
// check if the device has the port forwarded
|
||||
if String::from_utf8_lossy(&reverse_list_output.stdout).contains(&forward) {
|
||||
// device matches our target, we can skip forwarding
|
||||
if device.serial_no() == target_device_serial_no {
|
||||
log::debug!(
|
||||
"device {} already has the forward for {}",
|
||||
device.name(),
|
||||
forward
|
||||
);
|
||||
already_forwarded = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if there's a known target, we should forward the port to it
|
||||
if already_forwarded {
|
||||
log::info!("{forward} already forwarded to {target_device_name}");
|
||||
} else {
|
||||
loop {
|
||||
run_adb_reverse(env, &target_device_serial_no, &forward, &forward).with_context(|| {
|
||||
format!("failed to forward port with adb, is the {target_device_name} device connected?",)
|
||||
})?;
|
||||
|
||||
let reverse_list_output = adb_reverse_list(env, &target_device_serial_no)?;
|
||||
// wait and retry until the port has actually been forwarded
|
||||
if String::from_utf8_lossy(&reverse_list_output.stdout).contains(&forward) {
|
||||
break;
|
||||
} else {
|
||||
log::warn!(
|
||||
"waiting for the port to be forwarded to {}...",
|
||||
target_device_name
|
||||
);
|
||||
std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::warn!("no running devices detected with ADB; skipping port forwarding");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_adb_reverse(
|
||||
env: &cargo_mobile2::android::env::Env,
|
||||
device_serial_no: &str,
|
||||
@ -193,15 +271,13 @@ fn run_adb_reverse(
|
||||
.run()
|
||||
}
|
||||
|
||||
fn remove_adb_reverse(
|
||||
fn adb_reverse_list(
|
||||
env: &cargo_mobile2::android::env::Env,
|
||||
device_serial_no: &str,
|
||||
remote: &str,
|
||||
) {
|
||||
// ignore errors in case the port is not forwarded
|
||||
let _ = adb::adb(env, ["-s", device_serial_no, "reverse", "--remove", remote])
|
||||
) -> std::io::Result<std::process::Output> {
|
||||
adb::adb(env, ["-s", device_serial_no, "reverse", "--list"])
|
||||
.stdin_file(os_pipe::dup_stdin().unwrap())
|
||||
.stdout_file(os_pipe::dup_stdout().unwrap())
|
||||
.stderr_file(os_pipe::dup_stdout().unwrap())
|
||||
.run();
|
||||
.stdout_capture()
|
||||
.stderr_capture()
|
||||
.run()
|
||||
}
|
||||
|
||||
@ -14,7 +14,9 @@ use crate::{
|
||||
flock,
|
||||
},
|
||||
interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions},
|
||||
mobile::{write_options, CliOptions, DevChild, DevProcess, TargetDevice},
|
||||
mobile::{
|
||||
use_network_address_for_dev_url, write_options, CliOptions, DevChild, DevProcess, TargetDevice,
|
||||
},
|
||||
ConfigValue, Result,
|
||||
};
|
||||
use clap::{ArgAction, Parser};
|
||||
@ -31,7 +33,7 @@ use cargo_mobile2::{
|
||||
target::TargetTrait,
|
||||
};
|
||||
|
||||
use std::env::set_current_dir;
|
||||
use std::{env::set_current_dir, net::IpAddr};
|
||||
|
||||
#[derive(Debug, Clone, Parser)]
|
||||
#[clap(
|
||||
@ -62,6 +64,23 @@ pub struct Options {
|
||||
pub open: bool,
|
||||
/// Runs on the given device name
|
||||
pub device: Option<String>,
|
||||
/// Force prompting for an IP to use to connect to the dev server on mobile.
|
||||
#[clap(long)]
|
||||
pub force_ip_prompt: bool,
|
||||
/// Use the public network address for the development server.
|
||||
/// If an actual address it provided, it is used instead of prompting to pick one.
|
||||
///
|
||||
/// This option is particularly useful along the `--open` flag when you intend on running on a physical device.
|
||||
///
|
||||
/// This replaces the devUrl configuration value to match the public network address host,
|
||||
/// it is your responsibility to set up your development server to listen on this address
|
||||
/// by using 0.0.0.0 as host for instance.
|
||||
///
|
||||
/// When this is set or when running on an iOS device the CLI sets the `TAURI_DEV_HOST`
|
||||
/// environment variable so you can check this on your framework's configuration to expose the development server
|
||||
/// on the public network address.
|
||||
#[clap(long)]
|
||||
pub host: Option<Option<IpAddr>>,
|
||||
/// Disable the built-in dev server for static files.
|
||||
#[clap(long)]
|
||||
pub no_dev_server: bool,
|
||||
@ -177,6 +196,16 @@ fn run_dev(
|
||||
metadata: &AndroidMetadata,
|
||||
noise_level: NoiseLevel,
|
||||
) -> Result<()> {
|
||||
// when running on an actual device we must use the network IP
|
||||
if options.host.is_some()
|
||||
|| device
|
||||
.as_ref()
|
||||
.map(|device| !device.serial_no().starts_with("emulator"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?;
|
||||
}
|
||||
|
||||
crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?;
|
||||
|
||||
let interface_options = InterfaceOptions {
|
||||
|
||||
@ -10,11 +10,11 @@ use crate::{
|
||||
dev::Options as DevOptions,
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{get as get_tauri_config, reload as reload_config, ConfigHandle},
|
||||
config::{get as get_tauri_config, ConfigHandle},
|
||||
flock,
|
||||
},
|
||||
interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions},
|
||||
mobile::{write_options, CliOptions, DevChild, DevProcess},
|
||||
mobile::{use_network_address_for_dev_url, write_options, CliOptions, DevChild, DevProcess},
|
||||
ConfigValue, Result,
|
||||
};
|
||||
use clap::{ArgAction, Parser};
|
||||
@ -29,11 +29,7 @@ use cargo_mobile2::{
|
||||
opts::{NoiseLevel, Profile},
|
||||
};
|
||||
|
||||
use std::{
|
||||
env::set_current_dir,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
sync::OnceLock,
|
||||
};
|
||||
use std::{env::set_current_dir, net::IpAddr};
|
||||
|
||||
const PHYSICAL_IPHONE_DEV_WARNING: &str = "To develop on physical phones you need the `--host` option (not required for Simulators). See the documentation for more information: https://v2.tauri.app/develop/#development-server";
|
||||
|
||||
@ -82,7 +78,7 @@ pub struct Options {
|
||||
/// This option is particularly useful along the `--open` flag when you intend on running on a physical device.
|
||||
///
|
||||
/// This replaces the devUrl configuration value to match the public network address host,
|
||||
/// it is your responsability to set up your development server to listen on this address
|
||||
/// it is your responsibility to set up your development server to listen on this address
|
||||
/// by using 0.0.0.0 as host for instance.
|
||||
///
|
||||
/// When this is set or when running on an iOS device the CLI sets the `TAURI_DEV_HOST`
|
||||
@ -222,142 +218,10 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> {
|
||||
)
|
||||
}
|
||||
|
||||
fn local_ip_address(force: bool) -> &'static IpAddr {
|
||||
static LOCAL_IP: OnceLock<IpAddr> = OnceLock::new();
|
||||
LOCAL_IP.get_or_init(|| {
|
||||
let prompt_for_ip = || {
|
||||
let addresses: Vec<IpAddr> = local_ip_address::list_afinet_netifas()
|
||||
.expect("failed to list networks")
|
||||
.into_iter()
|
||||
.map(|(_, ipaddr)| ipaddr)
|
||||
.filter(|ipaddr| match ipaddr {
|
||||
IpAddr::V4(i) => i != &Ipv4Addr::LOCALHOST,
|
||||
IpAddr::V6(i) => i.to_string().ends_with("::2"),
|
||||
|
||||
})
|
||||
.collect();
|
||||
match addresses.len() {
|
||||
0 => panic!("No external IP detected."),
|
||||
1 => {
|
||||
let ipaddr = addresses.first().unwrap();
|
||||
*ipaddr
|
||||
}
|
||||
_ => {
|
||||
let selected = dialoguer::Select::with_theme(&dialoguer::theme::ColorfulTheme::default())
|
||||
.with_prompt(
|
||||
"Failed to detect external IP, What IP should we use to access your development server?",
|
||||
)
|
||||
.items(&addresses)
|
||||
.default(0)
|
||||
.interact()
|
||||
.expect("failed to select external IP");
|
||||
*addresses.get(selected).unwrap()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let ip = if force {
|
||||
prompt_for_ip()
|
||||
} else {
|
||||
local_ip_address::local_ip().unwrap_or_else(|_| prompt_for_ip())
|
||||
};
|
||||
log::info!("Using {ip} to access the development server.");
|
||||
ip
|
||||
})
|
||||
}
|
||||
|
||||
fn use_network_address_for_dev_url(
|
||||
config: &ConfigHandle,
|
||||
options: &mut Options,
|
||||
dev_options: &mut DevOptions,
|
||||
) -> crate::Result<()> {
|
||||
let mut dev_url = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.dev_url
|
||||
.clone();
|
||||
|
||||
let ip = if let Some(url) = &mut dev_url {
|
||||
let localhost = match url.host() {
|
||||
Some(url::Host::Domain(d)) => d == "localhost",
|
||||
Some(url::Host::Ipv4(i)) => {
|
||||
i == std::net::Ipv4Addr::LOCALHOST || i == std::net::Ipv4Addr::UNSPECIFIED
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if localhost {
|
||||
let ip = options
|
||||
.host
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|| *local_ip_address(options.force_ip_prompt));
|
||||
log::info!(
|
||||
"Replacing devUrl host with {ip}. {}.",
|
||||
"If your frontend is not listening on that address, try configuring your development server to use the `TAURI_DEV_HOST` environment variable or 0.0.0.0 as host"
|
||||
);
|
||||
|
||||
*url = url::Url::parse(&format!(
|
||||
"{}://{}{}",
|
||||
url.scheme(),
|
||||
SocketAddr::new(ip, url.port_or_known_default().unwrap()),
|
||||
url.path()
|
||||
))?;
|
||||
|
||||
if let Some(c) = &mut options.config {
|
||||
if let Some(build) = c
|
||||
.0
|
||||
.as_object_mut()
|
||||
.and_then(|root| root.get_mut("build"))
|
||||
.and_then(|build| build.as_object_mut())
|
||||
{
|
||||
build.insert("devUrl".into(), url.to_string().into());
|
||||
}
|
||||
} else {
|
||||
let mut build = serde_json::Map::new();
|
||||
build.insert("devUrl".into(), url.to_string().into());
|
||||
|
||||
options
|
||||
.config
|
||||
.replace(crate::ConfigValue(serde_json::json!({
|
||||
"build": build
|
||||
})));
|
||||
}
|
||||
reload_config(options.config.as_ref().map(|c| &c.0))?;
|
||||
|
||||
Some(ip)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if !dev_options.no_dev_server {
|
||||
let ip = options
|
||||
.host
|
||||
.unwrap_or_default()
|
||||
.unwrap_or_else(|| *local_ip_address(options.force_ip_prompt));
|
||||
dev_options.host.replace(ip);
|
||||
Some(ip)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(ip) = ip {
|
||||
std::env::set_var("TAURI_DEV_HOST", ip.to_string());
|
||||
std::env::set_var("TRUNK_SERVE_ADDRESS", ip.to_string());
|
||||
if ip.is_ipv6() {
|
||||
// in this case we can't ping the server for some reason
|
||||
dev_options.no_dev_server_wait = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn run_dev(
|
||||
mut interface: AppInterface,
|
||||
mut options: Options,
|
||||
options: Options,
|
||||
mut dev_options: DevOptions,
|
||||
tauri_config: ConfigHandle,
|
||||
device: Option<Device>,
|
||||
@ -372,7 +236,7 @@ fn run_dev(
|
||||
.map(|device| !matches!(device.kind(), DeviceKind::Simulator))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
use_network_address_for_dev_url(&tauri_config, &mut options, &mut dev_options)?;
|
||||
use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?;
|
||||
}
|
||||
|
||||
crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?;
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
use crate::{
|
||||
helpers::{
|
||||
app_paths::tauri_dir,
|
||||
config::{Config as TauriConfig, ConfigHandle},
|
||||
config::{reload as reload_config, Config as TauriConfig, ConfigHandle},
|
||||
},
|
||||
interface::{AppInterface, AppSettings, DevProcess, Interface, Options as InterfaceOptions},
|
||||
ConfigValue,
|
||||
@ -32,12 +32,12 @@ use std::{
|
||||
ffi::OsString,
|
||||
fmt::Write,
|
||||
fs::{read_to_string, write},
|
||||
net::SocketAddr,
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||
path::PathBuf,
|
||||
process::{exit, ExitStatus},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
Arc,
|
||||
Arc, OnceLock,
|
||||
},
|
||||
};
|
||||
use tokio::runtime::Runtime;
|
||||
@ -166,6 +166,144 @@ impl Default for CliOptions {
|
||||
}
|
||||
}
|
||||
|
||||
fn local_ip_address(force: bool) -> &'static IpAddr {
|
||||
static LOCAL_IP: OnceLock<IpAddr> = OnceLock::new();
|
||||
LOCAL_IP.get_or_init(|| {
|
||||
let prompt_for_ip = || {
|
||||
let addresses: Vec<IpAddr> = local_ip_address::list_afinet_netifas()
|
||||
.expect("failed to list networks")
|
||||
.into_iter()
|
||||
.map(|(_, ipaddr)| ipaddr)
|
||||
.filter(|ipaddr| match ipaddr {
|
||||
IpAddr::V4(i) => i != &Ipv4Addr::LOCALHOST,
|
||||
IpAddr::V6(i) => i.to_string().ends_with("::2"),
|
||||
|
||||
})
|
||||
.collect();
|
||||
match addresses.len() {
|
||||
0 => panic!("No external IP detected."),
|
||||
1 => {
|
||||
let ipaddr = addresses.first().unwrap();
|
||||
*ipaddr
|
||||
}
|
||||
_ => {
|
||||
let selected = dialoguer::Select::with_theme(&dialoguer::theme::ColorfulTheme::default())
|
||||
.with_prompt(
|
||||
"Failed to detect external IP, What IP should we use to access your development server?",
|
||||
)
|
||||
.items(&addresses)
|
||||
.default(0)
|
||||
.interact()
|
||||
.expect("failed to select external IP");
|
||||
*addresses.get(selected).unwrap()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let ip = if force {
|
||||
prompt_for_ip()
|
||||
} else {
|
||||
local_ip_address::local_ip().unwrap_or_else(|_| prompt_for_ip())
|
||||
};
|
||||
log::info!("Using {ip} to access the development server.");
|
||||
ip
|
||||
})
|
||||
}
|
||||
|
||||
struct DevUrlConfig {
|
||||
no_dev_server_wait: bool,
|
||||
}
|
||||
|
||||
fn use_network_address_for_dev_url(
|
||||
config: &ConfigHandle,
|
||||
dev_options: &mut crate::dev::Options,
|
||||
force_ip_prompt: bool,
|
||||
) -> crate::Result<DevUrlConfig> {
|
||||
let mut dev_url = config
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.build
|
||||
.dev_url
|
||||
.clone();
|
||||
|
||||
let ip = if let Some(url) = &mut dev_url {
|
||||
let localhost = match url.host() {
|
||||
Some(url::Host::Domain(d)) => d == "localhost",
|
||||
Some(url::Host::Ipv4(i)) => {
|
||||
i == std::net::Ipv4Addr::LOCALHOST || i == std::net::Ipv4Addr::UNSPECIFIED
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if localhost {
|
||||
let ip = dev_options
|
||||
.host
|
||||
.unwrap_or_else(|| *local_ip_address(force_ip_prompt));
|
||||
log::info!(
|
||||
"Replacing devUrl host with {ip}. {}.",
|
||||
"If your frontend is not listening on that address, try configuring your development server to use the `TAURI_DEV_HOST` environment variable or 0.0.0.0 as host"
|
||||
);
|
||||
|
||||
*url = url::Url::parse(&format!(
|
||||
"{}://{}{}",
|
||||
url.scheme(),
|
||||
SocketAddr::new(ip, url.port_or_known_default().unwrap()),
|
||||
url.path()
|
||||
))?;
|
||||
|
||||
if let Some(c) = &mut dev_options.config {
|
||||
if let Some(build) = c
|
||||
.0
|
||||
.as_object_mut()
|
||||
.and_then(|root| root.get_mut("build"))
|
||||
.and_then(|build| build.as_object_mut())
|
||||
{
|
||||
build.insert("devUrl".into(), url.to_string().into());
|
||||
}
|
||||
} else {
|
||||
let mut build = serde_json::Map::new();
|
||||
build.insert("devUrl".into(), url.to_string().into());
|
||||
|
||||
dev_options
|
||||
.config
|
||||
.replace(crate::ConfigValue(serde_json::json!({
|
||||
"build": build
|
||||
})));
|
||||
}
|
||||
reload_config(dev_options.config.as_ref().map(|c| &c.0))?;
|
||||
|
||||
Some(ip)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if !dev_options.no_dev_server {
|
||||
let ip = dev_options
|
||||
.host
|
||||
.unwrap_or_else(|| *local_ip_address(force_ip_prompt));
|
||||
dev_options.host.replace(ip);
|
||||
Some(ip)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut dev_url_config = DevUrlConfig {
|
||||
no_dev_server_wait: false,
|
||||
};
|
||||
|
||||
if let Some(ip) = ip {
|
||||
std::env::set_var("TAURI_DEV_HOST", ip.to_string());
|
||||
std::env::set_var("TRUNK_SERVE_ADDRESS", ip.to_string());
|
||||
if ip.is_ipv6() {
|
||||
// in this case we can't ping the server for some reason
|
||||
dev_url_config.no_dev_server_wait = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(dev_url_config)
|
||||
}
|
||||
|
||||
fn env_vars() -> HashMap<String, OsString> {
|
||||
let mut vars = HashMap::new();
|
||||
vars.insert("RUST_LOG_STYLE".into(), "always".into());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user