基于Tauri的Android应用如何申请主目录全文件访问权限?
Android Tauri应用请求全存储权限问题排查
在现代Android系统中,使用Tauri(Rust后端+JavaScript前端)开发应用时,如何请求用户授予访问主目录(/storage/emulated/0)下所有文件(包括文档、下载、图片、视频及外部存储设备文件)的权限?
我尝试了以下代码,各平台编译无错误警告,应用在Android上运行正常无崩溃,但始终不会触发权限请求,导致无法读取或列出大量必要文件。请问问题出在哪里?
原代码示例
Rust后端代码
// rust side ... #[cfg(target_os = "android")] use tauri_plugin_android_fs::{AndroidFsExt}; ... tauri::Builder::default() .plugin(tauri_plugin_android_fs::init()) ... // this is the func to let the app ask the user for minimal storage access #[tauri::command] async fn request_directory_access(app: tauri::AppHandle) { #[cfg(target_os = "android")] { let fs = app.android_fs_async(); let file_picker = fs.file_picker(); let _ = file_picker .pick_dir( None, // no initial location hint true, // local only (no cloud storage) ) .await .map_err(|e| e.to_string()); } }
JavaScript前端代码
// javascript side ... // request file access permission if android window.addEventListener("DOMContentLoaded", async () => { try { await invoke("request_directory_access"); } catch (err) { console.error(err); } }); ...
问题根源及解决方案
1. 核心问题:权限逻辑与需求不匹配
你当前调用的pick_dir是文件选择器API,它的作用是让用户手动选择单个目录,应用仅能访问该目录及子内容,不会触发全局存储权限请求,完全不符合你"访问主目录下所有文件"的需求。
2. 必要的权限声明缺失
Android 10+对存储权限管控严格,必须在AndroidManifest.xml中添加对应权限:
<!-- Android 12及以下的全局存储读取权限 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- Android 13+ 媒体文件细分权限 --> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" /> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" /> <!-- Android 10+ 访问所有文件的特殊权限(需用户手动在设置开启) --> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" />
3. 正确的权限请求实现
Rust后端修改版
#[cfg(target_os = "android")] use tauri::Manager; #[cfg(target_os = "android")] use android_activity::AndroidApp; #[cfg(target_os = "android")] use android_system_properties::AndroidSystemProperties; #[tauri::command] async fn request_full_storage_access(app: tauri::AppHandle) -> Result<String, String> { #[cfg(target_os = "android")] { let android_app = app.android_app().ok_or("无法获取Android应用句柄")?; let sdk_version = AndroidSystemProperties::get_int("ro.build.version.sdk", 0)?; if sdk_version >= 30 { // Android 10+ 检查全存储权限 if !android_app.has_permission("android.permission.MANAGE_EXTERNAL_STORAGE") { // 引导用户到应用设置页开启特殊权限 android_app.open_app_settings()?; return Ok("请在设置中开启「所有文件访问权限」".to_string()); } } else if sdk_version >= 23 { // Android 6-9 请求传统存储权限 let result = android_app.request_permissions(&["android.permission.READ_EXTERNAL_STORAGE"]).await?; if !result["android.permission.READ_EXTERNAL_STORAGE"].granted() { return Err("存储权限被拒绝".to_string()); } } Ok("权限已获取".to_string()) } #[cfg(not(target_os = "android"))] Ok("非Android平台无需权限".to_string()) }
JavaScript前端修改版
window.addEventListener("DOMContentLoaded", async () => { try { const res = await invoke("request_full_storage_access"); console.log(res); } catch (err) { console.error("权限请求失败:", err); } });
4. 关键注意事项
MANAGE_EXTERNAL_STORAGE是特殊权限,无法通过弹窗直接请求,必须引导用户到应用设置页手动开启- 若仅需访问媒体文件(图片/视频/音频),优先使用
READ_MEDIA_*权限,避免申请全存储权限(Google Play审核可能卡审) - 测试时必须用真实设备验证,部分模拟器的权限模拟存在偏差
内容的提问来源于stack exchange,提问作者anis djerrab




