Note: I’m using a translation tool, so there may be some inappropriate expressions.
Overview
The Android file system is strict and complex. This plugin was created to provide practical file operations. You don’t need to set special permissions or configurations.
Setup
Register this plugin in 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");
}
Usage
This plugin only provides a Rust-side API.
If you need to use file data on frontend, consider using Tauri’s custom protocols for efficient transmission. Or convert tauri_plugin_android_fs::FileUri
to tauri_plugin_fs::FilePath
and use tauri_plugin_fs functions on frontend.
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::{AndroidFsExt, ImageFormat, Size};
fn file_picker_example(app: tauri::AppHandle) -> tauri_plugin_android_fs::Result<()> {
let api = app.android_fs();
let selected_files = api.file_picker().pick_files(
None, &["*/*"], )?;
if selected_files.is_empty() {
}
else {
for uri in selected_files {
let file_path: tauri_plugin_fs::FilePath = uri.clone().into();
let file_type = api.get_mime_type(&uri)?;
let file_name = api.get_name(&uri)?;
let file_thumbnail = api.get_thumbnail(
&uri,
Size { width: 200, height: 200},
ImageFormat::Jpeg
)?;
{
let file: std::fs::File = api.open_file_readable(&uri)?;
}
{
let file: std::fs::File = api.open_file_writable(&uri)?;
}
}
}
Ok(())
}
use tauri_plugin_android_fs::{AndroidFsExt, Entry};
fn dir_picker_example(app: tauri::AppHandle) -> tauri_plugin_android_fs::Result<()> {
let api = app.android_fs();
let selected_folder = api.file_picker().pick_dir(
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::{AndroidFsExt, FileUri, InitialLocation, PersistableAccessMode, PrivateDir};
fn save_file_with_file_saver(
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.file_picker().save_file(
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_picker(
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 initial_location = api.resolve_initial_location(
InitialLocation::TopPublicDir,
false
)?;
let uri = api.file_picker().pick_dir(
Some(&initial_location)
)?;
let Some(uri) = uri 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.
This is for Android 10 (API level 29) or higher.
use tauri_plugin_android_fs::{AndroidFsExt, PublicGeneralPurposeDir, PublicImageDir};
fn example(app: tauri::AppHandle) -> tauri_plugin_android_fs::Result<()> {
let api = app.android_fs();
let storage = api.public_storage();
let contents = &[];
let uri = storage.create_file_in_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_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::{AndroidFsExt, PrivateDir};
fn example(app: tauri::AppHandle) -> tauri_plugin_android_fs::Result<()> {
let storage = app.android_fs().private_storage();
let contents = &[];
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", contents
)?;
let contents = storage.read(
PrivateDir::Data, "config/data1" )?;
Ok(())
}
Link
License
MIT OR Apache-2.0