tauri_plugin_android_fs/
lib.rs

1//! # Overview
2//!
3//! The Android file system is strict and complex because its behavior and the available APIs vary depending on the version.  
4//! This plugin was created to provide explicit and consistent file operations.  
5//! No special permission or configuration is required.  
6//!
7//! # Setup
8//! All you need to do is register the core plugin with Tauri: 
9//!
10//! `src-tauri/src/lib.rs`
11//!
12//! ```no_run
13//! #[cfg_attr(mobile, tauri::mobile_entry_point)]
14//! pub fn run() {
15//!    tauri::Builder::default()
16//!        .plugin(tauri_plugin_android_fs::init()) // This
17//!        .run(tauri::generate_context!())
18//!        .expect("error while running tauri application");
19//! }
20//! ```
21//!
22//! # Usage
23//! There are three main ways to manipulate files:
24//!
25//! ### 1. Dialog
26//! Opens the file picker to read and write user-selected files.
27//!
28//! ```no_run
29//! use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, VisualMediaTarget};
30//!
31//! fn read_files(app: tauri::AppHandle) {
32//!     let api = app.android_fs();
33//!     let selected_paths = api.show_open_file_dialog(&["*/*"], true).unwrap();
34//!
35//!     if selected_paths.is_empty() {
36//!         // Handle cancellation
37//!     }
38//!     else {
39//!         for path in selected_paths {
40//!             let file_name = api.get_file_name(&path).unwrap();
41//!             let file: std::fs::File = api.open_file(&path).unwrap();
42//!         }
43//!     }
44//! }
45//!
46//! fn write_file(app: tauri::AppHandle) {
47//!     let api = app.android_fs();
48//!     let selected_path = api.show_save_file_dialog("fileName", Some("image/png")).unwrap();
49//!
50//!     if let Some(path) = selected_path {
51//!         let mut file: std::fs::File = api.open_file_writable(&path).unwrap();
52//!     }
53//!     else {
54//!         // Handle cancellation
55//!     }
56//! }
57//! ```
58//!
59//! ### 2. Public Storage
60//! File storage intended to be shared with other apps and user.
61//!
62//! ```no_run
63//! use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, PublicImageDir, PublicStorage};
64//!
65//! fn example(app: tauri::AppHandle) {
66//!     let api = app.android_fs().public_storage();
67//!     let contents: Vec<u8> = todo!();
68//!
69//!     api.write_image(
70//!         PublicImageDir::Pictures,
71//!         "myApp/2025-02-13.png",
72//!         Some("image/png"),
73//!         &contents
74//!     ).unwrap();
75//! }
76//! ```
77//!
78//! ### 3. Private Storage
79//! File storage intended for the app’s use only.
80//!
81//! ```no_run
82//! use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, PrivateDir, PrivateStorage};
83//!
84//! fn example(app: tauri::AppHandle) {
85//!     let api = app.android_fs().private_storage();
86//!
87//!     // Write data
88//!     api.write(PrivateDir::Data, "config/data1.txt", "data").unwrap();
89//!
90//!     // Read data
91//!     let data = api.read_to_string(PrivateDir::Data, "config/data1.txt").unwrap();
92//!     assert_eq!(data, "data");
93//! }
94//! ```
95//!
96//! # License
97//! MIT OR Apache-2.0
98
99mod models;
100mod impls;
101mod error;
102
103use std::io::{Read, Write};
104
105pub use models::*;
106pub use error::{Error, Result, PathError};
107pub use impls::{AndroidFsExt, init};
108pub use tauri_plugin_fs::FilePath;
109
110
111/// API
112pub trait AndroidFs {
113
114    /// Verify whether this plugin is available.  
115    /// 
116    /// On Android, this returns true.  
117    /// On other platforms, this returns false.  
118    fn is_available(&self) -> bool {
119        #[cfg(not(target_os = "android"))] {
120            false
121        }
122        #[cfg(target_os = "android")] {
123            true
124        }
125    }
126
127    /// Get the file name.  
128    /// 
129    /// `FilePath` can be obtained from functions such as `AndroidFs::show_open_file_dialog`, `AndroidFs::show_open_visual_media_dialog`, or `AndroidFs::show_save_file_dialog`.  
130    /// 
131    /// # Support
132    /// All Android version.
133    fn get_file_name(&self, path: &FilePath) -> crate::Result<String>;
134
135    /// Get the mime type.  
136    /// If the type is unknown, this returns None.  
137    /// 
138    /// `FilePath` can be obtained from functions such as `AndroidFs::show_open_file_dialog`, `AndroidFs::show_open_visual_media_dialog`, or `AndroidFs::show_save_file_dialog`.  
139    /// 
140    /// # Support
141    /// All Android version.
142    fn get_mime_type(&self, path: &FilePath) -> crate::Result<Option<String>>;
143
144    /// Open a file in read-only mode.
145    /// 
146    /// If you only need to read the entire file contents, consider using `AndroidFs::read`  or `AndroidFs::read_to_string` instead.  
147    /// 
148    /// `FilePath` can be obtained from functions such as `AndroidFs::show_open_file_dialog` or `AndroidFs::show_open_visual_media_dialog`.  
149    /// 
150    /// # Support
151    /// All Android version.
152    fn open_file(&self, path: &FilePath) -> crate::Result<std::fs::File>;
153
154    /// Open a file in writable mode from ***writable*** `FilePath`.
155    /// 
156    /// If you only need to write the contents, consider using `AndroidFs::write`  instead.  
157    /// 
158    /// # Note
159    /// A **writable** `FilePath` can be obtained from `AndroidFs::show_save_file_dialog`, 
160    /// but not from `AndroidFs::show_open_file_dialog` or `AndroidFs::show_open_visual_media_dialog`.
161    /// 
162    /// # Support
163    /// All Android version.
164    fn open_file_writable(&self, path: &FilePath) -> crate::Result<std::fs::File>;
165
166    /// Reads the entire contents of a file into a bytes vector.  
167    /// 
168    /// If you need to operate on a readable file, use `AndroidFs::open_file` instead.  
169    /// 
170    /// `FilePath` can be obtained from functions such as `AndroidFs::show_open_file_dialog` or `AndroidFs::show_open_visual_media_dialog`.  
171    /// 
172    /// # Support
173    /// All Android version.
174    fn read(&self, path: &FilePath) -> crate::Result<Vec<u8>> {
175        let mut file = self.open_file(path)?;
176        let mut buf = file.metadata().ok()
177            .map(|m| m.len() as usize)
178            .map(Vec::with_capacity)
179            .unwrap_or_else(Vec::new);
180
181        file.read_to_end(&mut buf)?;
182        Ok(buf)
183    }
184
185    /// Reads the entire contents of a file into a string.  
186    /// 
187    /// If you need to operate on a readable file, use `AndroidFs::open_file` instead.  
188    /// 
189    /// `FilePath` can be obtained from functions such as `AndroidFs::show_open_file_dialog` or `AndroidFs::show_open_visual_media_dialog`.  
190    /// 
191    /// # Support
192    /// All Android version.
193    fn read_to_string(&self, path: &FilePath) -> crate::Result<String> {
194        let mut file = self.open_file(path)?;
195        let mut buf = file.metadata().ok()
196            .map(|m| m.len() as usize)
197            .map(String::with_capacity)
198            .unwrap_or_else(String::new);
199
200        file.read_to_string(&mut buf)?;
201        Ok(buf)
202    }
203
204    /// Writes a slice as the entire contents of a file in a **writable** `FilePath`
205    /// 
206    /// If you need to operate on a writable file, use `AndroidFs::open_file_writable` instead.  
207    /// 
208    /// # Note
209    /// A **writable** `FilePath` can be obtained from `AndroidFs::show_save_file_dialog`, 
210    /// but not from `AndroidFs::show_open_file_dialog` or `AndroidFs::show_visual_media_dialog`.
211    /// 
212    /// # Support
213    /// All Android version.
214    fn write(&self, path: &FilePath, contetns: impl AsRef<[u8]>) -> crate::Result<()> {
215        let mut file = self.open_file_writable(path)?;
216        file.write_all(contetns.as_ref())?;
217        Ok(())
218    }
219
220    /// Open a dialog for file selection.  
221    /// This returns a **readonly** `FilePath`  vec. If no file is selected or canceled by user, it is an empty vec.  
222    /// 
223    /// For images and videos, consider using `AndroidFs::show_open_visiual_media_dialog`  instead.  
224    /// 
225    /// # Note
226    /// `mime_types` represents the types of files that should be selected. 
227    /// However, there is no guarantee that the returned file will match the specified types.    
228    /// If this is empty, all file types will be available for selection. 
229    /// This is equivalent to `["*/*"]`, and it will invoke the standard file picker in most cases.  
230    /// 
231    /// # Support
232    /// All Android version.
233    fn show_open_file_dialog(
234        &self,
235        mime_types: &[&str],
236        multiple: bool
237    ) -> crate::Result<Vec<FilePath>>;
238
239    /// Opens a dialog for media file selection, such as images and videos.  
240    /// This returns a **readonly** `FilePath`  vec. If no file is selected or canceled by user, it is an empty vec.  
241    /// 
242    /// This is more user-friendly than `AndroidFs::show_open_file_dialog`.  
243    ///
244    /// # Note
245    /// The file obtained from this function cannot retrieve the correct file name using `AndroidFs::get_file_name`.
246    /// Instead, it will be assigned a sequential number, such as 1000091523.png.  
247    /// <https://issuetracker.google.com/issues/268079113>  
248    ///  
249    /// # Support
250    /// This is available on devices that meet the following criteria:
251    ///  - Run Android 11 (API level 30) or higher
252    ///  - Receive changes to Modular System Components through Google System Updates
253    ///  
254    /// Availability on a given device can be verified by calling `is_visual_media_dialog_available`.  
255    /// If not supported, this functions the same as `AndroidFs::show_open_file_dialog`.
256    fn show_open_visual_media_dialog(
257        &self,
258        target: VisualMediaTarget,
259        multiple: bool
260    ) -> crate::Result<Vec<FilePath>>;
261
262    /// Open a dialog for file saving, and write contents to the selected file, then return that path.    
263    /// This returns a **writable** `FilePath` . If canceled by the user, return None, and do not write it.  
264    /// 
265    /// When storing media files such as images, videos, and audio, consider using `PublicStorage::write_image` or a similar method.  
266    /// When a file does not need to be accessed by other applications and users, consider using  `PrivateStorage::write`.  
267    /// These are easier because the destination does not need to be selected in a dialog.  
268    /// 
269    /// If you want to operate directly on writable files, use `AndroidFs::show_save_file_dialog`  then `AndroidFs::open_file_writable` insted.  
270    /// 
271    /// # Note
272    /// `mime_type`  specify the type of the target file to be saved. 
273    /// It should be provided whenever possible. If not specified, `application/octet-stream` is used, as generic, unknown, or undefined file types.  
274    /// 
275    /// # Support
276    /// All Android version.
277    fn show_save_file_dialog_with_contents(
278        &self,
279        default_file_name: impl AsRef<str>,
280        mime_type: Option<&str>,
281        contents: impl AsRef<[u8]>,
282    ) -> crate::Result<Option<FilePath>> {
283
284        if let Some(path) = self.show_save_file_dialog(default_file_name, mime_type)? {
285            self.write(&path, contents)?;
286            return Ok(Some(path))
287        }
288        
289        Ok(None)
290    }
291
292    /// Open a dialog for file saving, and return the selected path.  
293    /// This returns a **writable** `FilePath` . If canceled by the user, return None.  
294    /// 
295    /// When storing media files such as images, videos, and audio, consider using `PublicStorage::write_image` or a similar method.  
296    /// When a file does not need to be accessed by other applications and users, consider using  `PrivateStorage::write`.  
297    /// These are easier because the destination does not need to be selected in a dialog.  
298    /// 
299    /// If you only need to write contents, use `AndroidFs::show_save_file_dialog_with_contents` instead.  
300    /// 
301    /// # Note
302    /// `mime_type` specify the type of the target file to be saved. 
303    /// It should be provided whenever possible. If not specified, `application/octet-stream` is used, as generic, unknown, or undefined file types.  
304    /// 
305    /// # Support
306    /// All Android version.
307    fn show_save_file_dialog(
308        &self,
309        default_file_name: impl AsRef<str>,
310        mime_type: Option<&str>,
311    ) -> crate::Result<Option<FilePath>>;
312
313    /// Verify whether `AndroidFs::show_open_visual_media_dialog` is available on a given device.
314    /// 
315    /// # Support
316    /// All Android version.
317    fn is_visual_media_dialog_available(&self) -> crate::Result<bool>;
318
319    /// File storage API intended to be shared with other apps.
320    fn public_storage(&self) -> &impl PublicStorage;
321
322    /// File storage API intended to be shared with other apps.
323    #[deprecated(note = "This is typo. Use `public_storage` instead.")]
324    #[warn(deprecated)]
325    fn pubic_storage(&self) -> &impl PublicStorage;
326
327    /// File storage API intended for the app’s use only.
328    fn private_storage(&self) -> &impl PrivateStorage;
329}
330
331/// File storage API intended to be shared with other apps.  
332pub trait PublicStorage {
333
334    /// Save the contents to public storage.  
335    /// This is used when saving a file for access by other applications and user.  
336    /// 
337    /// When storing media files such as images, videos, and audio, consider using `PublicStorage::write_image` or a similar method.  
338    /// For saving a general-purpose file, it is often better to use `AndroidFs::open_save_file_dialog`.  
339    /// 
340    /// If the same file name already exists, a sequential number is added to the name and saved.  
341    /// 
342    /// If you want to operate directly on writable files, use `PublicStorage::write_with_contents_writer` insted.  
343    /// 
344    /// # Note
345    /// Do not save files directly in the base directory. 
346    /// Please specify a subdirectory in the `relative_path_with_sub_dir`, such as `appName/file.txt` or `appName/2025-2-11/file.txt`. 
347    /// Do not use `file.txt`.  
348    /// 
349    /// # Support
350    /// All Android version.
351    fn write(
352        &self,
353        base_dir: PublicGeneralPurposeDir,
354        relative_path_with_sub_dir: impl AsRef<str>,
355        mime_type: Option<&str>,
356        contents: impl AsRef<[u8]>,
357    ) -> crate::Result<FilePath> {
358
359        self.write_with_contents_writer(
360            base_dir,
361            relative_path_with_sub_dir, 
362            mime_type,
363            |file| file.write_all(contents.as_ref())
364        )
365    }
366
367    /// Save the contents as an image file to public storage.  
368    /// This is used when saving a file for access by other applications and user.  
369    /// 
370    /// If the same file name already exists, a sequential number is added to the name and saved.  
371    /// 
372    /// If you want to operate directly on writable files, use `PublicStorage::write_image_with_contents_writer` insted.  
373    /// 
374    /// # Note
375    /// Do not set a non-image type to `mime_type`, as it may result in an error. 
376    /// Even if the type is an image, if the Android system does not recognize it as such, an error will occur. 
377    /// 
378    /// Do not save files directly in the base directory. 
379    /// Please specify a subdirectory in the `relative_path_with_sub_dir`, such as `appName/file.png` or `appName/2025-2-11/file.png`. 
380    /// Do not use `file.png`.  
381    /// 
382    /// # Support
383    /// All Android version.
384    fn write_image(
385        &self,
386        base_dir: PublicImageDir,
387        relative_path_with_sub_dir: impl AsRef<str>,
388        mime_type: Option<&str>,
389        contents: impl AsRef<[u8]>,
390    ) -> crate::Result<FilePath> {
391
392        self.write_image_with_contents_writer(
393            base_dir,
394            relative_path_with_sub_dir, 
395            mime_type,
396            |file| file.write_all(contents.as_ref())
397        )
398    }
399
400    /// Save the contents as an video file to public storage.  
401    /// This is used when saving a file for access by other applications and user.  
402    /// 
403    /// If the same file name already exists, a sequential number is added to the name and saved.  
404    /// 
405    /// If you want to operate directly on writable files, use `PublicStorage::write_video_with_contents_writer` insted.  
406    /// 
407    /// # Note
408    /// Do not set a non-video type to `mime_type`, as it may result in an error. 
409    /// Even if the type is an video, if the Android system does not recognize it as such, an error will occur.  
410    /// 
411    /// Do not save files directly in the base directory. 
412    /// Please specify a subdirectory in the `relative_path_with_sub_dir, such as `appName/file.mp4` or `appName/2025-2-11/file.mp4`. 
413    /// Do not use `file.mp4`.  
414    /// 
415    /// # Support
416    /// All Android version.
417    fn write_video(
418        &self,
419        base_dir: PublicVideoDir,
420        relative_path_with_sub_dir: impl AsRef<str>,
421        mime_type: Option<&str>,
422        contents: impl AsRef<[u8]>,
423    ) -> crate::Result<FilePath> {
424
425        self.write_video_with_contents_writer(
426            base_dir,
427            relative_path_with_sub_dir, 
428            mime_type,
429            |file| file.write_all(contents.as_ref())
430        )
431    }
432
433    /// Save the contents as an audio file to public storage.  
434    /// This is used when saving a file for access by other applications and user.  
435    /// 
436    /// If the same file name already exists, a sequential number is added to the name and saved.  
437    /// 
438    /// If you want to operate directly on writable files, use `PublicStorage::write_audio_with_contents_writer` insted.  
439    /// 
440    /// # Note
441    /// Do not set a non-audio type to `mime_type`, as it may result in an error. 
442    /// Even if the type is an audio, if the Android system does not recognize it as such, an error will occur.  
443    /// 
444    /// Do not save files directly in the base directory. 
445    /// Please specify a subdirectory in the `relative_path_with_sub_dir`, such as `appName/file.mp3` or `appName/2025-2-11/file.mp3`. 
446    /// Do not use `file.mp3`.  
447    /// 
448    /// # Support
449    /// `PublicAudioDir::Audiobooks` is not available on Android 9 (API level 28) and lower.  
450    /// Availability on a given device can be verified by calling `PublicStorage::is_audiobooks_dir_available`.  
451    /// 
452    /// `PublicAudioDir::Recordings` is not available on Android 11 (API level 30) and lower.  
453    /// Availability on a given device can be verified by calling `PublicStorage::is_recordings_dir_available`.  
454    /// 
455    /// Others are available in all Android versions.  
456    fn write_audio(
457        &self,
458        base_dir: PublicAudioDir,
459        relative_path_with_sub_dir: impl AsRef<str>,
460        mime_type: Option<&str>,
461        contents: impl AsRef<[u8]>,
462    ) -> crate::Result<FilePath> {
463
464        self.write_audio_with_contents_writer(
465            base_dir,
466            relative_path_with_sub_dir, 
467            mime_type,
468            |file| file.write_all(contents.as_ref())
469        )
470    }
471
472    /// See ``PublicStorage::write`` for description.
473    ///
474    /// The following is equivalent to `PublicStorage::write`.  
475    /// ```ignore
476    /// self.write_with_contents_writer(
477    ///     base_dir,
478    ///     relative_path_with_sub_dir, 
479    ///     mime_type,
480    ///     |file| file.write_all(contents)
481    /// )
482    /// ```
483    fn write_with_contents_writer(
484        &self,
485        base_dir: PublicGeneralPurposeDir,
486        relative_path_with_sub_dir: impl AsRef<str>,
487        mime_type: Option<&str>,
488        contents_writer: impl FnOnce(&mut std::fs::File) -> std::io::Result<()>
489    ) -> crate::Result<FilePath>;
490
491    /// See ``PublicStorage::write_image`` for description.
492    ///
493    /// The following is equivalent to `PublicStorage::write_image`.  
494    /// ```ignore
495    /// self.write_image_with_contents_writer(
496    ///     base_dir,
497    ///     relative_path_with_sub_dir, 
498    ///     mime_type,
499    ///     |file| file.write_all(contents)
500    /// )
501    /// ```
502    fn write_image_with_contents_writer(
503        &self,
504        base_dir: PublicImageDir,
505        relative_path_with_sub_dir: impl AsRef<str>,
506        mime_type: Option<&str>,
507        contents_writer: impl FnOnce(&mut std::fs::File) -> std::io::Result<()>
508    ) -> crate::Result<FilePath>;
509
510    /// See ``PublicStorage::write_video`` for description.
511    ///
512    /// The following is equivalent to `PublicStorage::write_video`.  
513    /// ```ignore
514    /// self.write_video_with_contents_writer(
515    ///     base_dir,
516    ///     relative_path_with_sub_dir, 
517    ///     mime_type,
518    ///     |file| file.write_all(contents)
519    /// )
520    /// ```
521    fn write_video_with_contents_writer(
522        &self,
523        base_dir: PublicVideoDir,
524        relative_path_with_sub_dir: impl AsRef<str>,
525        mime_type: Option<&str>,
526        contents_writer: impl FnOnce(&mut std::fs::File) -> std::io::Result<()>
527    ) -> crate::Result<FilePath>;
528
529    /// See ``PublicStorage::write_audio`` for description.
530    ///
531    /// The following is equivalent to `PublicStorage::write_audio`.  
532    /// ```ignore
533    /// self.write_audio_with_contents_writer(
534    ///     base_dir,
535    ///     relative_path_with_sub_dir, 
536    ///     mime_type,
537    ///     |file| file.write_all(contents)
538    /// )
539    /// ```
540    fn write_audio_with_contents_writer(
541        &self,
542        base_dir: PublicAudioDir,
543        relative_path_with_sub_dir: impl AsRef<str>,
544        mime_type: Option<&str>,
545        contents_writer: impl FnOnce(&mut std::fs::File) -> std::io::Result<()>
546    ) -> crate::Result<FilePath>;
547
548    /// Verify whether `PublicAudioDir::Audiobooks` is available on a given device.
549    /// 
550    /// # Support
551    /// All Android version.
552    fn is_audiobooks_dir_available(&self) -> crate::Result<bool>;
553
554    /// Verify whether `PublicAudioDir::Recordings` is available on a given device.
555    /// 
556    /// # Support
557    /// All Android version.
558    fn is_recordings_dir_available(&self) -> crate::Result<bool>;
559}
560
561/// File storage API intended for the app’s use only.  
562pub trait PrivateStorage {
563
564    /// Get the absolute path of the specified directory.  
565    /// Apps require no extra permissions to read or write to the returned path, since this path lives in their private storage.  
566    ///
567    /// These files will be deleted when the app is uninstalled, and may also be deleted by the user.  
568    /// When using `PrivateDir::Cache`, the system will automatically delete files in this directory as disk space is needed elsewhere on the device.   
569    /// 
570    /// 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.   
571    /// 
572    /// # Examples
573    /// ```no_run
574    /// use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, PrivateDir, PrivateStorage};
575    /// 
576    /// fn example(app: tauri::AppHandle) {
577    ///     let api = app.android_fs().private_storage();
578    /// 
579    ///     let dir_path = api.resolve_path(PrivateDir::Data).unwrap();
580    ///     let file_path = dir_path.join("2025-2-12/data.txt");
581    ///     
582    ///     // Write file
583    ///     std::fs::create_dir_all(file_path.parent().unwrap()).unwrap();
584    ///     std::fs::write(&file_path, "aaaa").unwrap();
585    /// 
586    ///     // Read file
587    ///     let _ = std::fs::read_to_string(&file_path).unwrap();
588    /// 
589    ///     // Remove file
590    ///     std::fs::remove_file(&file_path).unwrap();
591    /// 
592    ///     // Remove all files in the dir.
593    ///     std::fs::remove_dir_all(&dir_path).unwrap();
594    /// }
595    /// ```
596    /// 
597    /// # Support
598    /// All Android version.
599    fn resolve_path(&self, dir: PrivateDir) -> crate::Result<std::path::PathBuf>;
600
601    /// Get the absolute path of the specified relative path and base directory.  
602    /// Apps require no extra permissions to read or write to the returned path, since this path lives in their private storage.  
603    ///
604    /// See `PrivateStorage::resolve_path` for details.  
605    /// 
606    /// # Support
607    /// All Android version.
608    fn resolve_path_with(
609        &self,
610        base_dir: PrivateDir,
611        relative_path: impl AsRef<str>
612    ) -> crate::Result<std::path::PathBuf> {
613
614        let relative_path = relative_path.as_ref().trim_start_matches('/');
615        let path = self.resolve_path(base_dir)?.join(relative_path);
616        Ok(path)
617    }
618
619    /// Writes a slice as the entire contents of a file.  
620    /// 
621    /// This function will create a file if it does not exist, and will entirely replace its contents if it does.  
622    /// Recursively create parent directories if they are missing.  
623    /// 
624    /// This internally uses `PrivateStorage::resolve_path` , `std::fs::create_dir_all` , and `std::fs::write`.  
625    /// See `PrivateStorage::resolve_path` for details.  
626    /// 
627    /// # Support
628    /// All Android version.
629    fn write(
630        &self, 
631        base_dir: PrivateDir, 
632        relative_path: impl AsRef<str>, 
633        contents: impl AsRef<[u8]>
634    ) -> crate::Result<()> {
635
636        let path = self.resolve_path_with(base_dir, relative_path)?;
637
638        if let Some(parent_dir) = path.parent() {
639            std::fs::create_dir_all(parent_dir)?;
640        }
641
642        std::fs::write(path, contents)?;
643
644        Ok(())
645    }
646
647    /// Open a file in read-only mode.  
648    /// 
649    /// If you only need to read the entire file contents, consider using `PrivateStorage::read`  or `PrivateStorage::read_to_string` instead.  
650    /// 
651    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::File::open`.  
652    /// See `PrivateStorage::resolve_path` for details.  
653    /// 
654    /// # Support
655    /// All Android version.
656    fn open_file(
657        &self,
658        base_dir: PrivateDir, 
659        relative_path: impl AsRef<str>, 
660    ) -> crate::Result<std::fs::File> {
661
662        let path = self.resolve_path_with(base_dir, relative_path)?;
663        Ok(std::fs::File::open(path)?)
664    }
665
666    /// Reads the entire contents of a file into a bytes vector.  
667    /// 
668    /// If you need `std::fs::File`, use ``PrivateStorage::open_file`` insted.  
669    /// 
670    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::read`.  
671    /// See `PrivateStorage::resolve_path` for details.  
672    /// 
673    /// # Support
674    /// All Android version.
675    fn read(
676        &self,
677        base_dir: PrivateDir, 
678        relative_path: impl AsRef<str>, 
679    ) -> crate::Result<Vec<u8>> {
680
681        let path = self.resolve_path_with(base_dir, relative_path)?;
682        Ok(std::fs::read(path)?)
683    }
684
685    /// Reads the entire contents of a file into a string.  
686    /// 
687    /// If you need `std::fs::File`, use ``PrivateStorage::open_file`` insted.  
688    /// 
689    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::read_to_string`.  
690    /// See `PrivateStorage::resolve_path` for details.  
691    /// 
692    /// # Support
693    /// All Android version.
694    fn read_to_string(
695        &self,
696        base_dir: PrivateDir,
697        relative_path: impl AsRef<str>, 
698    ) -> crate::Result<String> {
699
700        let path = self.resolve_path_with(base_dir, relative_path)?;
701        Ok(std::fs::read_to_string(path)?)
702    }
703
704    /// Returns an iterator over the entries within a directory.
705    /// 
706    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::read_dir`.  
707    /// See `PrivateStorage::resolve_path` for details.  
708    /// 
709    /// # Support
710    /// All Android version.
711    fn read_dir(
712        &self,
713        base_dir: PrivateDir,
714        relative_path: Option<&str>,
715    ) -> crate::Result<std::fs::ReadDir> {
716
717        let path = match relative_path {
718            Some(relative_path) => self.resolve_path_with(base_dir, relative_path)?,
719            None => self.resolve_path(base_dir)?,
720        };
721
722        Ok(std::fs::read_dir(path)?)
723    }
724
725    /// Removes a file from the filesystem.  
726    /// 
727    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::remove_file`.  
728    /// See `PrivateStorage::resolve_path` for details.  
729    /// 
730    /// # Support
731    /// All Android version.
732    fn remove_file(
733        &self,
734        base_dir: PrivateDir,
735        relative_path: impl AsRef<str>,
736    ) -> crate::Result<()> {
737
738        let path = self.resolve_path_with(base_dir, relative_path)?;
739        Ok(std::fs::remove_file(path)?)
740    }
741
742    /// Removes an empty directory.  
743    /// 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.  
744    /// 
745    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::remove_dir`.  
746    /// See `PrivateStorage::resolve_path` for details.  
747    /// 
748    /// # Support
749    /// All Android version.
750    fn remove_dir(
751        &self,
752        base_dir: PrivateDir,
753        relative_path: Option<&str>,
754    ) -> crate::Result<()> {
755
756        let path = match relative_path {
757            Some(relative_path) => self.resolve_path_with(base_dir, relative_path)?,
758            None => self.resolve_path(base_dir)?,
759        };
760
761        std::fs::remove_dir(path)?;
762        Ok(())
763    }
764
765    /// Removes a directory at this path, after removing all its contents. Use carefully!  
766    /// 
767    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::remove_dir_all`.  
768    /// See `PrivateStorage::resolve_path` for details.  
769    /// 
770    /// # Support
771    /// All Android version.
772    fn remove_dir_all(
773        &self,
774        base_dir: PrivateDir,
775        relative_path: Option<&str>,
776    ) -> crate::Result<()> {
777
778        let path = match relative_path {
779            Some(relative_path) => self.resolve_path_with(base_dir, relative_path)?,
780            None => self.resolve_path(base_dir)?,
781        };
782
783        std::fs::remove_dir_all(path)?;
784        Ok(())
785    }
786
787    /// Returns Ok(true) if the path points at an existing entity.  
788    /// 
789    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::exists`.  
790    /// See `PrivateStorage::resolve_path` for details.  
791    /// 
792    /// # Support
793    /// All Android version.
794    fn exists(
795        &self,
796        base_dir: PrivateDir,
797        relative_path: impl AsRef<str>
798    ) -> crate::Result<bool> {
799
800        let path = self.resolve_path_with(base_dir, relative_path)?;
801        Ok(std::fs::exists(path)?)
802    }
803
804    /// Queries the file system to get information about a file, directory.  
805    /// 
806    /// This internally uses `PrivateStorage::resolve_path` and `std::fs::metadata`.  
807    /// See `PrivateStorage::resolve_path` for details.  
808    /// 
809    /// # Support
810    /// All Android version.
811    fn metadata(
812        &self,
813        base_dir: PrivateDir,
814        relative_path: Option<&str>,
815    ) -> crate::Result<std::fs::Metadata> {
816
817        let path = match relative_path {
818            Some(relative_path) => self.resolve_path_with(base_dir, relative_path)?,
819            None => self.resolve_path(base_dir)?,
820        };
821
822        Ok(std::fs::metadata(path)?)
823    }
824}