You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xamarin.Forms Android 10 SD卡访问权限激活方法咨询

解决Android 10外部SD卡/Documents目录访问权限被拒的问题

你碰到的问题核心是Android 10引入了Scoped Storage(分区存储)机制,它彻底改变了应用访问外部存储的规则——哪怕你声明了存储权限,也没法再像旧版本那样直接通过文件路径读写公共目录(比如/storage/emulated/0/Documents)。下面分步骤给你具体的解决方法:

1. 先声明必要的权限

首先在你的AndroidManifest.xml里添加存储权限声明:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- 若应用目标API是30+(Android 11及以上)需额外添加,Android 10可选 -->
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" android:minSdkVersion="30" />

2. 动态申请运行时权限

存储权限属于「危险权限」,Android 6.0及以上必须在运行时请求用户授权。你可以在Activity里添加以下代码:

private const int RequestStoragePermissions = 1;

private void RequestPermissions()
{
    string[] permissions = {
        Android.Manifest.Permission.ReadExternalStorage,
        Android.Manifest.Permission.WriteExternalStorage
    };

    if (ActivityCompat.CheckSelfPermission(this, Android.Manifest.Permission.ReadExternalStorage) != Permission.Granted ||
        ActivityCompat.CheckSelfPermission(this, Android.Manifest.Permission.WriteExternalStorage) != Permission.Granted)
    {
        ActivityCompat.RequestPermissions(this, permissions, RequestStoragePermissions);
    }
    else
    {
        // 权限已授予,执行文件操作逻辑
        AccessDocumentsDirectory();
    }
}

// 处理权限申请结果
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == RequestStoragePermissions)
    {
        if (grantResults.Length > 0 && grantResults[0] == Permission.Granted)
        {
            AccessDocumentsDirectory();
        }
        else
        {
            Toast.MakeText(this, "需要存储权限才能访问文件", ToastLength.Short).Show();
        }
    }
}

3. 适配Scoped Storage:用SAF访问Documents目录

Android 10下,就算拿到了存储权限,也不能直接用System.IO.Directory.GetFiles访问公共Documents目录——你得用**Storage Access Framework(SAF)**让用户手动选择目录,再通过ContentResolver来访问文件。

下面是获取Documents目录文件列表的示例代码:

private const int RequestOpenDocumentTree = 2;

private void AccessDocumentsDirectory()
{
    // 打开系统文件选择器,引导用户选择Documents目录
    Intent intent = new Intent(Intent.ActionOpenDocumentTree);
    // 设置默认打开Documents目录
    Uri uri = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDocuments).Uri;
    intent.PutExtra("android.provider.extra.INITIAL_URI", uri);
    StartActivityForResult(intent, RequestOpenDocumentTree);
}

// 处理目录选择结果
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
    base.OnActivityResult(requestCode, resultCode, data);
    if (requestCode == RequestOpenDocumentTree && resultCode == Result.Ok && data != null)
    {
        Uri treeUri = data.Data;
        // 持久化URI权限,下次启动无需重复选择
        ContentResolver.TakePersistableUriPermission(treeUri, IntentFlags.GrantReadUriPermission);
        
        // 遍历目录下的文件
        DocumentFile rootDoc = DocumentFile.FromTreeUri(this, treeUri);
        if (rootDoc != null && rootDoc.IsDirectory)
        {
            foreach (DocumentFile file in rootDoc.ListFiles())
            {
                string fileName = file.Name;
                // 若需读取文件内容,可通过ContentResolver打开输入流
                // Stream stream = ContentResolver.OpenInputStream(file.Uri);
            }
        }
    }
}

为什么原来的代码会报错?

Android 10默认启用Scoped Storage,它把应用的存储访问限制在私有目录,以及通过SAF/MediaStore访问的内容里。GetExternalStoragePublicDirectory虽然能返回路径,但应用没有直接访问该路径的权限,所以调用Directory.GetFiles会抛出权限拒绝错误。

如果你只是需要访问自己应用生成的文件,也可以考虑用应用的私有外部存储目录(Context.GetExternalFilesDir(null)),这个目录不需要额外权限就能访问,还不受Scoped Storage限制。

内容的提问来源于stack exchange,提问作者Prino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 23:49:10