MAUI Android应用打开Downloads目录文件时触发Android.OS.FileUriExposedException异常的问题求助
嗨,我来帮你搞定这个头疼的问题!这个FileUriExposedException是Android 7.0(API 24)及以上版本的安全限制导致的——直接用file://格式的Uri分享文件/文件夹会被系统拦截,因为这种方式会暴露文件的绝对路径,存在安全风险。下面给你几个可行的解决方案,优先推荐第一种官方合规的方式:
方案一:使用FileProvider生成Content Uri(推荐)
这是Android官方推荐的安全方式,通过FileProvider把文件路径转换成content://格式的Uri,避免直接暴露文件路径。
步骤1:在AndroidManifest.xml中配置FileProvider
打开Platforms/Android/AndroidManifest.xml,在<application>标签内部添加以下FileProvider配置:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
注意:${applicationId}会自动替换成你的应用包名,不用手动修改。
步骤2:创建file_paths.xml配置文件
在Platforms/Android/Resources目录下新建一个xml文件夹(如果没有的话),然后在里面创建file_paths.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <!-- 配置允许访问公共Downloads目录 --> <external-path name="downloads" path="Download/" /> </paths>
这个配置是告诉FileProvider,你的应用可以访问设备公共Downloads目录下的内容。
步骤3:修改MAUI代码生成合规的Uri
把你原来的Uri生成和打开逻辑替换成以下代码(仅针对Android平台做修改,Windows逻辑保持不变):
#if ANDROID string dir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath; string folderName = rework.ServiceOrder.ServiceOrderNo; string folderPath = Path.Combine(dir, folderName); Java.IO.File targetFolder = new Java.IO.File(folderPath); // 使用FileProvider生成Content格式的Uri Android.Net.Uri contentUri = AndroidX.Core.Content.FileProvider.GetUriForFile( Android.App.Application.Context, Android.App.Application.Context.PackageName + ".fileprovider", targetFolder); // 创建打开文件夹的Intent,并授予临时读取权限 Intent openFolderIntent = new Intent(Intent.ActionView); // 针对文件夹的MIME类型,部分设备可能需要调整为"*/*" openFolderIntent.SetDataAndType(contentUri, "resource/folder"); // 授予临时权限给目标应用(比如文件管理器) openFolderIntent.AddFlags(Android.Content.ActivityFlags.GrantReadUriPermission); openFolderIntent.AddFlags(Android.Content.ActivityFlags.NewTask); // 启动Intent打开文件夹 Android.App.Application.Context.StartActivity(openFolderIntent); #else // Windows平台原有逻辑保持不变 string dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads"); string folderName = rework.ServiceOrder.ServiceOrderNo; string folderPath = Path.Combine(dir, folderName); var uri = new Uri(folderPath).AbsoluteUri; await Launcher.Default.OpenAsync(uri); #endif
如果是打开单个文件而非文件夹,只需要把"resource/folder"改成对应文件的MIME类型(比如PDF文件用"application/pdf",图片用"image/*")即可。
方案二:临时降低目标SDK版本(不推荐)
如果只是临时测试,可以把Android的目标SDK版本降到23以下(Android 6.0及以下),这样系统不会触发FileUriExposedException。但这只是权宜之计,不符合现代Android的安全规范,绝对不建议用于正式发布的应用。
补充说明
- 你之前添加的
WRITE_EXTERNAL_STORAGE和MANAGE_EXTERNAL_STORAGE权限,在Android 10及以上版本,访问公共Downloads目录其实不需要这些权限(因为Downloads是系统开放的公共目录),如果你的应用不需要访问其他私有目录,可以考虑移除这些权限。 - 不要再用
Launcher.Default.OpenAsync直接打开file://格式的Uri,在Android 7+版本上必然会触发异常,改用FileProvider的方式才是长期可行的解决方案。
备注:内容来源于stack exchange,提问作者Dragon Slayer

