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