From 67515ce812786f2bcb68866a0cd27f93ac3629da Mon Sep 17 00:00:00 2001 From: Andrew Voynov <37143421+Andrew15-5@users.noreply.github.com> Date: Sat, 1 Feb 2025 01:29:54 +0300 Subject: [PATCH] Allow to connect to the dev server from a physical Android device (#3634) * fix(android): now dev server just works on devices * fix: allow custom port for Android app development * refactor: simplified URL creation in LaunchBuilder --- packages/cli-config/src/lib.rs | 15 ++++++++++++--- packages/cli/src/serve/handle.rs | 29 +++++++++++++++++++++++++---- packages/cli/src/serve/server.rs | 17 +++++++++++++++++ packages/dioxus/src/launch.rs | 8 +------- 4 files changed, 55 insertions(+), 14 deletions(-) diff --git a/packages/cli-config/src/lib.rs b/packages/cli-config/src/lib.rs index 681443024..640f6d739 100644 --- a/packages/cli-config/src/lib.rs +++ b/packages/cli-config/src/lib.rs @@ -59,7 +59,8 @@ use std::{ pub const CLI_ENABLED_ENV: &str = "DIOXUS_CLI_ENABLED"; pub const SERVER_IP_ENV: &str = "IP"; pub const SERVER_PORT_ENV: &str = "PORT"; -pub const DEVSERVER_RAW_ADDR_ENV: &str = "DIOXUS_DEVSERVER_ADDR"; +pub const DEVSERVER_IP_ENV: &str = "DIOXUS_DEVSERVER_IP"; +pub const DEVSERVER_PORT_ENV: &str = "DIOXUS_DEVSERVER_PORT"; pub const ALWAYS_ON_TOP_ENV: &str = "DIOXUS_ALWAYS_ON_TOP"; pub const ASSET_ROOT_ENV: &str = "DIOXUS_ASSET_ROOT"; pub const APP_TITLE_ENV: &str = "DIOXUS_APP_TITLE"; @@ -100,8 +101,16 @@ macro_rules! read_env_config { /// For reference, the devserver typically lives on `127.0.0.1:8080` and serves the devserver websocket /// on `127.0.0.1:8080/_dioxus`. pub fn devserver_raw_addr() -> Option { - let addr = std::env::var(DEVSERVER_RAW_ADDR_ENV).ok()?; - addr.parse().ok() + let ip = std::env::var(DEVSERVER_IP_ENV).ok()?; + let port = std::env::var(DEVSERVER_PORT_ENV).ok()?; + + if cfg!(target_os = "android") { + // Since `adb reverse` is used for Android, the 127.0.0.1 will always be + // the correct IP address. + return Some(format!("127.0.0.1:{}", port).parse().unwrap()); + } + + format!("{}:{}", ip, port).parse().ok() } /// Get the address of the devserver for use over a websocket diff --git a/packages/cli/src/serve/handle.rs b/packages/cli/src/serve/handle.rs index ce802fbeb..8cad0fb17 100644 --- a/packages/cli/src/serve/handle.rs +++ b/packages/cli/src/serve/handle.rs @@ -86,8 +86,12 @@ impl AppHandle { ), ("RUST_BACKTRACE", "1".to_string()), ( - dioxus_cli_config::DEVSERVER_RAW_ADDR_ENV, - devserver_ip.to_string(), + dioxus_cli_config::DEVSERVER_IP_ENV, + devserver_ip.ip().to_string(), + ), + ( + dioxus_cli_config::DEVSERVER_PORT_ENV, + devserver_ip.port().to_string(), ), // unset the cargo dirs in the event we're running `dx` locally // since the child process will inherit the env vars, we don't want to confuse the downstream process @@ -145,7 +149,7 @@ impl AppHandle { // https://developer.android.com/studio/run/emulator-commandline Platform::Android => { - self.open_android_sim(envs).await; + self.open_android_sim(devserver_ip, envs).await; None } @@ -697,13 +701,30 @@ We checked the folder: {} Ok(()) } - async fn open_android_sim(&self, envs: Vec<(&'static str, String)>) { + async fn open_android_sim( + &self, + devserver_socket: SocketAddr, + envs: Vec<(&'static str, String)>, + ) { let apk_path = self.app.apk_path(); let session_cache = self.app.build.krate.session_cache_dir(); let full_mobile_app_name = self.app.build.krate.full_mobile_app_name(); // Start backgrounded since .open() is called while in the arm of the top-level match tokio::task::spawn(async move { + let port = devserver_socket.port(); + if let Err(e) = Command::new("adb") + .arg("reverse") + .arg(format!("tcp:{}", port)) + .arg(format!("tcp:{}", port)) + .stderr(Stdio::piped()) + .stdout(Stdio::piped()) + .output() + .await + { + tracing::error!("failed to forward port {port}: {e}"); + } + // Install // adb install -r app-debug.apk if let Err(e) = Command::new(DioxusCrate::android_adb()) diff --git a/packages/cli/src/serve/server.rs b/packages/cli/src/serve/server.rs index 966fe6ce5..d431e275b 100644 --- a/packages/cli/src/serve/server.rs +++ b/packages/cli/src/serve/server.rs @@ -193,6 +193,23 @@ impl WebServer { } pub(crate) async fn shutdown(&mut self) { + if matches!(self.platform, Platform::Android) { + use std::process::{Command, Stdio}; + if let Err(err) = Command::new("adb") + .arg("reverse") + .arg("--remove") + .arg(format!("tcp:{}", self.devserver_port)) + .stderr(Stdio::piped()) + .stdout(Stdio::piped()) + .output() + { + tracing::error!( + "failed to remove forwarded port {}: {err}", + self.devserver_port + ); + } + } + self.send_shutdown().await; for socket in self.hot_reload_sockets.drain(..) { _ = socket.close().await; diff --git a/packages/dioxus/src/launch.rs b/packages/dioxus/src/launch.rs index 1ad29393e..75c084fde 100644 --- a/packages/dioxus/src/launch.rs +++ b/packages/dioxus/src/launch.rs @@ -162,14 +162,8 @@ impl LaunchBuilder { { use dioxus_fullstack::prelude::server_fn::client::{get_server_url, set_server_url}; if get_server_url().is_empty() { - let ip = if cfg!(target_os = "android") { - "10.0.2.2" - } else { - "127.0.0.1" - }; - let serverurl = format!( - "http://{ip}:{}", + "http://127.0.0.1:{}", std::env::var("PORT").unwrap_or_else(|_| "8080".to_string()) ) .leak();