tauri_plugin_android_fs/api/
private_storage.rs

1use sync_async::sync_async;
2use crate::*;
3use super::*;
4
5
6/// API of file storage intended for the app’s use only.  
7/// 
8/// # Examples
9/// ```no_run
10/// fn example(app: &tauri::AppHandle) {
11///     use tauri_plugin_android_fs::AndroidFsExt as _;
12/// 
13///     let api = app.android_fs();
14///     let private_storage = api.private_storage();
15/// }
16/// ```
17#[sync_async]
18pub struct PrivateStorage<'a, R: tauri::Runtime> {
19    #[cfg(target_os = "android")]
20    pub(crate) handle: &'a tauri::plugin::PluginHandle<R>,
21
22    #[cfg(not(target_os = "android"))]
23    #[allow(unused)]
24    pub(crate) handle: &'a std::marker::PhantomData<fn() -> R>,
25}
26
27#[cfg(target_os = "android")]
28#[sync_async(
29    use(if_sync) impls::SyncImpls as Impls;
30    use(if_async) impls::AsyncImpls as Impls;
31)]
32impl<'a, R: tauri::Runtime> PrivateStorage<'a, R> {
33    
34    #[always_sync]
35    fn impls(&self) -> Impls<'_, R> {
36        Impls { handle: &self.handle }
37    }
38}
39
40#[sync_async(
41    use(if_async) api_async::{AndroidFs, FileOpener, FilePicker, PublicStorage, WritableStream};
42    use(if_sync) api_sync::{AndroidFs, FileOpener, FilePicker, PublicStorage, WritableStream};
43)]
44impl<'a, R: tauri::Runtime> PrivateStorage<'a, R> {
45
46    /// Get an absolute path of the app-specific directory on the internal storage.  
47    /// App can fully manage entries within this directory.   
48    /// 
49    /// This function does **not** create any directories; it only constructs the path.
50    /// 
51    /// Since these locations may contain files created by other Tauri plugins or webview systems, 
52    /// it is recommended to add a subdirectory with a unique name.
53    ///
54    /// These entries will be deleted when the app is uninstalled and may also be deleted at the user’s initialising request.  
55    /// 
56    /// When using [`PrivateDir::Cache`], the system will automatically delete entries as disk space is needed elsewhere on the device. 
57    /// But you should not rely on this. The cache should be explicitly cleared by yourself.
58    /// 
59    /// The system prevents other apps and user from accessing these locations. 
60    /// In cases where the device is rooted or the user has special permissions, the user may be able to access this.   
61    /// 
62    /// Since the returned paths can change when the app is moved to an [adopted storage](https://source.android.com/docs/core/storage/adoptable), 
63    /// only relative paths should be stored.
64    /// 
65    /// # Note
66    /// This provides a separate area for each user in a multi-user environment.
67    /// 
68    /// # Support
69    /// All Android version.
70    #[maybe_async]
71    pub fn resolve_path(
72        &self, 
73        dir: PrivateDir
74    ) -> Result<std::path::PathBuf> {
75
76        #[cfg(not(target_os = "android"))] {
77            Err(Error::NOT_ANDROID)
78        }
79        #[cfg(target_os = "android")] {
80            self.impls().internal_private_dir_path(dir).map(Clone::clone)
81        }
82    }
83
84    /// Get an absolute path of the app-specific directory on the specified storage volume.  
85    /// App can fully manage entries within this directory.  
86    /// 
87    /// This function does **not** create any directories; it only constructs the path.
88    ///    
89    /// Since these locations may contain files created by other Tauri plugins or webview systems, 
90    /// it is recommended to add a subdirectory with a unique name.
91    ///
92    /// These entries will be deleted when the app is uninstalled and may also be deleted at the user’s initialising request.   
93    /// 
94    /// # Note
95    /// If you are unsure between this function and [`PrivateStorage::resolve_path`], 
96    /// you don’t need to use this one.  
97    /// The difference from [`PrivateStorage::resolve_path`] is that these files may be accessed by other apps that have specific permissions,
98    /// and it cannot always be available since removable storage can be ejected.  
99    /// 
100    /// One advantage of using this is that it allows storing large app-specific data/cache on SD cards or other supplementary storage, 
101    /// which can be useful on older devices with limited built-in storage capacity. 
102    /// However on modern devices, the built-in storage capacity is relatively large,
103    /// and there is little advantage in using this.  
104    /// 
105    /// By using [`StorageVolume { is_emulated, .. }`](StorageVolume), 
106    /// you can determine whether this belongs to the same storage volume as [`PrivateStorage::resolve_path`]. 
107    /// In this case, there is no advantage in using this instead of `PrivateStorage::resolve_path`. 
108    /// It only reduces security.
109    /// 
110    /// # Args
111    /// - ***volume_id*** :  
112    /// ID of the storage volume, such as internal storage, SD card, etc.  
113    /// If `None` is provided, [`the primary storage volume`](PrivateStorage::get_primary_volume) will be used.  
114    /// 
115    /// # Support
116    /// All Android version. 
117    #[maybe_async]
118    pub fn resolve_outside_path(
119        &self, 
120        volume_id: Option<&StorageVolumeId>,
121        dir: OutsidePrivateDir
122    ) -> Result<std::path::PathBuf> {
123
124        #[cfg(not(target_os = "android"))] {
125            Err(Error::NOT_ANDROID)
126        }
127        #[cfg(target_os = "android")] {
128            self.impls().resolve_outside_private_dir_path(volume_id, dir).await
129        }
130    }
131
132    /// Gets a list of currently available storage volumes (internal storage, SD card, USB drive, etc.).
133    /// Be aware of TOCTOU.
134    /// 
135    /// Since read-only SD cards and similar cases may be included, 
136    /// please use [`StorageVolume { is_readonly, .. }`](StorageVolume) for filtering as needed.
137    /// 
138    /// This function returns only storage volume that is considered stable by system. 
139    /// It includes device’s built-in storage and physical media slots under protective covers,
140    /// but does not include storage volume considered temporary, 
141    /// such as USB flash drives connected to handheld devices.
142    /// 
143    /// This typically includes [`primary storage volume`](PrivateStorage::get_primary_volume),
144    /// but it may occasionally be absent if primary torage volume is inaccessible 
145    /// (e.g., mounted on a computer, removed, or another issue).
146    ///
147    /// Primary storage volume is always listed first, if included. 
148    /// But the order of the others is not guaranteed.  
149    /// 
150    /// # Note
151    /// The volume represents the logical view of a storage volume for an individual user:
152    /// each user may have a different view for the same physical volume.
153    /// In other words, it provides a separate area for each user in a multi-user environment.
154    /// 
155    /// # Support
156    /// All Android version.
157    #[maybe_async]
158    pub fn get_volumes(&self) -> Result<Vec<StorageVolume>> {
159        #[cfg(not(target_os = "android"))] {
160            Err(Error::NOT_ANDROID)
161        }
162        #[cfg(target_os = "android")] {
163            self.impls().get_available_storage_volumes_for_private_storage().await
164        }
165    }
166
167    /// Gets a primary storage volume.  
168    /// In many cases, it is device's built-in storage. 
169    /// 
170    /// A device always has one (and one only) primary storage volume.  
171    /// 
172    /// Primary volume may not currently be accessible 
173    /// if it has been mounted by the user on their computer, 
174    /// has been removed from the device, or some other problem has happened. 
175    /// If so, this returns `None`.
176    /// 
177    /// # Note
178    /// The volume represents the logical view of a storage volume for an individual user:
179    /// each user may have a different view for the same physical volume.
180    /// In other words, it provides a separate area for each user in a multi-user environment.
181    /// 
182    /// # Support
183    /// All Android version.
184    #[maybe_async]
185    pub fn get_primary_volume(&self) -> Result<Option<StorageVolume>> {
186        #[cfg(not(target_os = "android"))] {
187            Err(Error::NOT_ANDROID)
188        }
189        #[cfg(target_os = "android")] {
190            self.impls().get_primary_storage_volume_if_available_for_private_storage().await
191        }
192    }
193
194
195    /// This is same as [`FileUri::from_path`]
196    #[deprecated = "use `FileUri::from_path` instead"]
197    #[maybe_async]
198    pub fn resolve_uri(
199        &self, 
200        dir: PrivateDir,
201        relative_path: impl AsRef<std::path::Path>
202    ) -> Result<FileUri> {
203
204        #[cfg(not(target_os = "android"))] {
205            Err(Error::NOT_ANDROID)
206        }
207        #[cfg(target_os = "android")] {
208            let mut path = self.resolve_path(dir).await?;
209            path.push(relative_path.as_ref());
210            Ok(path.into())
211        }
212    }
213}
214
215/*
216#[allow(unused)]
217impl<'a, R: tauri::Runtime> PrivateStorage<'a, R> {
218
219    pub(crate) fn create_new_tmp_file(&self) -> crate::Result<(std::fs::File, std::path::PathBuf)> {
220        on_android!({
221            let tmp_file_path = {
222                use std::sync::atomic::{AtomicUsize, Ordering};
223
224                static COUNTER: AtomicUsize = AtomicUsize::new(0);
225                let id = COUNTER.fetch_add(1, Ordering::Relaxed);
226
227                let tmp_dir_path = self.resolve_tmp_dir()?;
228                let _ = std::fs::create_dir_all(&tmp_dir_path);
229            
230                tmp_dir_path.join(format!("{id}"))
231            };
232            
233            let tmp_file = std::fs::File::create_new(&tmp_file_path)?;
234
235            Ok((tmp_file, tmp_file_path))
236        })
237    }
238
239    pub(crate) fn remove_all_tmp_files(&self) -> crate::Result<()> {
240        on_android!({
241            match std::fs::remove_dir_all(self.resolve_tmp_dir()?) {
242                Ok(_) => Ok(()),
243                Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),
244                Err(e) => Err(e.into()),
245            }
246        })
247    }
248
249    pub(crate) fn resolve_tmp_dir(&self) -> crate::Result<std::path::PathBuf> {
250        on_android!({
251            const TMP_DIR_RELATIVE_PATH: &str = "pluginAndroidFs-tmpDir-01K486FKQ2BZSBGFD34RFH9FWJ";
252
253            let mut path = self.resolve_path(PrivateDir::Cache)?;
254            path.push(TMP_DIR_RELATIVE_PATH);
255            Ok(path)
256        })
257    }
258} */