Skip to content

Commit

Permalink
fix: pass off env vars to android apps (#3621)
Browse files Browse the repository at this point in the history
* fix: pass off env vars to android apps

* move to jni_onload

* fix clippy
  • Loading branch information
jkelleyrtp authored Jan 22, 2025
1 parent ce2b223 commit 03c2d67
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 10 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 11 additions & 4 deletions packages/cli-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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/")
}
27 changes: 24 additions & 3 deletions packages/cli/src/serve/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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,);
Expand All @@ -727,7 +749,6 @@ We checked the folder: {}
.arg("start")
.arg("-n")
.arg(activity_name)
.envs(envs)
.stderr(Stdio::piped())
.stdout(Stdio::piped())
.output()
Expand Down
3 changes: 3 additions & 0 deletions packages/cli/src/serve/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop/src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
1 change: 1 addition & 0 deletions packages/mobile/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
22 changes: 22 additions & 0 deletions packages/mobile/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
}

0 comments on commit 03c2d67

Please sign in to comment.