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

Xamarin Forms适配Android 13(API33)后外部存储读写权限问题求助

Android 13(API33)下Xamarin.Forms外部存储权限问题解决方案

问题核心

升级目标版本到Android 13后,WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE权限被系统直接拒绝——因为Android 13彻底废弃了这两个权限用于非媒体文件的访问。应用需要存储可被用户通过文件浏览器/USB访问的文档、日志,既不能放在媒体目录,也无法使用应用私有存储(用户无法直接访问)。

合规解决方案:使用存储访问框架(SAF)

这是Google推荐的方式,无需特殊权限,让用户自主选择存储位置,完全符合权限政策。

1. 实现目录选择与文件写入(Android项目层)

先在Forms层定义接口,再在Android项目中实现具体逻辑:

// Forms层定义接口
public interface IStorageService
{
    Task<string> PickFolderAsync();
    Task CreateLogFileAsync(string folderUri, string fileName, string content);
}

// Android项目中的实现类
[assembly: Dependency(typeof(StorageService))]
namespace YourApp.Droid
{
    public class StorageService : IStorageService
    {
        public async Task<string> PickFolderAsync()
        {
            var intent = new Intent(Intent.ActionOpenDocumentTree);
            intent.AddFlags(ActivityFlags.GrantReadUriPermission);
            intent.AddFlags(ActivityFlags.GrantWriteUriPermission);
            intent.AddFlags(ActivityFlags.GrantPersistableUriPermission);

            // 可选:默认打开系统Documents目录
            var initialUri = Android.Net.Uri.Parse("content://com.android.externalstorage.documents/document/primary%3ADocuments");
            intent.PutExtra(DocumentsContract.ExtraInitialUri, initialUri);

            var activity = Platform.CurrentActivity;
            var result = await activity.StartActivityForResultAsync(intent, 100);
            
            if (result.ResultCode == Result.Ok && result.Data != null)
            {
                var selectedUri = result.Data.Data;
                // 持久化权限,重启应用后仍可访问该目录
                activity.ContentResolver.TakePersistableUriPermission(selectedUri, 
                    ActivityFlags.GrantReadUriPermission | ActivityFlags.GrantWriteUriPermission);
                
                return selectedUri.ToString();
            }
            return null;
        }

        public async Task CreateLogFileAsync(string folderUri, string fileName, string content)
        {
            var uri = Android.Net.Uri.Parse(folderUri);
            var documentUri = DocumentsContract.CreateDocument(Platform.CurrentActivity.ContentResolver, uri, "text/plain", fileName);
            
            using (var stream = Platform.CurrentActivity.ContentResolver.OpenOutputStream(documentUri))
            using (var writer = new StreamWriter(stream))
            {
                await writer.WriteAsync(content);
            }
        }
    }
}

2. 在Forms层调用

// 示例:选择存储目录并创建日志文件
var folderUri = await DependencyService.Get<IStorageService>().PickFolderAsync();
if (!string.IsNullOrEmpty(folderUri))
{
    await DependencyService.Get<IStorageService>().CreateLogFileAsync(folderUri, "app_log.txt", $"[{DateTime.Now}] 应用启动日志");
}

特殊场景方案:申请MANAGE_EXTERNAL_STORAGE权限

如果你的应用是文件管理器类工具,确实需要全外部存储访问权限,可以使用此方案,但需注意Google Play审核要求,必须明确说明权限的必要性,否则会被拒审。

1. 声明权限(AndroidManifest.xml)

<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<!-- 兼容Android 12及以下版本 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />

2. 权限请求实现

public async Task<bool> CheckAndRequestManageStorage()
{
    if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.R)
    {
        if (!Environment.IsExternalStorageManager)
        {
            var intent = new Intent(Settings.ActionManageAppAllFilesAccessPermission);
            intent.SetData(Android.Net.Uri.Parse($"package:{Platform.CurrentActivity.PackageName}"));
            Platform.CurrentActivity.StartActivity(intent);
            
            // 等待用户操作后检查权限状态
            await Task.Delay(2000);
            return Environment.IsExternalStorageManager;
        }
        return true;
    }
    // 兼容Android 11及以下版本
    var writeStatus = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();
    if (writeStatus != PermissionStatus.Granted)
    {
        var result = await Permissions.RequestAsync<Permissions.StorageWrite>();
        return result == PermissionStatus.Granted;
    }
    return true;
}

失效原因说明

Android 13对非媒体文件的外部存储权限做了彻底调整:

  • WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE权限被废弃,系统会直接拒绝此类权限请求
  • 应用专属外部存储目录(Android/data/包名/)无需权限,但属于私有目录,用户无法直接访问(需手动开启文件管理器的隐藏文件显示)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 04:53:22