docs.rs failed to build tauri-plugin-android-fs-8.3.0
Please check the
build logs for more information.
See
Builds for ideas on how to fix a failed build,
or
Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault,
open an issue.
Overview
The Android file system is strict and complex because its behavior and the available APIs vary depending on the version. This plugin was created to provide explicit and consistent file operations and detailed and clear documentation. No special permission or configuration is required.
Note that this crate aims to provide practicality through detailed and clear documentation and a wide range of options, rather than focusing on clean functions that require minimal attention. If an error or unexpected behavior occurs, please first check the documentation for the function and functions that provided arguments. If the issue persists, it would be helpful if you could let us know on Github.
Setup
Register this plugin with your Tauri project:
src-tauri/src/lib.rs
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_android_fs::init()) .run(tauri::generate_context!())
.expect("error while running tauri application");
}
The current dialog in this plugin has an issue. To avoid this, please follow these two steps:
src-tauri/Cargo.toml
[dependencies]
tauri-plugin-android-fs = { features = ["avoid-issue1"], .. }
src-tauri/capabilities/default.json
{
..
"permissions": [
"android-fs:default",
..
]
}
Usage
Currently, this plugin only provides a Rust-side API, not a NPM library.
Then, there are three main ways to manipulate files:
1. Dialog
Opens the file/folder picker to read and write user-selected entries.
use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, FileAccessMode};
fn file_picker_example(app: tauri::AppHandle) -> tauri_plugin_android_fs::Result<()> {
let api = app.android_fs();
let selected_files = api.show_open_file_dialog(
None, &["*/*"], true, )?;
if selected_files.is_empty() {
}
else {
for uri in selected_files {
let file_type = api.get_mime_type(&uri)?.unwrap(); let file_name = api.get_name(&uri)?;
{
let file: std::fs::File = api.open_file(&uri, FileAccessMode::Read)?;
}
{
let file: std::fs::File = api.open_file(&uri, FileAccessMode::WriteTruncate)?;
}
let file_path: tauri_plugin_fs::FilePath = uri.into();
}
}
Ok(())
}
use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, Entry};
fn dir_picker_example(app: tauri::AppHandle) -> tauri_plugin_android_fs::Result<()> {
let api = app.android_fs();
let selected_folder = api.show_manage_dir_dialog(
None, )?;
if let Some(dir_uri) = selected_folder {
for entry in api.read_dir(&dir_uri)? {
match entry {
Entry::File { name, uri, last_modified, len, mime_type, .. } => {
},
Entry::Dir { name, uri, last_modified, .. } => {
},
}
}
}
else {
}
Ok(())
}
use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, FileUri, PersistableAccessMode, PrivateDir, PrivateStorage};
fn save_file_with_dialog(
app: tauri::AppHandle,
file_name: &str,
mime_type: &str,
contents: &[u8],
) -> tauri_plugin_android_fs::Result<bool> {
let api = app.android_fs();
let file_uri = api.show_save_file_dialog(
None, file_name, Some(mime_type), )?;
let Some(file_uri) = file_uri else {
return Ok(false)
};
if let Err(e) = api.write(&file_uri, contents) {
let _ = api.remove_file(&file_uri);
return Err(e)
}
Ok(true)
}
fn save_file_with_dir_dialog(
app: tauri::AppHandle,
relative_path: &str,
mime_type: &str,
contents: &[u8],
) -> tauri_plugin_android_fs::Result<bool> {
const DEST_DIR_URI_DATA_RELATIVE_PATH: &str = "01JQMFWVH65YNCWM31V3DZG6GR";
let api = app.android_fs();
let dest_dir_uri = api
.private_storage()
.read_to_string(PrivateDir::Data, DEST_DIR_URI_DATA_RELATIVE_PATH)
.and_then(|u| FileUri::from_str(&u))
.ok();
let dest_dir_uri = match dest_dir_uri {
Some(dest_dir_uri) => {
if api.check_persisted_uri_permission(&dest_dir_uri, PersistableAccessMode::ReadAndWrite)? {
Some(dest_dir_uri)
}
else {
None
}
},
None => None
};
let dest_dir_uri = match dest_dir_uri {
Some(dest_dir_uri) => dest_dir_uri,
None => {
let Some(uri) = api.show_manage_dir_dialog(None)? else {
return Ok(false)
};
api.private_storage().write(
PrivateDir::Data,
DEST_DIR_URI_DATA_RELATIVE_PATH,
uri.to_string()?.as_bytes()
)?;
api.take_persistable_uri_permission(&uri)?;
uri
},
};
let new_file_uri = api.create_file(
&dest_dir_uri,
relative_path,
Some(mime_type)
)?;
if let Err(e) = api.write(&new_file_uri, contents) {
let _ = api.remove_file(&new_file_uri);
return Err(e)
}
Ok(true)
}
2. Public Storage
File storage that is available to other applications and users.
Currently, this is for Android 10 (API level 29) or higher.
use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, PublicGeneralPurposeDir, PublicImageDir, PublicStorage};
fn example(app: tauri::AppHandle) -> tauri_plugin_android_fs::Result<()> {
let api = app.android_fs();
let storage = api.public_storage();
let contents: Vec<u8> = vec![];
let uri = storage.create_file_in_public_app_dir(
PublicImageDir::Pictures, "my-image.png", Some("image/png") )?;
if let Err(e) = api.write(&uri, &contents) {
let _ = api.remove_file(&uri);
return Err(e)
}
let uri = storage.create_file_in_public_app_dir(
PublicGeneralPurposeDir::Documents, "2025-3-2/data.txt", Some("text/plain") )?;
if let Err(e) = api.write(&uri, &contents) {
let _ = api.remove_file(&uri);
return Err(e)
}
Ok(())
}
3. Private Storage
File storage intended for the app’s use only.
use tauri_plugin_android_fs::{AndroidFs, AndroidFsExt, PrivateDir, PrivateStorage};
fn example(app: tauri::AppHandle) -> tauri_plugin_android_fs::Result<()> {
let storage = app.android_fs().private_storage();
let _cache_dir_path: std::path::PathBuf = storage.resolve_path(PrivateDir::Cache)?;
let _data_dir_path: std::path::PathBuf = storage.resolve_path(PrivateDir::Data)?;
storage.write(
PrivateDir::Data, "config/data1", &[]
)?;
let contents = storage.read(
PrivateDir::Data, "config/data1" )?;
Ok(())
}
Link
License
MIT OR Apache-2.0