From 03c2d6711d864f147eb4260a692e5f5eafd66b5f Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Tue, 21 Jan 2025 18:52:56 -0800 Subject: [PATCH] fix: pass off env vars to android apps (#3621) * fix: pass off env vars to android apps * move to jni_onload * fix clippy --- Cargo.lock | 5 +++-- packages/cli-config/src/lib.rs | 15 +++++++++++---- packages/cli/src/serve/handle.rs | 27 ++++++++++++++++++++++++--- packages/cli/src/serve/server.rs | 3 +++ packages/desktop/src/protocol.rs | 2 +- packages/mobile/Cargo.toml | 1 + packages/mobile/src/lib.rs | 22 ++++++++++++++++++++++ 7 files changed, 65 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 152f619fad..8fde583ed8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4029,6 +4029,7 @@ dependencies = [ name = "dioxus-mobile" version = "0.6.1" dependencies = [ + "dioxus-cli-config", "dioxus-desktop", "dioxus-lib", "jni", @@ -6291,9 +6292,9 @@ dependencies = [ [[package]] name = "hstr" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dae404c0c5d4e95d4858876ab02eecd6a196bb8caa42050dfa809938833fc412" +checksum = "63d6824358c0fd9a68bb23999ed2ef76c84f79408a26ef7ae53d5f370c94ad36" dependencies = [ "hashbrown 0.14.5", "new_debug_unreachable", diff --git a/packages/cli-config/src/lib.rs b/packages/cli-config/src/lib.rs index 11d4afbfd6..6814430248 100644 --- a/packages/cli-config/src/lib.rs +++ b/packages/cli-config/src/lib.rs @@ -100,10 +100,8 @@ 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 { - std::env::var(DEVSERVER_RAW_ADDR_ENV) - .unwrap_or_else(|_| "127.0.0.1:8080".to_string()) - .parse() - .ok() + let addr = std::env::var(DEVSERVER_RAW_ADDR_ENV).ok()?; + addr.parse().ok() } /// Get the address of the devserver for use over a websocket @@ -288,5 +286,14 @@ pub fn out_dir() -> Option { /// /// This is designed with desktop executables in mind. pub fn session_cache_dir() -> Option { + if cfg!(target_os = "android") { + return Some(android_session_cache_dir()); + } + std::env::var(SESSION_CACHE_DIR).ok().map(PathBuf::from) } + +/// The session cache directory for android +pub fn android_session_cache_dir() -> PathBuf { + PathBuf::from("/data/local/tmp/dx/") +} diff --git a/packages/cli/src/serve/handle.rs b/packages/cli/src/serve/handle.rs index 84e670b503..ce802fbeb6 100644 --- a/packages/cli/src/serve/handle.rs +++ b/packages/cli/src/serve/handle.rs @@ -292,8 +292,8 @@ impl AppHandle { // If the emulator is android, we need to copy the asset to the device with `adb push asset /data/local/tmp/dx/assets/filename.ext` if self.app.build.build.platform() == Platform::Android { if let Some(bundled_name) = bundled_name.as_ref() { - let target = format!("/data/local/tmp/dx/{}", bundled_name.display()); - tracing::debug!("Pushing asset to device: {target}"); + let target = dioxus_cli_config::android_session_cache_dir().join(bundled_name); + tracing::debug!("Pushing asset to device: {target:?}"); let res = tokio::process::Command::new(DioxusCrate::android_adb()) .arg("push") .arg(&changed_file) @@ -699,6 +699,7 @@ We checked the folder: {} async fn open_android_sim(&self, 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 @@ -717,6 +718,27 @@ We checked the folder: {} tracing::error!("Failed to install apk with `adb`: {e}"); }; + // Write the env vars to a .env file in our session cache + let env_file = session_cache.join(".env"); + let contents: String = envs + .iter() + .map(|(key, value)| format!("{key}={value}")) + .collect::>() + .join("\n"); + _ = std::fs::write(&env_file, contents); + + // Push the env file to the device + if let Err(e) = tokio::process::Command::new(DioxusCrate::android_adb()) + .arg("push") + .arg(env_file) + .arg(dioxus_cli_config::android_session_cache_dir().join(".env")) + .output() + .await + .context("Failed to push asset to device") + { + tracing::error!("Failed to push .env file to device: {e}"); + } + // eventually, use the user's MainAcitivty, not our MainAcitivty // adb shell am start -n dev.dioxus.main/dev.dioxus.main.MainActivity let activity_name = format!("{}/dev.dioxus.main.MainActivity", full_mobile_app_name,); @@ -727,7 +749,6 @@ We checked the folder: {} .arg("start") .arg("-n") .arg(activity_name) - .envs(envs) .stderr(Stdio::piped()) .stdout(Stdio::piped()) .output() diff --git a/packages/cli/src/serve/server.rs b/packages/cli/src/serve/server.rs index f9dc96da6e..966fe6ce5b 100644 --- a/packages/cli/src/serve/server.rs +++ b/packages/cli/src/serve/server.rs @@ -355,6 +355,9 @@ impl WebServer { pub fn displayed_address(&self) -> Option { let mut address = self.server_address()?; + // Set the port to the devserver port since that's usually what people expect + address.set_port(self.devserver_port); + if self.devserver_bind_ip == IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)) { address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), address.port()); } diff --git a/packages/desktop/src/protocol.rs b/packages/desktop/src/protocol.rs index 677fe5e6f2..3063647782 100644 --- a/packages/desktop/src/protocol.rs +++ b/packages/desktop/src/protocol.rs @@ -282,7 +282,7 @@ pub(crate) fn to_java_load_asset(filepath: &str) -> Option> { // in debug mode, the asset might be under `/data/local/tmp/dx/` - attempt to read it from there if it exists #[cfg(debug_assertions)] { - let path = std::path::PathBuf::from("/data/local/tmp/dx/").join(normalized); + let path = dioxus_cli_config::android_session_cache_dir().join(normalized); if path.exists() { return std::fs::read(path).ok(); } diff --git a/packages/mobile/Cargo.toml b/packages/mobile/Cargo.toml index 41e1317b0f..3fc6667563 100644 --- a/packages/mobile/Cargo.toml +++ b/packages/mobile/Cargo.toml @@ -12,6 +12,7 @@ license = "MIT OR Apache-2.0" [dependencies] dioxus-desktop = { workspace = true } dioxus-lib = { workspace = true } +dioxus-cli-config = { workspace = true } libc = "0.2.159" once_cell.workspace = true diff --git a/packages/mobile/src/lib.rs b/packages/mobile/src/lib.rs index 26128ae4b4..88d8e5051c 100644 --- a/packages/mobile/src/lib.rs +++ b/packages/mobile/src/lib.rs @@ -128,9 +128,31 @@ pub extern "C" fn JNI_OnLoad( panic!("Failed to find main symbol"); } + // Set the env vars that rust code might expect, passed off to us by the android app + // Doing this before main emulates the behavior of a regular executable + if cfg!(target_os = "android") && cfg!(debug_assertions) { + load_env_file_from_session_cache(); + } + let main_fn: extern "C" fn() = std::mem::transmute(main_fn_ptr); main_fn(); }; jni::sys::JNI_VERSION_1_6 } + +/// Load the env file from the session cache if we're in debug mode and on android +/// +/// This is a slightly hacky way of being able to use std::env::var code in android apps without +/// going through their custom java-based system. +#[cfg(target_os = "android")] +fn load_env_file_from_session_cache() { + let env_file = dioxus_cli_config::android_session_cache_dir().join(".env"); + if let Some(env_file) = std::fs::read_to_string(&env_file).ok() { + for line in env_file.lines() { + if let Some((key, value)) = line.trim().split_once('=') { + std::env::set_var(key, value); + } + } + } +}