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. By default (default-feature), this does not use any options that require additional permissions or review, so you can submit your app for Google Play review with peace of mind.
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.
1. Dialog
Opens the file/folder picker to read and write user-selected entries.
use tauri_plugin_android_fs::{AndroidFsExt, ImageFormat, Result, Size};
async fn file_picker_example(&app: tauri::AppHandle<impl tauri::Runtime>) -> Result<()> {
let api = app.android_fs_async();
let selected_files = api
.file_picker()
.pick_files(
None, &["*/*"], )
.await?;
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).await?;
let file_name = api.get_name(&uri).await?;
let file_thumbnail = api.get_thumbnail(
&uri,
Size { width: 200, height: 200},
ImageFormat::Jpeg
).await?;
{
let file: std::fs::File = api.open_file_readable(&uri).await?;
}
}
}
Ok(())
}
use tauri_plugin_android_fs::{AndroidFsExt, PublicImageDir, Result};
async fn file_saver_example(app: &tauri::AppHandle<impl tauri::Runtime>) -> Result<()> {
let api = app.android_fs_async();
let initial_location = api
.public_storage()
.resolve_initial_location(
None, PublicImageDir::Pictures, "MyApp/2025-10-22", true ).await?;
let selected_file = api
.file_picker()
.save_file(
Some(&initial_location), "my-image.jpg", Some("image/jpeg"), )
.await?;
if let Some(uri) = selected_file {
let file: std::fs::File = api.open_file_writable(&uri).await?;
}
else {
}
Ok(())
}
use tauri_plugin_android_fs::{AndroidFsExt, Entry, Result};
async fn dir_picker_example(app: &tauri::AppHandle<impl tauri::Runtime>) -> Result<()> {
let api = app.android_fs_async();
let selected = api
.file_picker()
.pick_dir(
None, )
.await?;
if let Some(dir_uri) = selected {
api.take_persistable_uri_permission(&dir_uri).await?;
for entry in api.read_dir(&dir_uri).await? {
match entry {
Entry::File { uri, name, .. } => {
},
Entry::Dir { uri, name, .. } => {
},
}
}
let file_uri = api
.create_new_file(
&dir_uri,
"MyApp/2025-1021/file.txt",
Some("text/plain")
)
.await?;
}
else {
}
Ok(())
}
2. Public Storage
File storage that is available to other applications and users.
For Android 9 (API level 29) or lower, please enable legacy_storage_permission feature.
use tauri_plugin_android_fs::{AndroidFsExt, Error, PublicGeneralPurposeDir, PublicImageDir, Result};
async fn example(app: &tauri::AppHandle<impl tauri::Runtime>) -> Result<()> {
let api = app.android_fs_async();
if !api.public_storage().request_permission().await? {
return Err(Error::with("Permission denied by user"))
}
api.public_storage().write_new(
None,
PublicImageDir::Pictures,
"MyApp/my-image.png",
Some("image/png"),
&[]
).await?;
let volume = api
.public_storage()
.get_volumes().await?
.into_iter()
.find(|v| !v.is_primary && !v.is_readonly);
let uri = api
.public_storage()
.create_new_file_with_pending(
volume.as_ref().map(|v| &v.id),
PublicGeneralPurposeDir::Documents,
"MyApp/2025-9-14/data.txt",
Some("text/plain")
).await?;
let mut file: std::fs::File = api.open_file_writable(&uri).await?;
let result = tauri::async_runtime::spawn_blocking(move || -> Result<()> {
use std::io::Write;
file.write_all(&[])?;
Ok(())
}).await.map_err(Into::into).and_then(|r| r);
if let Err(err) = result {
api.remove_file(&uri).await.ok();
return Err(err)
}
api.public_storage().set_pending(&uri, false).await?;
api.public_storage().scan(&uri).await?;
Ok(())
}
3. Private Storage
File storage intended for the app’s use only.
use tauri_plugin_android_fs::{AndroidFsExt, PrivateDir, Result};
async fn example(app: tauri::AppHandle<impl tauri::Runtime>) -> Result<()> {
let ps = app
.android_fs_async()
.private_storage();
let cache_dir_path: std::path::PathBuf = ps.resolve_path(PrivateDir::Cache).await?;
let data_dir_path: std::path::PathBuf = ps.resolve_path(PrivateDir::Data).await?;
let cache_dir_path = cache_dir_path.join("01K6049FVCD4SAGMAB6X20SA5S");
let data_dir_path = data_dir_path.join("01K6049FVCD4SAGMAB6X20SA5S");
Ok(())
}
Link
License
MIT OR Apache-2.0