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