tauri_plugin_android_fs/api/
android_fs.rs

1use sync_async::sync_async;
2use crate::*;
3use super::*;
4
5
6/// ***Root API***  
7/// 
8/// # Examples
9/// ```no_run
10/// fn example(app: &tauri::AppHandle) {
11///     use tauri_plugin_android_fs::AndroidFsExt as _;
12/// 
13///     let api = app.android_fs();
14/// }
15/// ```
16
17#[sync_async]
18pub struct AndroidFs<R: tauri::Runtime> {
19    #[cfg(target_os = "android")]
20    pub(crate) handle: tauri::plugin::PluginHandle<R>,
21
22    #[cfg(not(target_os = "android"))]
23    #[allow(unused)]
24    pub(crate) handle: std::marker::PhantomData<fn() -> R>
25}
26
27#[cfg(target_os = "android")]
28#[sync_async(
29    use(if_sync) impls::SyncImpls as Impls;
30    use(if_async) impls::AsyncImpls as Impls;
31)]
32impl<R: tauri::Runtime> AndroidFs<R> {
33    
34    #[always_sync]
35    pub(crate) fn impls(&self) -> Impls<'_, R> {
36        Impls { handle: &self.handle }
37    }
38}
39
40#[sync_async(
41    use(if_async) api_async::{FileOpener, FilePicker, AppStorage, PrivateStorage, PublicStorage};
42    use(if_sync) api_sync::{FileOpener, FilePicker, AppStorage, PrivateStorage, PublicStorage};
43)]
44impl<R: tauri::Runtime> AndroidFs<R> {
45
46    /// API of file storage that is available to other applications and users.
47    #[always_sync]
48    pub fn public_storage(&self) -> PublicStorage<'_, R> {
49        PublicStorage { handle: &self.handle }
50    }
51
52    /// API of file storage intended for the app's use only.
53    #[always_sync]
54    pub fn private_storage(&self) -> PrivateStorage<'_, R> {
55        PrivateStorage { handle: &self.handle }
56    }
57
58    /// API of file storage intended for the app's use.  
59    #[always_sync]
60    pub fn app_storage(&self) -> AppStorage<'_, R> {
61        AppStorage { handle: &self.handle }
62    }
63
64    /// API of file/dir picker.
65    #[always_sync]
66    pub fn file_picker(&self) -> FilePicker<'_, R> {
67        FilePicker { handle: &self.handle }
68    }
69
70    /// API of opening file/dir with other apps.
71    #[always_sync]
72    pub fn file_opener(&self) -> FileOpener<'_, R> {
73        FileOpener { handle: &self.handle }
74    }
75
76    /// Get the file or directory name.  
77    /// 
78    /// # Args
79    /// - ***uri*** :  
80    /// Target URI.  
81    /// Must be **readable**.
82    /// 
83    /// # Support
84    /// All Android version.
85    #[maybe_async]
86    pub fn get_name(&self, uri: &FileUri) -> Result<String> {
87        #[cfg(not(target_os = "android"))] {
88            Err(Error::NOT_ANDROID)
89        }
90        #[cfg(target_os = "android")] {
91            self.impls().get_entry_name(uri).await
92        }
93    }
94
95    /// Queries the provider to get the MIME type.
96    ///
97    /// For file URIs via [`FileUri::from_path`], the MIME type is determined from the file extension.  
98    /// In most other cases, it uses the MIME type that was associated with the file when it was created.  
99    /// If the MIME type is unknown or unset, it falls back to `"application/octet-stream"`.  
100    /// 
101    /// If the target is a directory, an error will occur.  
102    /// To check whether the target is a file or a directory, use [`AndroidFs::get_type`].  
103    /// 
104    /// # Args
105    /// - ***uri*** :  
106    /// Target file URI.  
107    /// Must be **readable**.
108    /// 
109    /// # Support
110    /// All Android version.
111    #[maybe_async]
112    pub fn get_mime_type(&self, uri: &FileUri) -> Result<String> {
113        #[cfg(not(target_os = "android"))] {
114            Err(Error::NOT_ANDROID)
115        }
116        #[cfg(target_os = "android")] {
117            self.impls().get_file_mime_type(uri).await
118        }
119    }
120
121    /// Gets the entry type.
122    ///
123    /// If the target is a directory, returns [`EntryType::Dir`].
124    ///
125    /// If the target is a file, returns [`EntryType::File { mime_type }`](EntryType::File).  
126    /// For file URIs via [`FileUri::from_path`], the MIME type is determined from the file extension.  
127    /// In most other cases, it uses the MIME type that was associated with the file when it was created.  
128    /// If the MIME type is unknown or unset, it falls back to `"application/octet-stream"`.  
129    /// 
130    /// # Args
131    /// - ***uri*** :  
132    /// Target URI.  
133    /// Must be **readable**.
134    /// 
135    /// # Support
136    /// All Android version.
137    #[maybe_async]
138    pub fn get_type(&self, uri: &FileUri) -> Result<EntryType> {
139        #[cfg(not(target_os = "android"))] {
140            Err(Error::NOT_ANDROID)
141        }
142        #[cfg(target_os = "android")] {
143            self.impls().get_entry_type(uri).await
144        }
145    }
146
147    /// Gets the entry information.
148    ///
149    /// # Args
150    /// - ***uri*** :  
151    /// Target URI.  
152    /// Must be **readable**.
153    /// 
154    /// # Support
155    /// All Android version.
156    #[maybe_async]
157    pub fn get_info(&self, uri: &FileUri) -> Result<Entry> {
158        #[cfg(not(target_os = "android"))] {
159            Err(Error::NOT_ANDROID)
160        }
161        #[cfg(target_os = "android")] {
162            self.impls().get_entry_info(uri).await
163        }
164    }
165
166    /// Gets the file length in bytes.
167    ///
168    /// # Args
169    /// - ***uri*** :  
170    /// Target URI.  
171    /// Must be **readable**.
172    /// 
173    /// # Support
174    /// All Android version.
175    #[maybe_async]
176    pub fn get_len(&self, uri: &FileUri) -> Result<u64> {
177        #[cfg(not(target_os = "android"))] {
178            Err(Error::NOT_ANDROID)
179        }
180        #[cfg(target_os = "android")] {
181            self.impls().get_file_len(uri).await
182        }
183    }
184
185    /// Queries the file system to get information about a file, directory.
186    /// 
187    /// # Args
188    /// - ***uri*** :  
189    /// Target URI.  
190    /// Must be **readable**.
191    /// 
192    /// # Note
193    /// This uses [`AndroidFs::open_file`] internally.
194    /// 
195    /// # Support
196    /// All Android version.
197    #[maybe_async]
198    pub fn get_metadata(&self, uri: &FileUri) -> Result<std::fs::Metadata> {
199        #[cfg(not(target_os = "android"))] {
200            Err(Error::NOT_ANDROID)
201        }
202        #[cfg(target_os = "android")] {
203            self.impls().get_entry_metadata(uri).await
204        }
205    }
206
207    /// Open the file in **readable** mode. 
208    /// 
209    /// # Note
210    /// If the target is a file on cloud storage or otherwise not physically present on the device,
211    /// the file provider may downloads the entire contents, and then opens it. 
212    /// As a result, this processing may take longer than with regular local files.
213    /// And files might be a pair of pipe or socket for streaming data.
214    /// 
215    /// # Args
216    /// - ***uri*** :  
217    /// Target file URI.  
218    /// This need to be **readable**.
219    /// 
220    /// # Support
221    /// All Android version.
222    #[maybe_async]
223    pub fn open_file_readable(&self, uri: &FileUri) -> Result<std::fs::File> {
224        #[cfg(not(target_os = "android"))] {
225            Err(Error::NOT_ANDROID)
226        }
227        #[cfg(target_os = "android")] {
228            self.impls().open_file_readable(uri).await
229        }
230    }
231
232    /// Open the file in **writable** mode.  
233    /// This truncates the existing contents.  
234    /// 
235    /// # Args
236    /// - ***uri*** :  
237    /// Target file URI.  
238    /// This need to be **writable**.
239    /// 
240    /// # Support
241    /// All Android version.
242    #[maybe_async]
243    pub fn open_file_writable(
244        &self, 
245        uri: &FileUri, 
246    ) -> Result<std::fs::File> {
247
248        #[cfg(not(target_os = "android"))] {
249            Err(Error::NOT_ANDROID)
250        }
251        #[cfg(target_os = "android")] {
252            self.impls().open_file_writable(uri).await
253        }
254    }
255
256    /// Open the file in the specified mode.  
257    /// 
258    /// # Note
259    /// 1. **Delay**:   
260    /// If the target is a file on cloud storage or otherwise not physically present on the device,
261    /// the file provider may downloads the entire contents, and then opens it. 
262    /// As a result, this processing may take longer than with regular local files.
263    /// And files might be a pair of pipe or socket for streaming data.
264    /// 
265    /// 2. **File mode restrictions**:  
266    /// Files provided by third-party apps may not support modes other than
267    /// [`FileAccessMode::Write`] or [`FileAccessMode::Read`]. 
268    /// However, [`FileAccessMode::Write`] does not guarantee
269    /// that existing contents will always be truncated.  
270    /// As a result, if the new contents are shorter than the original, the file may
271    /// become corrupted. To avoid this, consider using
272    /// [`AndroidFs::open_file_writable`], which
273    /// ensure that existing contents are truncated and also automatically apply the
274    /// maximum possible fallbacks.  
275    /// - <https://issuetracker.google.com/issues/180526528>
276    /// 
277    /// # Args
278    /// - ***uri*** :  
279    /// Target file URI.  
280    /// This must have corresponding permissions (read, write, or both) for the specified ***mode***.
281    /// 
282    /// - ***mode*** :  
283    /// Indicates how the file is opened and the permissions granted. 
284    /// 
285    /// # Support
286    /// All Android version.
287    #[maybe_async]
288    pub fn open_file(&self, uri: &FileUri, mode: FileAccessMode) -> Result<std::fs::File> {
289        #[cfg(not(target_os = "android"))] {
290            Err(Error::NOT_ANDROID)
291        }
292        #[cfg(target_os = "android")] {
293            self.impls().open_file(uri, mode).await
294        }
295    }
296 
297    /// For detailed documentation and notes, see [`AndroidFs::open_file`].  
298    ///
299    /// The modes specified in ***candidate_modes*** are tried in order.  
300    /// If the file can be opened, this returns the file along with the mode used.  
301    /// If all attempts fail, an error is returned.  
302    #[maybe_async]
303    pub fn open_file_with_fallback(
304        &self, 
305        uri: &FileUri, 
306        candidate_modes: impl IntoIterator<Item = FileAccessMode>
307    ) -> Result<(std::fs::File, FileAccessMode)> {
308
309        #[cfg(not(target_os = "android"))] {
310            Err(Error::NOT_ANDROID)
311        }
312        #[cfg(target_os = "android")] {
313            self.impls().open_file_with_fallback(uri, candidate_modes).await
314        }
315    }
316
317    /// Reads the entire contents of a file into a bytes vector.  
318    /// 
319    /// # Args
320    /// - ***uri*** :  
321    /// Target file URI.    
322    /// Must be **readable**.
323    /// 
324    /// # Support
325    /// All Android version.
326    #[maybe_async]
327    pub fn read(&self, uri: &FileUri) -> Result<Vec<u8>> {
328        #[cfg(not(target_os = "android"))] {
329            Err(Error::NOT_ANDROID)
330        }
331        #[cfg(target_os = "android")] {
332            self.impls().read_file(uri).await
333        }
334    }
335
336    /// Reads the entire contents of a file into a string.  
337    /// 
338    /// # Args
339    /// - ***uri*** :  
340    /// Target file URI.  
341    /// Must be **readable**.
342    /// 
343    /// # Support
344    /// All Android version.
345    #[maybe_async]
346    pub fn read_to_string(&self, uri: &FileUri) -> Result<String> {
347        #[cfg(not(target_os = "android"))] {
348            Err(Error::NOT_ANDROID)
349        }
350        #[cfg(target_os = "android")] {
351            self.impls().read_file_to_string(uri).await
352        }
353    }
354
355    /// Writes a slice as the entire contents of a file.  
356    /// This function will entirely replace its contents if it does exist.    
357    /// 
358    /// # Args
359    /// - ***uri*** :  
360    /// Target file URI.  
361    /// Must be **writable**.
362    /// 
363    /// # Support
364    /// All Android version.
365    #[maybe_async]
366    pub fn write(&self, uri: &FileUri, contents: impl AsRef<[u8]>) -> Result<()> {
367        #[cfg(not(target_os = "android"))] {
368            Err(Error::NOT_ANDROID)
369        }
370        #[cfg(target_os = "android")] {
371            self.impls().write_file(uri, contents).await
372        }
373    }
374
375    /// Copies the contents of the source file to the destination.  
376    /// If the destination already has contents, they are truncated before writing the source contents.  
377    /// 
378    /// # Args
379    /// - ***src*** :  
380    /// The URI of source file.   
381    /// Must be **readable**.
382    /// 
383    /// - ***dest*** :  
384    /// The URI of destination file.  
385    /// Must be **writable**.
386    /// 
387    /// # Support
388    /// All Android version.
389    #[maybe_async]
390    pub fn copy(&self, src: &FileUri, dest: &FileUri) -> Result<()> {
391        #[cfg(not(target_os = "android"))] {
392            Err(Error::NOT_ANDROID)
393        }
394        #[cfg(target_os = "android")] {
395            self.impls().copy_file(src, dest).await
396        }
397    }
398
399    /// Renames a file or directory to a new name, and return new URI.  
400    /// Even if the names conflict, the existing file will not be overwritten.  
401    /// 
402    /// Note that when files or folders (and their descendants) are renamed, their URIs will change, and any previously granted permissions will be lost.
403    /// In other words, this function returns a new URI without any permissions.
404    /// However, for files created in PublicStorage, the URI remains unchanged even after such operations, and all permissions are retained.
405    /// In this, this function returns the same URI as original URI.
406    ///
407    /// # Args
408    /// - ***uri*** :  
409    /// URI of target entry.  
410    /// 
411    /// - ***new_name*** :  
412    /// New name of target entry. 
413    /// This include extension if use.  
414    /// The behaviour in the same name already exists depends on the file provider.  
415    /// In the case of e.g. [`PublicStorage`], the suffix (e.g. `(1)`) is added to this name.  
416    /// In the case of files hosted by other applications, errors may occur.  
417    /// But at least, the existing file will not be overwritten.  
418    /// The system may sanitize these strings as needed, so those strings may not be used as it is.
419    /// 
420    /// # Support
421    /// All Android version.
422    #[maybe_async]
423    pub fn rename(&self, uri: &FileUri, new_name: impl AsRef<str>) -> Result<FileUri> {
424        #[cfg(not(target_os = "android"))] {
425            Err(Error::NOT_ANDROID)
426        }
427        #[cfg(target_os = "android")] {
428            self.impls().rename_entry(uri, new_name).await
429        }
430    }
431
432    /// Remove the file.
433    /// 
434    /// # Args
435    /// - ***uri*** :  
436    /// Target file URI.  
437    /// Must be **read-writable**.   
438    /// If not file, an error will occur.
439    /// 
440    /// # Support
441    /// All Android version.
442    #[maybe_async]
443    pub fn remove_file(&self, uri: &FileUri) -> Result<()> {
444        #[cfg(not(target_os = "android"))] {
445            Err(Error::NOT_ANDROID)
446        }
447        #[cfg(target_os = "android")] {
448            self.impls().remove_file(uri).await
449        }
450    }
451
452    /// Remove the **empty** directory.
453    /// 
454    /// # Args
455    /// - ***uri*** :  
456    /// Target directory URI.  
457    /// Must be **read-writable**.  
458    /// If not empty directory, an error will occur.
459    /// 
460    /// # Support
461    /// All Android version.
462    #[maybe_async]
463    pub fn remove_dir(&self, uri: &FileUri) -> Result<()> {
464        #[cfg(not(target_os = "android"))] {
465            Err(Error::NOT_ANDROID)
466        }
467        #[cfg(target_os = "android")] {
468            self.impls().remove_dir_if_empty(uri).await
469        }
470    }
471
472    /// Removes a directory and all its contents. Use carefully!
473    /// 
474    /// # Args
475    /// - ***uri*** :  
476    /// Target directory URI.  
477    /// Must be **read-writable**.  
478    /// If not directory, an error will occur.
479    /// 
480    /// # Support
481    /// All Android version.
482    #[maybe_async]
483    pub fn remove_dir_all(&self, uri: &FileUri) -> Result<()> {
484        #[cfg(not(target_os = "android"))] {
485            Err(Error::NOT_ANDROID)
486        }
487        #[cfg(target_os = "android")] {
488            self.impls().remove_dir_all(uri).await
489        }
490    }
491
492    /// Build a URI of an **existing** file located at the relative path from the specified directory.   
493    /// Error occurs, if the file does not exist.  
494    /// 
495    /// The permissions and validity period of the returned URI depend on the origin directory 
496    /// (e.g., the top directory selected by [`FilePicker::pick_dir`]) 
497    /// 
498    /// # Note
499    /// For [`AndroidFs::create_new_file`] and etc, the system may sanitize path strings as needed, so those strings may not be used as it is.
500    /// However, this function does not perform any sanitization, so the same ***relative_path*** may still fail.  
501    /// So consider using [`AndroidFs::create_new_file_and_return_relative_path`].
502    /// 
503    /// # Args
504    /// - ***uri*** :  
505    /// Base directory URI.  
506    /// Must be **readable**.  
507    /// 
508    /// - ***relative_path*** :
509    /// Relative path from base directory.
510    /// 
511    /// # Support
512    /// All Android version.
513    #[maybe_async]
514    pub fn resolve_file_uri(
515        &self, 
516        dir: &FileUri, 
517        relative_path: impl AsRef<std::path::Path>
518    ) -> Result<FileUri> {
519
520        #[cfg(not(target_os = "android"))] {
521            Err(Error::NOT_ANDROID)
522        }
523        #[cfg(target_os = "android")] {
524            self.impls().resolve_file_uri(dir, relative_path, false).await
525        }
526    }
527
528    /// Build a URI of an **existing** directory located at the relative path from the specified directory.   
529    /// Error occurs, if the directory does not exist.  
530    /// 
531    /// The permissions and validity period of the returned URI depend on the origin directory 
532    /// (e.g., the top directory selected by [`FilePicker::pick_dir`]) 
533    /// 
534    /// # Note
535    /// For [`AndroidFs::create_dir_all`] and etc, the system may sanitize path strings as needed, so those strings may not be used as it is.
536    /// However, this function does not perform any sanitization, so the same ***relative_path*** may still fail.  
537    /// So consider using [`AndroidFs::create_dir_all_and_return_relative_path`].
538    /// 
539    /// # Args
540    /// - ***uri*** :  
541    /// Base directory URI.  
542    /// Must be **readable**.  
543    /// 
544    /// - ***relative_path*** :
545    /// Relative path from base directory.
546    /// 
547    /// # Support
548    /// All Android version.
549    #[maybe_async]
550    pub fn resolve_dir_uri(
551        &self,
552        dir: &FileUri, 
553        relative_path: impl AsRef<std::path::Path>
554    ) -> Result<FileUri> {
555
556        #[cfg(not(target_os = "android"))] {
557            Err(Error::NOT_ANDROID)
558        }
559        #[cfg(target_os = "android")] {
560            self.impls().resolve_dir_uri(dir, relative_path, false).await
561        }
562    }
563
564    /// See [`AndroidFs::get_thumbnail`] for descriptions.  
565    /// 
566    /// If thumbnail does not wrote to dest, return false.
567    #[maybe_async]
568    pub fn get_thumbnail_to(
569        &self, 
570        src: &FileUri,
571        dest: &FileUri,
572        preferred_size: Size,
573        format: ImageFormat,
574    ) -> Result<bool> {
575
576        #[cfg(not(target_os = "android"))] {
577            Err(Error::NOT_ANDROID)
578        }
579        #[cfg(target_os = "android")] {
580            self.impls().get_file_thumbnail_to_file(src, dest, preferred_size, format).await
581        }
582    }
583
584    /// Get a file thumbnail.  
585    /// If thumbnail does not exist it, return None.
586    /// 
587    /// Note this does not cache. Please do it in your part if need.  
588    /// 
589    /// # Args
590    /// - ***uri*** :  
591    /// Targe file uri.  
592    /// Thumbnail availablty depends on the file provider.  
593    /// In general, images and videos are available.  
594    /// For file URIs via [`FileUri::from_path`], 
595    /// the file type must match the filename extension. 
596    /// In this case, the type is determined by the extension and generate thumbnails.  
597    /// Otherwise, thumbnails are provided through MediaStore, file provider, and etc.
598    /// 
599    /// - ***preferred_size*** :  
600    /// Optimal thumbnail size desired.  
601    /// This may return a thumbnail of a different size, 
602    /// but never more than about double the requested size. 
603    /// In any case, the aspect ratio is maintained.
604    /// 
605    /// - ***format*** :  
606    /// Thumbnail image format.   
607    /// If you’re not sure which one to use, [`ImageFormat::Jpeg`] is recommended.   
608    /// If you need transparency, use others.   
609    /// 
610    /// # Support
611    /// All Android version.
612    #[maybe_async]
613    pub fn get_thumbnail(
614        &self,
615        uri: &FileUri,
616        preferred_size: Size,
617        format: ImageFormat,
618    ) -> Result<Option<Vec<u8>>> {
619
620        #[cfg(not(target_os = "android"))] {
621            Err(Error::NOT_ANDROID)
622        }
623        #[cfg(target_os = "android")] {
624            self.impls().get_file_thumbnail(uri, preferred_size, format).await
625        }
626    }
627
628    /// Get a file thumbnail that encoded to base64 string.  
629    /// If thumbnail does not exist it, return None.
630    /// 
631    /// Note this does not cache. Please do it in your part if need.  
632    /// 
633    /// # Inner
634    /// This uses Kotlin's [`android.util.Base64.encodeToString(.., android.util.Base64.NO_WRAP)`](https://developer.android.com/reference/android/util/Base64#encodeToString(byte[],%20int)) internally. 
635    /// It is the same as [`base64::engine::general_purpose::STANDARD`](https://docs.rs/base64/0.22.1/base64/engine/general_purpose/constant.STANDARD.html) in `base64` crate.
636    /// 
637    /// # Args
638    /// - ***uri*** :  
639    /// Targe file uri.  
640    /// Thumbnail availablty depends on the file provider.  
641    /// In general, images and videos are available.  
642    /// For file URIs via [`FileUri::from_path`], 
643    /// the file type must match the filename extension. 
644    /// In this case, the type is determined by the extension and generate thumbnails.  
645    /// Otherwise, thumbnails are provided through MediaStore, file provider, and etc.
646    /// 
647    /// - ***preferred_size*** :  
648    /// Optimal thumbnail size desired.  
649    /// This may return a thumbnail of a different size, 
650    /// but never more than about double the requested size. 
651    /// In any case, the aspect ratio is maintained.
652    /// 
653    /// - ***format*** :  
654    /// Thumbnail image format.   
655    /// If you’re not sure which one to use, [`ImageFormat::Jpeg`] is recommended.   
656    /// If you need transparency, use others.   
657    /// 
658    /// # Support
659    /// All Android version.
660    #[maybe_async]
661    pub fn get_thumbnail_base64(
662        &self,
663        uri: &FileUri,
664        preferred_size: Size,
665        format: ImageFormat,
666    ) -> Result<Option<String>> {
667
668        #[cfg(not(target_os = "android"))] {
669            Err(Error::NOT_ANDROID)
670        }
671        #[cfg(target_os = "android")] {
672            self.impls().get_file_thumbnail_base64(uri, preferred_size, format).await
673        }
674    }
675
676    /// Creates a new empty file in the specified location and returns a URI.   
677    /// 
678    /// The permissions and validity period of the returned URIs depend on the origin directory 
679    /// (e.g., the top directory selected by [`FilePicker::pick_dir`]) 
680    /// 
681    /// # Args  
682    /// - ***dir*** :  
683    /// The URI of the base directory.  
684    /// Must be **read-write**.
685    ///  
686    /// - ***relative_path*** :  
687    /// The file path relative to the base directory.  
688    /// Any missing parent directories will be created automatically.  
689    /// If a file with the same name already exists, a sequential number may be appended to ensure uniqueness.  
690    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
691    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
692    /// Note those operation may vary depending on the file provider.  
693    /// 
694    /// - ***mime_type*** :  
695    /// The MIME type of the file to be created.  
696    /// If this is None, MIME type is inferred from the extension of ***relative_path***
697    /// and if that fails, `application/octet-stream` is used.  
698    ///  
699    /// # Support
700    /// All Android version.
701    #[maybe_async]
702    pub fn create_new_file(
703        &self,
704        dir: &FileUri, 
705        relative_path: impl AsRef<std::path::Path>, 
706        mime_type: Option<&str>
707    ) -> Result<FileUri> {
708
709        #[cfg(not(target_os = "android"))] {
710            Err(Error::NOT_ANDROID)
711        }
712        #[cfg(target_os = "android")] {
713            self.impls().create_new_file(dir, relative_path, mime_type).await
714        }
715    }
716
717    /// Creates a new empty file in the specified location and returns a URI and relative path.   
718    /// 
719    /// The returned relative path may be sanitized and have a suffix appended to the file name, 
720    /// so it may differ from the input relative path.
721    /// And it is a logical path within the file provider and 
722    /// available for [`AndroidFs::resolve_file_uri`].
723    /// 
724    /// The permissions and validity period of the returned URIs depend on the origin directory 
725    /// (e.g., the top directory selected by [`FilePicker::pick_dir`]) 
726    /// 
727    /// # Args  
728    /// - ***dir*** :  
729    /// The URI of the base directory.  
730    /// Must be **read-write**.
731    ///  
732    /// - ***relative_path*** :  
733    /// The file path relative to the base directory.  
734    /// Any missing parent directories will be created automatically.  
735    /// If a file with the same name already exists, a sequential number may be appended to ensure uniqueness.  
736    /// If the file has no extension, one may be inferred from ***mime_type*** and appended to the file name.  
737    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
738    /// Note those operation may vary depending on the file provider.  
739    ///  
740    /// - ***mime_type*** :  
741    /// The MIME type of the file to be created.  
742    /// If this is None, MIME type is inferred from the extension of ***relative_path***
743    /// and if that fails, `application/octet-stream` is used.  
744    ///  
745    /// # Support
746    /// All Android version.
747    #[maybe_async]
748    pub fn create_new_file_and_return_relative_path(
749        &self,
750        dir: &FileUri, 
751        relative_path: impl AsRef<std::path::Path>, 
752        mime_type: Option<&str>
753    ) -> Result<(FileUri, std::path::PathBuf)> {
754
755        #[cfg(not(target_os = "android"))] {
756            Err(Error::NOT_ANDROID)
757        }
758        #[cfg(target_os = "android")] {
759            self.impls().create_new_file_and_retrun_relative_path(dir, relative_path, mime_type).await
760        }
761    }
762
763    /// Creates a directory and it's parents at the specified location if they are missing,
764    /// then return the URI.  
765    /// If it already exists, do nothing and just return the direcotry uri.
766    /// 
767    /// [`AndroidFs::create_new_file`] does this automatically, so there is no need to use it together.
768    /// 
769    /// # Args  
770    /// - ***dir*** :  
771    /// The URI of the base directory.  
772    /// Must be **read-write**.
773    ///  
774    /// - ***relative_path*** :  
775    /// The directory path relative to the base directory.    
776    /// Any missing parent directories will be created automatically.  
777    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
778    /// Note this sanitization may vary depending on the file provider.  
779    ///  
780    /// # Support
781    /// All Android version.
782    #[maybe_async]
783    pub fn create_dir_all(
784        &self,
785        dir: &FileUri, 
786        relative_path: impl AsRef<std::path::Path>, 
787    ) -> Result<FileUri> {
788
789        #[cfg(not(target_os = "android"))] {
790            Err(Error::NOT_ANDROID)
791        }
792        #[cfg(target_os = "android")] {
793            self.impls().create_dir_all(dir, relative_path).await
794        }
795    }
796
797    /// Recursively create a directory and all of its parent components if they are missing,
798    /// then return the URI and relative path.  
799    /// 
800    /// The returned relative path may be sanitized, 
801    /// so it may differ from the input relative path.
802    /// And it is a logical path within the file provider and 
803    /// available for [`AndroidFs::resolve_dir_uri`].
804    /// 
805    /// [`AndroidFs::create_new_file`] does this automatically, so there is no need to use it together.
806    /// 
807    /// # Args  
808    /// - ***dir*** :  
809    /// The URI of the base directory.  
810    /// Must be **read-write**.
811    ///  
812    /// - ***relative_path*** :  
813    /// The directory path relative to the base directory.    
814    /// Any missing parent directories will be created automatically.  
815    /// Strings may also be sanitized as needed, so they may not be used exactly as provided.
816    /// Note this sanitization may vary depending on the file provider.  
817    ///  
818    /// # Support
819    /// All Android version.
820    #[maybe_async]
821    pub fn create_dir_all_and_return_relative_path(
822        &self,
823        dir: &FileUri, 
824        relative_path: impl AsRef<std::path::Path>, 
825    ) -> Result<(FileUri, std::path::PathBuf)> {
826
827        #[cfg(not(target_os = "android"))] {
828            Err(Error::NOT_ANDROID)
829        }
830        #[cfg(target_os = "android")] {
831            self.impls().create_dir_all_and_return_relative_path(dir, relative_path).await
832        }
833    }
834
835    /// Returns the child files and directories of the specified directory.  
836    /// The order of the entries is not guaranteed.  
837    /// 
838    /// The permissions and validity period of the returned URIs depend on the origin directory 
839    /// (e.g., the top directory selected by [`FilePicker::pick_dir`])  
840    /// 
841    /// This retrieves all metadata including `uri`, `name`, `last_modified`, `len`, and `mime_type`. 
842    /// If only specific information is needed, 
843    /// using [`AndroidFs::read_dir_with_options`] will improve performance.
844    /// 
845    /// # Note
846    /// The returned type is an iterator, but the file system call is not executed lazily.  
847    /// Instead, all data is retrieved at once.  
848    /// For directories containing thousands or even tens of thousands of entries,  
849    /// this function may take several seconds to complete.  
850    /// The returned iterator itself is low-cost, as it only performs lightweight data formatting.
851    /// 
852    /// # Args
853    /// - ***uri*** :  
854    /// Target directory URI.  
855    /// Must be **readable**.
856    /// 
857    /// # Support
858    /// All Android version.
859    #[maybe_async]
860    pub fn read_dir(&self, uri: &FileUri) -> Result<impl Iterator<Item = Entry>> {
861        let entries = self.read_dir_with_options(uri, EntryOptions::ALL).await?
862            .map(Entry::try_from)
863            .filter_map(Result::ok);
864        
865        Ok(entries)
866    }
867
868    /// Returns the child files and directories of the specified directory.  
869    /// The order of the entries is not guaranteed.  
870    /// 
871    /// The permissions and validity period of the returned URIs depend on the origin directory 
872    /// (e.g., the top directory selected by [`FilePicker::pick_dir`])  
873    /// 
874    /// # Note
875    /// The returned type is an iterator, but the file system call is not executed lazily.  
876    /// Instead, all data is retrieved at once.  
877    /// For directories containing thousands or even tens of thousands of entries,  
878    /// this function may take several seconds to complete.  
879    /// The returned iterator itself is low-cost, as it only performs lightweight data formatting.
880    /// 
881    /// # Args
882    /// - ***uri*** :  
883    /// Target directory URI.  
884    /// Must be **readable**.
885    /// 
886    /// # Support
887    /// All Android version.
888    #[maybe_async]
889    pub fn read_dir_with_options(
890        &self, 
891        uri: &FileUri, 
892        options: EntryOptions
893    ) -> Result<impl Iterator<Item = OptionalEntry>> {
894        
895        #[cfg(not(target_os = "android"))] {
896            Err::<std::iter::Empty<_>, _>(Error::NOT_ANDROID)
897        }
898        #[cfg(target_os = "android")] {
899            self.impls().read_dir_with_options(uri, options).await
900        }
901    }
902
903    /// Take persistent permission to access the file, directory and its descendants.  
904    /// This is a prolongation of an already acquired permission, not the acquisition of a new one.  
905    /// 
906    /// This works by just calling, without displaying any confirmation to the user.
907    /// 
908    /// Note that [there is a limit to the total number of URI that can be made persistent by this function.](https://stackoverflow.com/questions/71099575/should-i-release-persistableuripermission-when-a-new-storage-location-is-chosen/71100621#71100621)  
909    /// Therefore, it is recommended to relinquish the unnecessary persisted URI by [`AndroidFs::release_persisted_uri_permission`] or [`AndroidFs::release_all_persisted_uri_permissions`].  
910    /// Persisted permissions may be relinquished by other apps, user, or by moving/removing entries.
911    /// So check by [`AndroidFs::check_persisted_uri_permission`].  
912    /// And you can retrieve the list of persisted uris using [`AndroidFs::get_all_persisted_uri_permissions`].
913    /// 
914    /// # Args
915    /// - **uri** :  
916    /// URI of the target file or directory.   
917    /// This must be a URI taken from following :  
918    ///     - [`FilePicker::pick_files`]  
919    ///     - [`FilePicker::pick_file`]  
920    ///     - [`FilePicker::pick_visual_medias`]  
921    ///     - [`FilePicker::pick_visual_media`]  
922    ///     - [`FilePicker::pick_dir`]  
923    ///     - [`FilePicker::save_file`]  
924    ///     - [`AndroidFs::resolve_file_uri`], [`AndroidFs::resolve_dir_uri`], [`AndroidFs::read_dir`], [`AndroidFs::create_new_file`], [`AndroidFs::create_dir_all`] :  
925    ///     If use URI from thoese fucntions, the permissions of the origin directory URI is persisted, not a entry iteself by this function. 
926    ///     Because the permissions and validity period of the descendant entry URIs depend on the origin directory.   
927    /// 
928    /// # Support
929    /// All Android version. 
930    #[maybe_async]
931    pub fn take_persistable_uri_permission(&self, uri: &FileUri) -> Result<()> {
932        #[cfg(not(target_os = "android"))] {
933            Err(Error::NOT_ANDROID)
934        }
935        #[cfg(target_os = "android")] {
936            self.impls().take_persistable_uri_permission(uri).await
937        }
938    }
939
940    /// Check a persisted URI permission grant by [`AndroidFs::take_persistable_uri_permission`].  
941    /// Returns false if there are only non-persistent permissions or no permissions.
942    /// 
943    /// # Args
944    /// - **uri** :  
945    /// URI of the target file or directory.  
946    /// This must be a URI taken from following :  
947    ///     - [`FilePicker::pick_files`]  
948    ///     - [`FilePicker::pick_file`]  
949    ///     - [`FilePicker::pick_visual_medias`]  
950    ///     - [`FilePicker::pick_visual_media`]  
951    ///     - [`FilePicker::pick_dir`]  
952    ///     - [`FilePicker::save_file`]  
953    ///     - [`AndroidFs::resolve_file_uri`], [`AndroidFs::resolve_dir_uri`], [`AndroidFs::read_dir`], [`AndroidFs::create_new_file`], [`AndroidFs::create_dir_all`] :  
954    ///     If use URI from thoese fucntions, the permissions of the origin directory URI is checked, not a entry iteself by this function. 
955    ///     Because the permissions and validity period of the descendant entry URIs depend on the origin directory.   
956    /// 
957    /// - **permission** :  
958    /// The permission you want to check.  
959    /// 
960    /// # Support
961    /// All Android version.
962    #[maybe_async]
963    pub fn check_persisted_uri_permission(
964        &self, 
965        uri: &FileUri, 
966        permission: UriPermission
967    ) -> Result<bool> {
968
969        #[cfg(not(target_os = "android"))] {
970            Err(Error::NOT_ANDROID)
971        }
972        #[cfg(target_os = "android")] {
973            self.impls().check_persisted_uri_permission(uri, permission).await
974        }
975    }
976
977    /// Return list of all persisted URIs that have been persisted by [`AndroidFs::take_persistable_uri_permission`] and currently valid.   
978    /// 
979    /// # Support
980    /// All Android version.
981    #[maybe_async]
982    pub fn get_all_persisted_uri_permissions(&self) -> Result<impl Iterator<Item = PersistedUriPermissionState>> {
983        #[cfg(not(target_os = "android"))] {
984            Err::<std::iter::Empty<_>, _>(Error::NOT_ANDROID)
985        }
986        #[cfg(target_os = "android")] {
987            self.impls().get_all_persisted_uri_permissions().await
988        }
989    }
990
991    /// Relinquish a persisted URI permission grant by [`AndroidFs::take_persistable_uri_permission`].   
992    /// 
993    /// # Args
994    /// - ***uri*** :  
995    /// URI of the target file or directory.  
996    ///
997    /// # Support
998    /// All Android version.
999    #[maybe_async]
1000    pub fn release_persisted_uri_permission(&self, uri: &FileUri) -> Result<()> {
1001        #[cfg(not(target_os = "android"))] {
1002            Err(Error::NOT_ANDROID)
1003        }
1004        #[cfg(target_os = "android")] {
1005            self.impls().release_persisted_uri_permission(uri).await
1006        }
1007    }
1008
1009    /// Relinquish a all persisted uri permission grants by [`AndroidFs::take_persistable_uri_permission`].  
1010    /// 
1011    /// # Support
1012    /// All Android version.
1013    #[maybe_async]
1014    pub fn release_all_persisted_uri_permissions(&self) -> Result<()> {
1015        #[cfg(not(target_os = "android"))] {
1016            Err(Error::NOT_ANDROID)
1017        }
1018        #[cfg(target_os = "android")] {
1019            self.impls().release_all_persisted_uri_permissions().await
1020        }
1021    }
1022
1023    /// See [`AppStorage::get_volumes`] or [`PublicStorage::get_volumes`] for details.
1024    /// 
1025    /// The difference is that this does not perform any filtering.
1026    /// You can it by [`StorageVolume { is_available_for_app_storage, is_available_for_public_storage, .. } `](StorageVolume).
1027    #[maybe_async]
1028    pub fn get_volumes(&self) -> Result<Vec<StorageVolume>> {
1029        #[cfg(not(target_os = "android"))] {
1030            Err(Error::NOT_ANDROID)
1031        }
1032        #[cfg(target_os = "android")] {
1033            self.impls().get_available_storage_volumes().await
1034        }
1035    }
1036
1037    /// See [`AppStorage::get_primary_volume`] or [`PublicStorage::get_primary_volume`] for details.
1038    /// 
1039    /// The difference is that this does not perform any filtering.
1040    /// You can it by [`StorageVolume { is_available_for_app_storage, is_available_for_public_storage, .. } `](StorageVolume).
1041    #[maybe_async]
1042    pub fn get_primary_volume(&self) -> Result<Option<StorageVolume>> {
1043        #[cfg(not(target_os = "android"))] {
1044            Err(Error::NOT_ANDROID)
1045        }
1046        #[cfg(target_os = "android")] {
1047            self.impls().get_primary_storage_volume_if_available().await
1048        }
1049    }
1050
1051    /// Builds the storage volume root URI.  
1052    /// 
1053    /// This should only be used as `initial_location` in the file picker, such as [`FilePicker::pick_files`]. 
1054    /// It must not be used for any other purpose.  
1055    /// 
1056    /// This is useful when selecting save location, 
1057    /// but when selecting existing entries, `initial_location` is often better with None.
1058    /// 
1059    /// # Args  
1060    /// - ***volume_id*** :  
1061    /// ID of the storage volume, such as internal storage, SD card, etc.  
1062    /// If `None` is provided, [`the primary storage volume`](AndroidFs::get_primary_volume) will be used.  
1063    /// 
1064    /// # Support
1065    /// All Android version.
1066    #[maybe_async]
1067    pub fn resolve_root_initial_location(&self, volume_id: Option<&StorageVolumeId>) -> Result<FileUri> {
1068        #[cfg(not(target_os = "android"))] {
1069            Err(Error::NOT_ANDROID)
1070        }
1071        #[cfg(target_os = "android")] {
1072            self.impls().resolve_root_initial_location(volume_id).await
1073        }
1074    }
1075
1076    /// Verify whether this plugin is available.  
1077    /// 
1078    /// On Android, this returns true.  
1079    /// On other platforms, this returns false.  
1080    #[always_sync]
1081    pub fn is_available(&self) -> bool {
1082        cfg!(target_os = "android")
1083    }
1084
1085    /// Get the api level of this Android device.
1086    /// 
1087    /// The correspondence table between API levels and Android versions can be found following.  
1088    /// <https://developer.android.com/guide/topics/manifest/uses-sdk-element#api-level-table>
1089    /// 
1090    /// If you want the constant value of the API level from an Android version, there is the [`api_level`] module.
1091    /// 
1092    /// # Table
1093    /// | Android version  | API Level |
1094    /// |------------------|-----------|
1095    /// | 16.0             | 36        |
1096    /// | 15.0             | 35        |
1097    /// | 14.0             | 34        |
1098    /// | 13.0             | 33        |
1099    /// | 12L              | 32        |
1100    /// | 12.0             | 31        |
1101    /// | 11.0             | 30        |
1102    /// | 10.0             | 29        |
1103    /// | 9.0              | 28        |
1104    /// | 8.1              | 27        |
1105    /// | 8.0              | 26        |
1106    /// | 7.1 - 7.1.2      | 25        |
1107    /// | 7.0              | 24        |
1108    /// 
1109    /// Tauri does not support Android versions below 7.
1110    #[always_sync]
1111    pub fn api_level(&self) -> Result<i32> {
1112        #[cfg(not(target_os = "android"))] {
1113            Err(Error::NOT_ANDROID)
1114        }
1115        #[cfg(target_os = "android")] {
1116            self.impls().api_level()
1117        }
1118    }
1119
1120    /// See [`AndroidFs::resolve_file_uri`] for details.
1121    /// 
1122    /// The difference is that this may skip checking whether the target exists and is a file.  
1123    /// As a result, in many cases it avoids the delay (from a few to several tens of milliseconds) caused by calling a Kotlin-side function.
1124    /// 
1125    /// Note that, depending on the situation, 
1126    /// the Kotlin-side function may be called or a check may be performed, 
1127    /// which could result in an error or a delay.
1128    #[maybe_async]
1129    pub fn _resolve_file_uri(
1130        &self, 
1131        dir: &FileUri, 
1132        relative_path: impl AsRef<std::path::Path>
1133    ) -> Result<FileUri> {
1134
1135        #[cfg(not(target_os = "android"))] {
1136            Err(Error::NOT_ANDROID)
1137        }
1138        #[cfg(target_os = "android")] {
1139            self.impls().resolve_file_uri(dir, relative_path, true).await
1140        }
1141    }
1142
1143    /// See [`AndroidFs::resolve_dir_uri`] for details.
1144    /// 
1145    /// The difference is that this may skip checking whether the target exists and is a directory.  
1146    /// As a result, in many cases it avoids the delay (from a few to several tens of milliseconds) caused by calling a Kotlin-side function.
1147    ///
1148    /// Note that, depending on the situation, 
1149    /// the Kotlin-side function may be called or a check may be performed, 
1150    /// which could result in an error or a delay.
1151    #[maybe_async]
1152    pub fn _resolve_dir_uri(
1153        &self, 
1154        dir: &FileUri, 
1155        relative_path: impl AsRef<std::path::Path>
1156    ) -> Result<FileUri> {
1157
1158        #[cfg(not(target_os = "android"))] {
1159            Err(Error::NOT_ANDROID)
1160        }
1161        #[cfg(target_os = "android")] {
1162            self.impls().resolve_dir_uri(dir, relative_path, true).await
1163        }
1164    }
1165}