Xamarin-System.UnauthorizedAccessException: 访问路径被拒绝

21

我正在尝试下载一个文件,但是遇到了System.UnauthorizedAccessException: Access to the path "/storage/emulated/0/Download/test.pdf" is denied的错误。我已经在Android清单文件中设置了所需的权限。

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

下载路径:

Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads)

如果我使用以下路径作为我的下载路径,我可以下载文件。但是我无法将PDF文件分享到Google Drive、Dropbox或其他任何地方 System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal)

我正在使用Xamarin.Forms v2.4.0.282和Xamarin.Android.Support包v25.4.0.2。

注意:当使用Xamarin.Forms版本2.3.5.256-pre2和Xamarin.Android.Support包v23.3.0时,该代码运行良好。请建议你的解决方案。

提前致谢。


{btsdaf} - Nick Peppers
{btsdaf} - Melody
1
{btsdaf} - Nick Peppers
{btsdaf} - Melody
以下答案可能会有所帮助 https://stackoverflow.com/a/66515458/7149454 - Nick Kovalsky
5个回答

36

根据您使用的 Android 版本,即使在 6.0 或更新版本的清单中添加了权限,用户仍必须在应用程序运行时显式启用该权限,而在较低版本中则会在安装期间询问权限。例如,在应用程序启动时,我创建了一个方法来检查是否启用了权限,并在未启用时请求权限。

private void CheckAppPermissions()
{
    if ((int)Build.VERSION.SdkInt < 23)
    {
        return;
    }
    else
    {
        if (PackageManager.CheckPermission(Manifest.Permission.ReadExternalStorage, PackageName) != Permission.Granted
            && PackageManager.CheckPermission(Manifest.Permission.WriteExternalStorage, PackageName) != Permission.Granted)
        {
            var permissions = new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage };
            RequestPermissions(permissions, 1);
        }
     }
}

您还可以使用支持库来完成此操作,这样更简单,并且允许您无需检查Android版本。有关更多信息,请查看Google的文档。


3
这应该被标记为正确答案。运行得非常完美。 - Zain SMJ
我正在使用这段代码,它返回"Granted"两个权限,但我仍然无法访问。你有什么想法吗? - Stephan Bisschop
可能无法读取或写入您尝试访问的位置。请检查该位置或将其更改为您知道存在的其他路径 - Nick Peppers
完全没问题。 - Khurram Shaikh
在手机设置中授予应用程序权限对于解决这个错误非常有效。 - Alan

23
如果目标API为29+,即使您请求了权限并获得了用户授权,您仍将收到错误信息,因为他们更改了存储方式。
正确的解决方案是查看在API 29+上应该如何完成,并执行它。
但如果您和我一样,对于Android每天都让事情变得更加复杂感到疲倦,只需将android:requestLegacyExternalStorage="true"添加到您的清单文件<application>标记中,那么您就可以保存,直到您开始针对API 30构建。

你怎么做到的? - Mashkur
嗨,我现在的目标是API 30。我的应用程序将日志文件存储并在位置“/storage/emulated/0/SpecialDir/LogFile.txt”中备份数据库。现在我遇到了访问被拒绝的问题。请问你能指导我该怎么做吗? - user6159419
1
你救了我的一天,感谢你。 (注意:我正在使用Unity,并且即使我已经授予外部存储权限,仍然遇到访问拒绝问题。现在,通过在自定义清单中的应用程序标记添加“android:requestLegacyExternalStorage =“true””,问题已得到解决。) - Soorya
值得一提的是,这只是一个临时解决方案,最好让您的应用程序与Scoped Storage兼容:在将应用程序更新为针对Android 11(API级别30)进行目标设置后,当您的应用程序在Android 11设备上运行时,系统会忽略requestLegacyExternalStorage属性,因此您的应用程序必须准备支持作用域存储并为那些设备上的用户迁移应用程序数据。Android源代码:https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage - SnapADragon
1
@SnapADragon 是的,我确实提到了。"只要你不开始针对API 30进行定位,你就是安全的。" - David Riha

9

如果你的应用程序目标API29或更高版本时遇到此问题,请访问以下链接并查看LandLu的回答:

https://forums.xamarin.com/discussion/171039/saving-files-to-external-storage

我之前是通过以下代码访问文件夹路径: return Android.OS.Environment.ExternalStorageDirectory.AbsolutePath; 但是使用以下代码解决了我的问题: return Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath;


1

如果您正在运行Android API 23或更高版本,则即使您已在清单文件中提到它们,也需要在运行时获得用户的许可。检查并且如果用户尚未授予READ_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE权限,请使用下面的代码;

var permissions = new string[] { Manifest.Permission.ReadExternalStorage, Manifest.Permission.WriteExternalStorage };
            RequestPermissions(permissions, 77);

如果我使用以下路径作为我的下载路径,我就可以下载这个文件。但我不能分享PDF文件到Google Drive、Dropbox或其他任何地方。 System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal)
你正在将文件存储在应用程序的私有存储空间中。所有保存在内部存储器中的文件都是您的应用程序私有的,其他应用程序(如Google Drive、Dropbox等)无法访问它们(用户也不能)。您可以使用任何公共文件夹来实现这一目的。
var finalPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads);

0

替换

Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;

使用

Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath;

嗨!在我的看法中,添加一些上下文可能会大大提高答案的质量。您还可以在此处找到有用的信息,以供将来回答时参考。 - Bedir Yilmaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接