tauri_plugin_android_fs/
lib.rs

1//! Overview and usage is [here](https://crates.io/crates/tauri-plugin-android-fs)
2
3mod models;
4mod impls;
5mod error;
6
7use std::io::{Read, Write};
8
9pub use models::*;
10#[allow(deprecated)]
11pub use error::{Error, Result, PathError};
12pub use impls::{AndroidFsExt, init};
13
14/// API
15pub trait AndroidFs<R: tauri::Runtime> {
16
17    /// Verify whether this plugin is available.  
18    /// 
19    /// On Android, this returns true.  
20    /// On other platforms, this returns false.  
21    fn is_available(&self) -> bool {
22        #[cfg(not(target_os = "android"))] {
23            false
24        }
25        #[cfg(target_os = "android")] {
26            true
27        }
28    }
29
30    /// Get the file or directory name.  
31    /// 
32    /// # Support
33    /// All Android version.
34    fn get_name(&self, uri: &FileUri) -> crate::Result<String>;
35
36    /// Query the provider to get mime type.  
37    /// If the directory, this returns `None`.  
38    /// If the file, this returns no `None`.  
39    /// If the file type is unknown or unset, this returns `Some("application/octet-stream")`.  
40    ///
41    /// # Support
42    /// All Android version.
43    fn get_mime_type(&self, uri: &FileUri) -> crate::Result<Option<String>>;
44
45    /// Queries the file system to get information about a file, directory.
46    /// 
47    /// # Note
48    /// This uses [`AndroidFs::open_file`] internally.
49    /// 
50    /// # Support
51    /// All Android version.
52    fn get_metadata(&self, uri: &FileUri) -> crate::Result<std::fs::Metadata> {
53        let file = self.open_file(uri, FileAccessMode::Read)?;
54        Ok(file.metadata()?)
55    }
56
57    /// Open a file in the specified mode.
58    /// 
59    /// # Note
60    /// Other than [`FileAccessMode::Read`] is only for **writable** uri.
61    /// 
62    /// # Support
63    /// All Android version.
64    fn open_file(&self, uri: &FileUri, mode: FileAccessMode) -> crate::Result<std::fs::File>;
65
66    /// Reads the entire contents of a file into a bytes vector.  
67    /// 
68    /// If you need to operate the file, use [`AndroidFs::open_file`] instead.  
69    /// 
70    /// # Support
71    /// All Android version.
72    fn read(&self, uri: &FileUri) -> crate::Result<Vec<u8>> {
73        let mut file = self.open_file(uri, FileAccessMode::Read)?;
74        let mut buf = file.metadata().ok()
75            .map(|m| m.len() as usize)
76            .map(Vec::with_capacity)
77            .unwrap_or_else(Vec::new);
78
79        file.read_to_end(&mut buf)?;
80        Ok(buf)
81    }
82
83    /// Reads the entire contents of a file into a string.  
84    /// 
85    /// If you need to operate the file, use [`AndroidFs::open_file`] instead.  
86    /// 
87    /// # Support
88    /// All Android version.
89    fn read_to_string(&self, uri: &FileUri) -> crate::Result<String> {
90        let mut file = self.open_file(uri, FileAccessMode::Read)?;
91        let mut buf = file.metadata().ok()
92            .map(|m| m.len() as usize)
93            .map(String::with_capacity)
94            .unwrap_or_else(String::new);
95    
96        file.read_to_string(&mut buf)?;
97        Ok(buf)
98    }
99
100    /// Writes a slice as the entire contents of a file.  
101    /// This function will entirely replace its contents if it does exist.    
102    /// 
103    /// If you want to operate the file, use [`AndroidFs::open_file`] instead.  
104    /// 
105    /// # Note
106    /// This is only for **writable** file uri.
107    /// 
108    /// # Support
109    /// All Android version.
110    fn write(&self, uri: &FileUri, contents: impl AsRef<[u8]>) -> crate::Result<()> {
111        let mut file = self.open_file(uri, FileAccessMode::WriteTruncate)?;
112        file.write_all(contents.as_ref())?;
113        Ok(())
114    }
115
116    /// Remove the file.
117    /// 
118    /// # Note
119    /// This is only for **removeable** uri.
120    /// 
121    /// # Support
122    /// All Android version.
123    fn remove_file(&self, uri: &FileUri) -> crate::Result<()>;
124
125    /// Remove the **empty** directory.
126    /// 
127    /// # Note
128    /// This is only for **removeable** uri.
129    /// 
130    /// # Support
131    /// All Android version.
132    fn remove_dir(&self, uri: &FileUri) -> crate::Result<()>;
133
134    /// Creates a new empty file at the specified directory, and returns **read-write-removeable** uri.    
135    /// If the same file name already exists, a sequential number is added to the name. And recursively create sub directories if they are missing.  
136    /// 
137    /// If you want to create a new file without a `FileUri`, use [`AndroidFs::create_file_in_public_location`].
138    /// 
139    /// # Note
140    /// `mime_type`  specify the type of the file to be created. 
141    /// It should be provided whenever possible. If not specified, `application/octet-stream` is used, as generic, unknown, or undefined file types.  
142    /// 
143    /// # Support
144    /// All Android version.
145    fn create_file(
146        &self,
147        dir: &FileUri, 
148        relative_path: impl AsRef<str>, 
149        mime_type: Option<&str>
150    ) -> crate::Result<FileUri>;
151
152    /// Please use [`PublicStorage::create_file_in_public_app_dir`] insted.
153    #[deprecated = "Please use PublicStorage::create_file_in_public_app_dir insted."]
154    #[warn(deprecated)]
155    fn create_file_in_public_location(
156        &self,
157        dir: impl Into<PublicDir>,
158        relative_path: impl AsRef<str>, 
159        mime_type: Option<&str>
160    ) -> crate::Result<FileUri> {
161
162        self.public_storage().create_file_in_public_app_dir(dir, relative_path, mime_type)
163    }
164
165    /// Returns the unordered child entries of the specified directory.  
166    /// Returned [`Entry`](crate::Entry) contains file or directory uri.
167    ///
168    /// # Note
169    /// By default, children are valid until the app is terminated.  
170    /// To persist it across app restarts, use [`AndroidFs::take_persistable_uri_permission`]. 
171    /// However, if you have obtained persistent permissions for the origin directory (e.g. parent, grand parents), it is unnecessary.
172    /// 
173    /// The returned type is an iterator because of the data formatting and the file system call is not executed lazily.
174    /// 
175    /// # Support
176    /// All Android version.
177    fn read_dir(&self, uri: &FileUri) -> crate::Result<impl Iterator<Item = Entry>>;
178
179    /// Take persistent permission to access the file, directory and its descendants.  
180    /// 
181    /// Preserve access across app and device restarts. 
182    /// If you only need it until the end of the app session, you do not need to use this.  
183    /// 
184    /// This works by just calling, without displaying any confirmation to the user.  
185    /// 
186    /// # Note
187    /// Even after calling this, the app doesn't retain access to the entry if it is moved or deleted.  
188    /// 
189    /// # Support
190    /// All Android version.
191    fn take_persistable_uri_permission(&self, uri: FileUri, mode: PersistableAccessMode) -> crate::Result<()>;
192
193    /// Open a dialog for file selection.  
194    /// This returns a **read-only** uris. If no file is selected or canceled by user, it is an empty.  
195    /// 
196    /// For images and videos, consider using [`AndroidFs::show_open_visual_media_dialog`] instead.  
197    /// 
198    /// # Issue
199    /// **Dialog has an issue. Details and resolution are following.**  
200    /// - <https://github.com/aiueo13/tauri-plugin-android-fs/issues/1>
201    /// - <https://github.com/aiueo13/tauri-plugin-android-fs/blob/main/README.md>
202    /// 
203    /// # Note
204    /// `mime_types` represents the types of files that should be selected. 
205    /// However, there is no guarantee that the returned file will match the specified types.    
206    /// If this is empty, all file types will be available for selection. 
207    /// This is equivalent to `["*/*"]`, and it will invoke the standard file picker in most cases.  
208    /// 
209    /// By default, returned uri is valid until the app is terminated. 
210    /// If you want to persist it across app restarts, use [`AndroidFs::take_persistable_uri_permission`].
211    /// 
212    /// # Support
213    /// All Android version.
214    fn show_open_file_dialog(
215        &self,
216        mime_types: &[&str],
217        multiple: bool
218    ) -> crate::Result<Vec<FileUri>>;
219
220    /// Opens a dialog for media file selection, such as images and videos.  
221    /// This returns a **read-only** uris. If no file is selected or canceled by user, it is an empty.  
222    /// 
223    /// This is more user-friendly than [`AndroidFs::show_open_file_dialog`].  
224    ///
225    /// # Issue
226    /// **Dialog has an issue. Details and resolution are following.**  
227    /// - <https://github.com/aiueo13/tauri-plugin-android-fs/issues/1>
228    /// - <https://github.com/aiueo13/tauri-plugin-android-fs/blob/main/README.md>
229    /// 
230    /// # Note
231    /// By default, returned uri is valid until the app is terminated. 
232    /// If you want to persist it across app restarts, use [`AndroidFs::take_persistable_uri_permission`].  
233    /// 
234    /// The file obtained from this function cannot retrieve the correct file name using [`AndroidFs::get_name`].
235    /// Instead, it will be assigned a sequential number, such as `1000091523.png`.  
236    /// <https://issuetracker.google.com/issues/268079113>  
237    ///
238    /// # Support
239    /// This is available on devices that meet the following criteria:
240    ///  - Run Android 11 (API level 30) or higher
241    ///  - Receive changes to Modular System Components through Google System Updates
242    ///  
243    /// Availability on a given device can be verified by calling [`AndroidFs::is_visual_media_dialog_available`].  
244    /// If not supported, this functions the same as [`AndroidFs::show_open_file_dialog`].
245    fn show_open_visual_media_dialog(
246        &self,
247        target: VisualMediaTarget,
248        multiple: bool
249    ) -> crate::Result<Vec<FileUri>>;
250
251    /// Open a dialog for directory selection,
252    /// allowing the app to read and write any file in the selected directory and its subdirectories.  
253    /// If canceled by the user, return None.    
254    /// 
255    /// # Issue
256    /// **Dialog has an issue. Details and resolution are following.**  
257    /// - <https://github.com/aiueo13/tauri-plugin-android-fs/issues/1>
258    /// - <https://github.com/aiueo13/tauri-plugin-android-fs/blob/main/README.md>
259    /// 
260    /// # Note
261    /// By default, retruned uri is valid until the app is terminated. 
262    /// If you want to persist it across app restarts, use [`AndroidFs::take_persistable_uri_permission`].
263    /// If you take permission for a directory, you can recursively obtain it for its descendants.
264    /// 
265    /// # Support
266    /// All Android version.
267    fn show_open_dir_dialog(&self) -> crate::Result<Option<FileUri>>;
268
269    /// Open a dialog for file saving, and return the selected path.  
270    /// This returns a **read-write-removeable** uri. If canceled by the user, return None.    
271    /// 
272    /// When storing media files such as images, videos, and audio, consider using [`AndroidFs::create_file_in_public_location`].  
273    /// When a file does not need to be accessed by other applications and users, consider using  [`PrivateStorage::write`].  
274    /// These are easier because the destination does not need to be selected in a dialog.  
275    /// 
276    /// # Issue
277    /// **Dialog has an issue. Details and resolution are following.**  
278    /// - <https://github.com/aiueo13/tauri-plugin-android-fs/issues/1>
279    /// - <https://github.com/aiueo13/tauri-plugin-android-fs/blob/main/README.md>
280    /// 
281    /// # Note
282    /// `mime_type` specify the type of the target file to be saved. 
283    /// It should be provided whenever possible. If not specified, `application/octet-stream` is used, as generic, unknown, or undefined file types.  
284    /// 
285    /// By default, returned uri is valid until the app is terminated. 
286    /// If you want to persist it across app restarts, use [`AndroidFs::take_persistable_uri_permission`].
287    /// 
288    /// # Support
289    /// All Android version.
290    fn show_save_file_dialog(
291        &self,
292        default_file_name: impl AsRef<str>,
293        mime_type: Option<&str>,
294    ) -> crate::Result<Option<FileUri>>;
295
296    /// Verify whether [`AndroidFs::show_open_visual_media_dialog`] is available on a given device.
297    /// 
298    /// # Support
299    /// All Android version.
300    fn is_visual_media_dialog_available(&self) -> crate::Result<bool>;
301
302    /// Please use [`PublicStorage::is_audiobooks_dir_available`] insted.
303    #[deprecated(note = "Please use PublicStorage::is_audiobooks_dir_available insted.")]
304    #[warn(deprecated)]
305    fn is_public_audiobooks_dir_available(&self) -> crate::Result<bool> {
306        self.public_storage().is_audiobooks_dir_available()
307    }
308
309    /// Please use [`PublicStorage::is_recordings_dir_available`] insted.
310    #[deprecated(note = "Please use PublicStorage::is_recordings_dir_available insted.")]
311    #[warn(deprecated)]
312    fn is_public_recordings_dir_available(&self) -> crate::Result<bool> {
313        self.public_storage().is_recordings_dir_available()
314    }
315
316    fn app_handle(&self) -> &tauri::AppHandle<R>;
317
318    /// File storage API intended for the app’s use only.
319    fn private_storage(&self) -> &impl PrivateStorage<R>;
320
321    /// File storage that is available to other applications and users.
322    fn public_storage(&self) -> &impl PublicStorage<R>;
323}
324
325/// File storage intended for the app’s use only.  
326pub trait PublicStorage<R: tauri::Runtime> {
327
328    /// Creates a new empty file at the specified public app directory, and returns **read-write-removeable** uri.    
329    /// If the same file name already exists, a sequential number is added to the name. And recursively create sub directories if they are missing.  
330    /// 
331    /// # Note
332    /// `mime_type`  specify the type of the file to be created. 
333    /// It should be provided whenever possible. If not specified, `application/octet-stream` is used, as generic, unknown, or undefined file types.  
334    /// 
335    /// When using [`PublicImageDir`], please do not use a `mime_type` other than image types.
336    /// This may result in an error.
337    /// Similarly, do not use non-corresponding media types for [`PublicVideoDir`] or [`PublicAudioDir`]. 
338    /// Only [`PublicGeneralPurposeDir`] allows all mime types.
339    /// 
340    /// # Support
341    /// Android 10 (API level 29) or higher.  
342    /// Lower are need runtime request of `WRITE_EXTERNAL_STORAGE`. (This option will be made available in the future)
343    /// 
344    /// [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
345    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
346    /// [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
347    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
348    /// Others are available in all Android versions.
349    fn create_file_in_public_app_dir(
350        &self,
351        dir: impl Into<PublicDir>,
352        relative_path: impl AsRef<str>, 
353        mime_type: Option<&str>
354    ) -> crate::Result<FileUri> {
355
356        let app = self.app_handle().config();
357        let app_name = app.product_name.as_ref().unwrap_or(&app.identifier).replace('/', " ");
358        let relative_path = relative_path.as_ref().trim_start_matches('/');
359        let relative_path_with_subdir = format!("{app_name}/{relative_path}");
360
361        self.create_file_in_public_dir(dir, relative_path_with_subdir, mime_type)
362    }
363
364    /// Creates a new empty file at the specified public directory, and returns **read-write-removeable** uri.    
365    /// If the same file name already exists, a sequential number is added to the name. And recursively create sub directories if they are missing.  
366    /// 
367    /// # Note
368    /// Do not save files directly in the public directory. Please specify a subdirectory in the `relative_path_with_sub_dir`, such as `appName/file.txt` or `appName/2025-2-11/file.txt`. Do not use `file.txt`.
369    /// 
370    /// `mime_type`  specify the type of the file to be created. 
371    /// It should be provided whenever possible. If not specified, `application/octet-stream` is used, as generic, unknown, or undefined file types.  
372    /// 
373    /// When using [`PublicImageDir`], please do not use a `mime_type` other than image types.
374    /// This may result in an error.
375    /// Similarly, do not use non-corresponding media types for [`PublicVideoDir`] or [`PublicAudioDir`]. 
376    /// Only [`PublicGeneralPurposeDir`] allows all mime types.
377    /// 
378    /// # Support
379    /// Android 10 (API level 29) or higher.  
380    /// Lower are need runtime request of `WRITE_EXTERNAL_STORAGE`. (This option will be made available in the future)
381    ///
382    /// [`PublicAudioDir::Audiobooks`] is not available on Android 9 (API level 28) and lower.
383    /// Availability on a given device can be verified by calling [`PublicStorage::is_audiobooks_dir_available`].  
384    /// [`PublicAudioDir::Recordings`] is not available on Android 11 (API level 30) and lower.
385    /// Availability on a given device can be verified by calling [`PublicStorage::is_recordings_dir_available`].  
386    /// Others are available in all Android versions.
387    fn create_file_in_public_dir(
388        &self,
389        dir: impl Into<PublicDir>,
390        relative_path_with_subdir: impl AsRef<str>, 
391        mime_type: Option<&str>
392    ) -> crate::Result<FileUri>;
393
394    /// Verify whether [`PublicAudioDir::Audiobooks`] is available on a given device.
395    /// 
396    /// # Support
397    /// All Android version.
398    fn is_audiobooks_dir_available(&self) -> crate::Result<bool>;
399
400    /// Verify whether [`PublicAudioDir::Recordings`] is available on a given device.
401    /// 
402    /// # Support
403    /// All Android version.
404    fn is_recordings_dir_available(&self) -> crate::Result<bool>;
405
406    fn app_handle(&self) -> &tauri::AppHandle<R>;
407}
408
409/// File storage intended for the app’s use only.  
410pub trait PrivateStorage<R: tauri::Runtime> {
411
412    /// Get the absolute path of the specified directory.  
413    /// Apps require no permissions to read or write to the returned path, since this path lives in their private storage.  
414    ///
415    /// These files will be deleted when the app is uninstalled and may also be deleted at the user’s request. 
416    /// When using [`PrivateDir::Cache`], the system will automatically delete files in this directory as disk space is needed elsewhere on the device.   
417    /// 
418    /// The returned path may change over time if the calling app is moved to an adopted storage device, so only relative paths should be persisted.   
419    /// 
420    /// # Examples
421    /// ```no_run
422    /// use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, PrivateDir, PrivateStorage};
423    /// 
424    /// fn example(app: tauri::AppHandle) {
425    ///     let api = app.android_fs().private_storage();
426    /// 
427    ///     let dir_path = api.resolve_path(PrivateDir::Data).unwrap();
428    ///     let file_path = dir_path.join("2025-2-12/data.txt");
429    ///     
430    ///     // Write file
431    ///     std::fs::create_dir_all(file_path.parent().unwrap()).unwrap();
432    ///     std::fs::write(&file_path, "aaaa").unwrap();
433    /// 
434    ///     // Read file
435    ///     let _ = std::fs::read_to_string(&file_path).unwrap();
436    /// 
437    ///     // Remove file
438    ///     std::fs::remove_file(&file_path).unwrap();
439    /// }
440    /// ```
441    /// 
442    /// # Support
443    /// All Android version.
444    fn resolve_path(&self, dir: PrivateDir) -> crate::Result<std::path::PathBuf>;
445
446    /// Get the absolute path of the specified relative path and base directory.  
447    /// Apps require no extra permissions to read or write to the returned path, since this path lives in their private storage.  
448    ///
449    /// See [`PrivateStorage::resolve_path`] for details.  
450    /// 
451    /// # Support
452    /// All Android version.
453    fn resolve_path_with(
454        &self,
455        dir: PrivateDir,
456        relative_path: impl AsRef<str>
457    ) -> crate::Result<std::path::PathBuf> {
458
459        let relative_path = relative_path.as_ref().trim_start_matches('/');
460        let path = self.resolve_path(dir)?.join(relative_path);
461        Ok(path)
462    }
463
464    fn resolve_uri(&self, dir: PrivateDir) -> crate::Result<FileUri> {
465        Ok(FileUri::from(tauri_plugin_fs::FilePath::Path(self.resolve_path(dir)?)))
466    }
467
468    fn resolve_uri_with(&self, dir: PrivateDir, relative_path: impl AsRef<str>) -> crate::Result<FileUri> {
469        Ok(FileUri::from(tauri_plugin_fs::FilePath::Path(self.resolve_path_with(dir, relative_path)?)))
470    }
471
472    /// Writes a slice as the entire contents of a file.  
473    /// 
474    /// This function will create a file if it does not exist, and will entirely replace its contents if it does.  
475    /// Recursively create parent directories if they are missing.  
476    /// 
477    /// This internally uses [`PrivateStorage::resolve_path`] , [`std::fs::create_dir_all`], and [`std::fs::write`].  
478    /// See [`PrivateStorage::resolve_path`] for details.  
479    /// 
480    /// # Support
481    /// All Android version.
482    fn write(
483        &self, 
484        base_dir: PrivateDir, 
485        relative_path: impl AsRef<str>, 
486        contents: impl AsRef<[u8]>
487    ) -> crate::Result<()> {
488
489        let path = self.resolve_path_with(base_dir, relative_path)?;
490
491        if let Some(parent_dir) = path.parent() {
492            std::fs::create_dir_all(parent_dir)?;
493        }
494
495        std::fs::write(path, contents)?;
496
497        Ok(())
498    }
499
500    /// Open a file in read-only mode.  
501    /// 
502    /// If you only need to read the entire file contents, consider using [`PrivateStorage::read`]  or [`PrivateStorage::read_to_string`] instead.  
503    /// 
504    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::File::open`].  
505    /// See [`PrivateStorage::resolve_path`] for details.  
506    /// 
507    /// # Support
508    /// All Android version.
509    fn open_file(
510        &self,
511        base_dir: PrivateDir, 
512        relative_path: impl AsRef<str>, 
513    ) -> crate::Result<std::fs::File> {
514
515        let path = self.resolve_path_with(base_dir, relative_path)?;
516        Ok(std::fs::File::open(path)?)
517    }
518
519    /// Opens a file in write-only mode.  
520    /// This function will create a file if it does not exist, and will truncate it if it does.
521    /// 
522    /// If you only need to write the contents, consider using [`PrivateStorage::write`]  instead.  
523    /// 
524    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::File::create`].  
525    /// See [`PrivateStorage::resolve_path`] for details.  
526    /// 
527    /// # Support
528    /// All Android version.
529    fn create_file(
530        &self,
531        base_dir: PrivateDir, 
532        relative_path: impl AsRef<str>, 
533    ) -> crate::Result<std::fs::File> {
534
535        let path = self.resolve_path_with(base_dir, relative_path)?;
536        Ok(std::fs::File::create(path)?)
537    }
538
539    /// Creates a new file in read-write mode; error if the file exists. 
540    /// 
541    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::File::create_new`].  
542    /// See [`PrivateStorage::resolve_path`] for details.  
543    /// 
544    /// # Support
545    /// All Android version.
546    fn create_new_file(
547        &self,
548        base_dir: PrivateDir, 
549        relative_path: impl AsRef<str>, 
550    ) -> crate::Result<std::fs::File> {
551
552        let path = self.resolve_path_with(base_dir, relative_path)?;
553        Ok(std::fs::File::create_new(path)?)
554    }
555
556    /// Reads the entire contents of a file into a bytes vector.  
557    /// 
558    /// If you need [`std::fs::File`], use [`PrivateStorage::open_file`] insted.  
559    /// 
560    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::read`].  
561    /// See [`PrivateStorage::resolve_path`] for details.  
562    /// 
563    /// # Support
564    /// All Android version.
565    fn read(
566        &self,
567        base_dir: PrivateDir, 
568        relative_path: impl AsRef<str>, 
569    ) -> crate::Result<Vec<u8>> {
570
571        let path = self.resolve_path_with(base_dir, relative_path)?;
572        Ok(std::fs::read(path)?)
573    }
574
575    /// Reads the entire contents of a file into a string.  
576    /// 
577    /// If you need [`std::fs::File`], use [`PrivateStorage::open_file`] insted.  
578    /// 
579    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::read_to_string`].  
580    /// See [`PrivateStorage::resolve_path`] for details.  
581    /// 
582    /// # Support
583    /// All Android version.
584    fn read_to_string(
585        &self,
586        base_dir: PrivateDir,
587        relative_path: impl AsRef<str>, 
588    ) -> crate::Result<String> {
589
590        let path = self.resolve_path_with(base_dir, relative_path)?;
591        Ok(std::fs::read_to_string(path)?)
592    }
593
594    /// Returns an iterator over the entries within a directory.
595    /// 
596    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::read_dir`].  
597    /// See [`PrivateStorage::resolve_path`] for details.  
598    /// 
599    /// # Support
600    /// All Android version.
601    fn read_dir(
602        &self,
603        base_dir: PrivateDir,
604        relative_path: Option<&str>,
605    ) -> crate::Result<std::fs::ReadDir> {
606
607        let path = match relative_path {
608            Some(relative_path) => self.resolve_path_with(base_dir, relative_path)?,
609            None => self.resolve_path(base_dir)?,
610        };
611
612        Ok(std::fs::read_dir(path)?)
613    }
614
615    /// Removes a file from the filesystem.  
616    /// 
617    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::remove_file`].  
618    /// See [`PrivateStorage::resolve_path`] for details.  
619    /// 
620    /// # Support
621    /// All Android version.
622    fn remove_file(
623        &self,
624        base_dir: PrivateDir,
625        relative_path: impl AsRef<str>,
626    ) -> crate::Result<()> {
627
628        let path = self.resolve_path_with(base_dir, relative_path)?;
629        Ok(std::fs::remove_file(path)?)
630    }
631
632    /// Removes an empty directory.  
633    /// If you want to remove a directory that is not empty, as well as all of its contents recursively, consider using [`PrivateStorage::remove_dir_all`] instead.  
634    /// 
635    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::remove_dir`].  
636    /// See [`PrivateStorage::resolve_path`] for details.  
637    /// 
638    /// # Support
639    /// All Android version.
640    fn remove_dir(
641        &self,
642        base_dir: PrivateDir,
643        relative_path: Option<&str>,
644    ) -> crate::Result<()> {
645
646        let path = match relative_path {
647            Some(relative_path) => self.resolve_path_with(base_dir, relative_path)?,
648            None => self.resolve_path(base_dir)?,
649        };
650
651        std::fs::remove_dir(path)?;
652        Ok(())
653    }
654
655    /// Removes a directory at this path, after removing all its contents. Use carefully!  
656    /// 
657    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::remove_dir_all`].  
658    /// See [`PrivateStorage::resolve_path`] for details.  
659    /// 
660    /// # Support
661    /// All Android version.
662    fn remove_dir_all(
663        &self,
664        base_dir: PrivateDir,
665        relative_path: Option<&str>,
666    ) -> crate::Result<()> {
667
668        let path = match relative_path {
669            Some(relative_path) => self.resolve_path_with(base_dir, relative_path)?,
670            None => self.resolve_path(base_dir)?,
671        };
672
673        std::fs::remove_dir_all(path)?;
674        Ok(())
675    }
676
677    /// Returns Ok(true) if the path points at an existing entity.  
678    /// 
679    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::exists`].  
680    /// See [`PrivateStorage::resolve_path`] for details.  
681    /// 
682    /// # Support
683    /// All Android version.
684    fn exists(
685        &self,
686        base_dir: PrivateDir,
687        relative_path: impl AsRef<str>
688    ) -> crate::Result<bool> {
689
690        let path = self.resolve_path_with(base_dir, relative_path)?;
691        Ok(std::fs::exists(path)?)
692    }
693
694    /// Queries the file system to get information about a file, directory.  
695    /// 
696    /// This internally uses [`PrivateStorage::resolve_path`] and [`std::fs::metadata`].  
697    /// See [`PrivateStorage::resolve_path`] for details.  
698    /// 
699    /// # Support
700    /// All Android version.
701    fn metadata(
702        &self,
703        base_dir: PrivateDir,
704        relative_path: Option<&str>,
705    ) -> crate::Result<std::fs::Metadata> {
706
707        let path = match relative_path {
708            Some(relative_path) => self.resolve_path_with(base_dir, relative_path)?,
709            None => self.resolve_path(base_dir)?,
710        };
711
712        Ok(std::fs::metadata(path)?)
713    }
714
715    fn app_handle(&self) -> &tauri::AppHandle<R>;
716}