From 1675030039ef378b393eec3beb2059569cff24a6 Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 19 Dec 2025 16:43:42 +0100 Subject: [PATCH 1/6] Added support for android local storage via set_dir! macro --- examples/storage/Cargo.toml | 1 + packages/storage/Cargo.toml | 4 +++ packages/storage/src/client_storage/fs.rs | 32 ++++++++++++++++++++++ packages/storage/src/client_storage/mod.rs | 20 ++++++++++++-- packages/storage/src/lib.rs | 3 ++ 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/examples/storage/Cargo.toml b/examples/storage/Cargo.toml index 5fd0a60..fac52e5 100644 --- a/examples/storage/Cargo.toml +++ b/examples/storage/Cargo.toml @@ -14,3 +14,4 @@ web = ["dioxus/web"] desktop = ["dioxus/desktop"] fullstack = ["dioxus/fullstack"] server = ["dioxus/server"] +mobile = ["dioxus/mobile"] diff --git a/packages/storage/Cargo.toml b/packages/storage/Cargo.toml index e9e5b74..3bd1340 100644 --- a/packages/storage/Cargo.toml +++ b/packages/storage/Cargo.toml @@ -32,3 +32,7 @@ directories = "4.0.1" [target.'cfg(target_family = "wasm")'.dependencies] web-sys = { workspace = true, features = ["Window", "Storage", "StorageEvent"] } wasm-bindgen = { workspace = true } + +[target.'cfg(target_os = "android")'.dependencies] +jni = "0.21.1" +ndk-context = "0.1.1" \ No newline at end of file diff --git a/packages/storage/src/client_storage/fs.rs b/packages/storage/src/client_storage/fs.rs index f7fd110..2bb82d0 100644 --- a/packages/storage/src/client_storage/fs.rs +++ b/packages/storage/src/client_storage/fs.rs @@ -9,6 +9,38 @@ use tokio::sync::watch::{Receiver, channel}; use crate::{StorageBacking, StorageSubscriber, serde_to_string, try_serde_from_string}; + +#[doc(hidden)] +#[cfg(target_os = "android")] +pub fn data_directory() -> std::path::PathBuf { + use jni::objects::{JObject, JString}; + use jni::JNIEnv; + use std::sync::mpsc::channel; + + let (tx, rx) = channel(); + + dioxus::mobile::wry::prelude::dispatch(move |env: &mut JNIEnv, activity: &JObject, _webview| { + let files_dir = env + .call_method(activity, "getFilesDir", "()Ljava/io/File;", &[]) + .unwrap() + .l() + .unwrap(); + + let abs_path = env + .call_method(files_dir, "getAbsolutePath", "()Ljava/lang/String;", &[]) + .unwrap() + .l() + .unwrap(); + + let abs_path: JString = abs_path.into(); + let abs_path: String = env.get_string(&abs_path).unwrap().into(); + + tx.send(std::path::PathBuf::from(abs_path)).unwrap(); + }); + + rx.recv().unwrap() +} + #[doc(hidden)] /// Sets the directory where the storage files are located. pub fn set_directory(path: std::path::PathBuf) { diff --git a/packages/storage/src/client_storage/mod.rs b/packages/storage/src/client_storage/mod.rs index 198a3f1..ee9d5e5 100644 --- a/packages/storage/src/client_storage/mod.rs +++ b/packages/storage/src/client_storage/mod.rs @@ -21,11 +21,27 @@ macro_rules! set_dir { () => { #[cfg(not(target_family = "wasm"))] - $crate::set_dir_name(env!("CARGO_PKG_NAME")) + { + #[cfg(target_os="android")] + { + let path = $crate::data_directory().join(env!("CARGO_PKG_NAME")); + $crate::set_directory(path); + } + #[cfg(not(target_os="android"))] + $crate::set_dir_name(env!("CARGO_PKG_NAME")) + } }; ($path:expr) => { #[cfg(not(target_family = "wasm"))] - $crate::set_directory(std::path::PathBuf::from($path)) + { + #[cfg(target_os="android")] + { + let path = $crate::data_directory().join($path); + $crate::set_directory(path); + } + #[cfg(not(target_os="android"))] + $crate::set_directory(std::path::PathBuf::from($path)); + } }; } diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs index 51020dd..4632815 100644 --- a/packages/storage/src/lib.rs +++ b/packages/storage/src/lib.rs @@ -53,6 +53,9 @@ use tokio::sync::watch::{Receiver, Sender}; #[cfg(not(target_family = "wasm"))] pub use client_storage::{set_dir_name, set_directory}; +#[cfg(target_os = "android")] +pub use client_storage::data_directory; + /// A storage hook that can be used to store data that will persist across application reloads. This hook is generic over the storage location which can be useful for other hooks. /// /// This hook returns a Signal that can be used to read and modify the state. From da7863d11bd6f3e7014d526bff1798e84496d9c3 Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 26 Dec 2025 15:03:00 +0100 Subject: [PATCH 2/6] Moved the platform specific code to set_dir_name --- packages/storage/src/client_storage/fs.rs | 23 ++++++++++++++++------ packages/storage/src/client_storage/mod.rs | 20 ++----------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/packages/storage/src/client_storage/fs.rs b/packages/storage/src/client_storage/fs.rs index 2bb82d0..7b72c2c 100644 --- a/packages/storage/src/client_storage/fs.rs +++ b/packages/storage/src/client_storage/fs.rs @@ -49,12 +49,23 @@ pub fn set_directory(path: std::path::PathBuf) { #[doc(hidden)] pub fn set_dir_name(name: &str) { - set_directory( - directories::BaseDirs::new() - .unwrap() - .data_local_dir() - .join(name), - ) + + #[cfg(target_os = "android")] + { + set_directory( + data_directory().join(name) + ); + } + #[cfg(not(target_os = "android"))] + { + set_directory( + directories::BaseDirs::new() + .unwrap() + .data_local_dir() + .join(name), + ) + }; + } /// The location where the storage files are located. diff --git a/packages/storage/src/client_storage/mod.rs b/packages/storage/src/client_storage/mod.rs index ee9d5e5..198a3f1 100644 --- a/packages/storage/src/client_storage/mod.rs +++ b/packages/storage/src/client_storage/mod.rs @@ -21,27 +21,11 @@ macro_rules! set_dir { () => { #[cfg(not(target_family = "wasm"))] - { - #[cfg(target_os="android")] - { - let path = $crate::data_directory().join(env!("CARGO_PKG_NAME")); - $crate::set_directory(path); - } - #[cfg(not(target_os="android"))] - $crate::set_dir_name(env!("CARGO_PKG_NAME")) - } + $crate::set_dir_name(env!("CARGO_PKG_NAME")) }; ($path:expr) => { #[cfg(not(target_family = "wasm"))] - { - #[cfg(target_os="android")] - { - let path = $crate::data_directory().join($path); - $crate::set_directory(path); - } - #[cfg(not(target_os="android"))] - $crate::set_directory(std::path::PathBuf::from($path)); - } + $crate::set_directory(std::path::PathBuf::from($path)) }; } From 48264f4ed461f6ab3587eb5394aebb5677dbe2ed Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 26 Dec 2025 15:07:24 +0100 Subject: [PATCH 3/6] Fixed clippy --- packages/storage/src/client_storage/fs.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/storage/src/client_storage/fs.rs b/packages/storage/src/client_storage/fs.rs index 7b72c2c..a91ad96 100644 --- a/packages/storage/src/client_storage/fs.rs +++ b/packages/storage/src/client_storage/fs.rs @@ -54,17 +54,18 @@ pub fn set_dir_name(name: &str) { { set_directory( data_directory().join(name) - ); + ) } + #[cfg(not(target_os = "android"))] { set_directory( directories::BaseDirs::new() .unwrap() .data_local_dir() - .join(name), + .join(name) ) - }; + } } From f5a678a4ad1fc947f6177bd122d0d87b5ea217b3 Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 26 Dec 2025 15:09:43 +0100 Subject: [PATCH 4/6] Removed doc[hidden] to expose data_directory() as into the public api --- packages/storage/src/client_storage/fs.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/storage/src/client_storage/fs.rs b/packages/storage/src/client_storage/fs.rs index a91ad96..62331bf 100644 --- a/packages/storage/src/client_storage/fs.rs +++ b/packages/storage/src/client_storage/fs.rs @@ -10,7 +10,6 @@ use tokio::sync::watch::{Receiver, channel}; use crate::{StorageBacking, StorageSubscriber, serde_to_string, try_serde_from_string}; -#[doc(hidden)] #[cfg(target_os = "android")] pub fn data_directory() -> std::path::PathBuf { use jni::objects::{JObject, JString}; From 9e197bfc4314520f67a7d063e8a00a6a96116558 Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 26 Dec 2025 15:14:16 +0100 Subject: [PATCH 5/6] Fixed fmt --- packages/storage/src/client_storage/fs.rs | 43 +++++++++++------------ 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/packages/storage/src/client_storage/fs.rs b/packages/storage/src/client_storage/fs.rs index 62331bf..9adefb0 100644 --- a/packages/storage/src/client_storage/fs.rs +++ b/packages/storage/src/client_storage/fs.rs @@ -9,33 +9,34 @@ use tokio::sync::watch::{Receiver, channel}; use crate::{StorageBacking, StorageSubscriber, serde_to_string, try_serde_from_string}; - #[cfg(target_os = "android")] pub fn data_directory() -> std::path::PathBuf { - use jni::objects::{JObject, JString}; use jni::JNIEnv; + use jni::objects::{JObject, JString}; use std::sync::mpsc::channel; let (tx, rx) = channel(); - dioxus::mobile::wry::prelude::dispatch(move |env: &mut JNIEnv, activity: &JObject, _webview| { - let files_dir = env - .call_method(activity, "getFilesDir", "()Ljava/io/File;", &[]) - .unwrap() - .l() - .unwrap(); + dioxus::mobile::wry::prelude::dispatch( + move |env: &mut JNIEnv, activity: &JObject, _webview| { + let files_dir = env + .call_method(activity, "getFilesDir", "()Ljava/io/File;", &[]) + .unwrap() + .l() + .unwrap(); - let abs_path = env - .call_method(files_dir, "getAbsolutePath", "()Ljava/lang/String;", &[]) - .unwrap() - .l() - .unwrap(); + let abs_path = env + .call_method(files_dir, "getAbsolutePath", "()Ljava/lang/String;", &[]) + .unwrap() + .l() + .unwrap(); - let abs_path: JString = abs_path.into(); - let abs_path: String = env.get_string(&abs_path).unwrap().into(); + let abs_path: JString = abs_path.into(); + let abs_path: String = env.get_string(&abs_path).unwrap().into(); - tx.send(std::path::PathBuf::from(abs_path)).unwrap(); - }); + tx.send(std::path::PathBuf::from(abs_path)).unwrap(); + }, + ); rx.recv().unwrap() } @@ -48,12 +49,9 @@ pub fn set_directory(path: std::path::PathBuf) { #[doc(hidden)] pub fn set_dir_name(name: &str) { - #[cfg(target_os = "android")] { - set_directory( - data_directory().join(name) - ) + set_directory(data_directory().join(name)) } #[cfg(not(target_os = "android"))] @@ -62,10 +60,9 @@ pub fn set_dir_name(name: &str) { directories::BaseDirs::new() .unwrap() .data_local_dir() - .join(name) + .join(name), ) } - } /// The location where the storage files are located. From 6f3924848c731ee9abb2a60ea6a25625274e8988 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 26 Dec 2025 08:34:44 -0600 Subject: [PATCH 6/6] Make data_directory work on all platforms and move cfg logic up one level --- packages/storage/src/client_storage/fs.rs | 41 ++++++++++++++--------- packages/storage/src/lib.rs | 5 +-- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/packages/storage/src/client_storage/fs.rs b/packages/storage/src/client_storage/fs.rs index 9adefb0..20b4763 100644 --- a/packages/storage/src/client_storage/fs.rs +++ b/packages/storage/src/client_storage/fs.rs @@ -9,8 +9,32 @@ use tokio::sync::watch::{Receiver, channel}; use crate::{StorageBacking, StorageSubscriber, serde_to_string, try_serde_from_string}; -#[cfg(target_os = "android")] +/// Get the default data directory for the current platform. +/// +/// # Example +/// ```rust +/// use dioxus_sdk_storage::{data_directory, set_dir}; +/// +/// // Set the storage directory to a folder named "my_app" in the default data directory. +/// set_dir!(data_directory().join("my_app")); +/// ``` pub fn data_directory() -> std::path::PathBuf { + #[cfg(target_os = "android")] + { + android_data_directory() + } + + #[cfg(not(target_os = "android"))] + { + directories::BaseDirs::new() + .unwrap() + .data_local_dir() + .to_path_buf() + } +} + +#[cfg(target_os = "android")] +fn android_data_directory() -> std::path::PathBuf { use jni::JNIEnv; use jni::objects::{JObject, JString}; use std::sync::mpsc::channel; @@ -49,20 +73,7 @@ pub fn set_directory(path: std::path::PathBuf) { #[doc(hidden)] pub fn set_dir_name(name: &str) { - #[cfg(target_os = "android")] - { - set_directory(data_directory().join(name)) - } - - #[cfg(not(target_os = "android"))] - { - set_directory( - directories::BaseDirs::new() - .unwrap() - .data_local_dir() - .join(name), - ) - } + set_directory(data_directory().join(name)) } /// The location where the storage files are located. diff --git a/packages/storage/src/lib.rs b/packages/storage/src/lib.rs index 4632815..46be68c 100644 --- a/packages/storage/src/lib.rs +++ b/packages/storage/src/lib.rs @@ -51,10 +51,7 @@ use tokio::sync::watch::error::SendError; use tokio::sync::watch::{Receiver, Sender}; #[cfg(not(target_family = "wasm"))] -pub use client_storage::{set_dir_name, set_directory}; - -#[cfg(target_os = "android")] -pub use client_storage::data_directory; +pub use client_storage::{data_directory, set_dir_name, set_directory}; /// A storage hook that can be used to store data that will persist across application reloads. This hook is generic over the storage location which can be useful for other hooks. ///