소스 검색

fix: pass off env vars to android apps (#3621)

* fix: pass off env vars to android apps

* move to jni_onload

* fix clippy
Jonathan Kelley 5 달 전
부모
커밋
03c2d6711d
7개의 변경된 파일65개의 추가작업 그리고 10개의 파일을 삭제
  1. 3 2
      Cargo.lock
  2. 11 4
      packages/cli-config/src/lib.rs
  3. 24 3
      packages/cli/src/serve/handle.rs
  4. 3 0
      packages/cli/src/serve/server.rs
  5. 1 1
      packages/desktop/src/protocol.rs
  6. 1 0
      packages/mobile/Cargo.toml
  7. 22 0
      packages/mobile/src/lib.rs

+ 3 - 2
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",

+ 11 - 4
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<SocketAddr> {
-    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<PathBuf> {
 ///
 /// This is designed with desktop executables in mind.
 pub fn session_cache_dir() -> Option<PathBuf> {
+    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/")
+}

+ 24 - 3
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::<Vec<_>>()
+                .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()

+ 3 - 0
packages/cli/src/serve/server.rs

@@ -355,6 +355,9 @@ impl WebServer {
     pub fn displayed_address(&self) -> Option<SocketAddr> {
         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());
         }

+ 1 - 1
packages/desktop/src/protocol.rs

@@ -282,7 +282,7 @@ pub(crate) fn to_java_load_asset(filepath: &str) -> Option<Vec<u8>> {
     // 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();
         }

+ 1 - 0
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
 

+ 22 - 0
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);
+            }
+        }
+    }
+}