Переглянути джерело

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
Andrew Voynov 4 місяців тому
батько
коміт
67515ce812

+ 12 - 3
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<SocketAddr> {
-    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

+ 25 - 4
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())

+ 17 - 0
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;

+ 1 - 7
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();