Procházet zdrojové kódy

fix(cli): adb port forward error handling, add logs, closes #9509 (#10604)

Lucas Fernandes Nogueira před 11 měsíci
rodič
revize
9f75d06228

+ 6 - 0
.changes/android-port-forward-fixes.md

@@ -0,0 +1,6 @@
+---
+"tauri-cli": patch:bug
+"@tauri-apps/cli": patch:bug
+---
+
+Fixes `android dev` port forward failing under some conditions, add better logging and error handling.

+ 2 - 2
tooling/cli/Cargo.lock

@@ -557,9 +557,9 @@ dependencies = [
 
 [[package]]
 name = "cargo-mobile2"
-version = "0.13.1"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a375de334eab8b47e0f02421509c3fb6910499ec8353d36e4d977c2b5d7646b"
+checksum = "ebaedf7b7e292b7f41f892f5c96ee15544e21814e89d0b6b8dc06740a69dabe5"
 dependencies = [
  "colored",
  "core-foundation",

+ 1 - 1
tooling/cli/Cargo.toml

@@ -39,7 +39,7 @@ name = "cargo-tauri"
 path = "src/main.rs"
 
 [dependencies]
-cargo-mobile2 = { version = "0.13.1", default-features = false }
+cargo-mobile2 = { version = "0.13.2", default-features = false }
 jsonrpsee = { version = "0.24", features = [ "server" ] }
 jsonrpsee-core = "0.24"
 jsonrpsee-client-transport = { version = "0.24", features = [ "ws" ] }

+ 55 - 6
tooling/cli/src/mobile/android/android_studio_script.rs

@@ -85,12 +85,35 @@ pub fn command(options: Options) -> Result<()> {
 
     if let Some(port) = dev_url.and_then(|url| url.port_or_known_default()) {
       let forward = format!("tcp:{port}");
-      // ignore errors in case we do not have a device available
-      let _ = adb::adb(&env, ["reverse", &forward, &forward])
-        .stdin_file(os_pipe::dup_stdin().unwrap())
-        .stdout_file(os_pipe::dup_stdout().unwrap())
-        .stderr_capture()
-        .run();
+      log::info!("Forwarding port {port} with adb");
+
+      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 {
+        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(", "));
+      }
     }
   }
 
@@ -152,3 +175,29 @@ fn validate_lib(path: &Path) -> Result<()> {
 
   Ok(())
 }
+
+fn run_adb_reverse(
+  env: &cargo_mobile2::android::env::Env,
+  device_serial_no: &str,
+  remote: &str,
+  local: &str,
+) -> std::io::Result<std::process::Output> {
+  adb::adb(env, ["-s", device_serial_no, "reverse", remote, local])
+    .stdin_file(os_pipe::dup_stdin().unwrap())
+    .stdout_file(os_pipe::dup_stdout().unwrap())
+    .stderr_file(os_pipe::dup_stdout().unwrap())
+    .run()
+}
+
+fn remove_adb_reverse(
+  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])
+    .stdin_file(os_pipe::dup_stdin().unwrap())
+    .stdout_file(os_pipe::dup_stdout().unwrap())
+    .stderr_file(os_pipe::dup_stdout().unwrap())
+    .run();
+}

+ 1 - 0
tooling/cli/src/mobile/android/build.rs

@@ -202,6 +202,7 @@ fn run_build(
     noise_level,
     vars: Default::default(),
     config: build_options.config.clone(),
+    target_device: None,
   };
   let handle = write_options(
     &tauri_config.lock().unwrap().as_ref().unwrap().identifier,

+ 5 - 1
tooling/cli/src/mobile/android/dev.rs

@@ -14,7 +14,7 @@ use crate::{
     flock,
   },
   interface::{AppInterface, AppSettings, Interface, MobileOptions, Options as InterfaceOptions},
-  mobile::{write_options, CliOptions, DevChild, DevProcess},
+  mobile::{write_options, CliOptions, DevChild, DevProcess, TargetDevice},
   ConfigValue, Result,
 };
 use clap::{ArgAction, Parser};
@@ -233,6 +233,10 @@ fn run_dev(
         noise_level,
         vars: Default::default(),
         config: dev_options.config.clone(),
+        target_device: device.as_ref().map(|d| TargetDevice {
+          id: d.serial_no().to_string(),
+          name: d.name().to_string(),
+        }),
       };
 
       let _handle = write_options(

+ 1 - 0
tooling/cli/src/mobile/ios/build.rs

@@ -284,6 +284,7 @@ fn run_build(
     noise_level,
     vars: Default::default(),
     config: build_options.config.clone(),
+    target_device: None,
   };
   let handle = write_options(
     &tauri_config.lock().unwrap().as_ref().unwrap().identifier,

+ 1 - 0
tooling/cli/src/mobile/ios/dev.rs

@@ -392,6 +392,7 @@ fn run_dev(
         noise_level,
         vars: Default::default(),
         config: dev_options.config.clone(),
+        target_device: None,
       };
       let _handle = write_options(
         &tauri_config.lock().unwrap().as_ref().unwrap().identifier,

+ 8 - 0
tooling/cli/src/mobile/mod.rs

@@ -135,6 +135,12 @@ impl Target {
   }
 }
 
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TargetDevice {
+  id: String,
+  name: String,
+}
+
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct CliOptions {
   pub dev: bool,
@@ -143,6 +149,7 @@ pub struct CliOptions {
   pub noise_level: NoiseLevel,
   pub vars: HashMap<String, OsString>,
   pub config: Option<ConfigValue>,
+  pub target_device: Option<TargetDevice>,
 }
 
 impl Default for CliOptions {
@@ -154,6 +161,7 @@ impl Default for CliOptions {
       noise_level: Default::default(),
       vars: Default::default(),
       config: None,
+      target_device: None,
     }
   }
 }