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