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

Xamarin下载PDF时遭遇未授权访问权限问题求助

问题分析与解决方案

一、原权限报错的根本原因

  1. 路径参数错误:原代码中File.Create(path)传入的是目录路径(Environment.SpecialFolder.MyDocuments指向目录),但File.Create需要具体的文件路径(必须包含文件名,比如xxx.pdf),直接传入目录会触发权限或操作错误。
  2. Android存储机制限制:Android 10(API 29)引入Scoped Storage,即使申请了StorageRead/StorageWrite权限,直接用File API操作公共目录会被拒绝;而应用私有目录本身自带读写权限,原权限申请属于冗余操作。

二、下载后找不到文件的解决方案

FileSystem.AppDataDirectory是应用私有目录,默认仅应用自身可访问,普通文件管理器无法查看。以下是几种可行方案:

方案1:保存到公共下载目录(推荐)

将文件保存到系统公共下载目录,用户可直接在“下载”文件夹中找到。

代码修改:

首先修复权限检查的逻辑错误:

public async Task<bool> CheckStorage()
{
    var readPermission = await Permissions.CheckStatusAsync<Permissions.StorageRead>();
    var writePermission = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();

    if (readPermission != PermissionStatus.Granted || writePermission != PermissionStatus.Granted)
    {
        readPermission = await Permissions.RequestAsync<Permissions.StorageRead>();
        writePermission = await Permissions.RequestAsync<Permissions.StorageWrite>();
    }

    // 需同时拥有读写权限才返回true
    return readPermission == PermissionStatus.Granted && writePermission == PermissionStatus.Granted;
}

然后修改下载函数,适配Android版本处理公共目录写入:

public async Task<bool> DownloadFile(string fileURL)
{
    string fileName = $"AdoptPaw_{DateTime.Now:yyyyMMddHHmmss}.pdf";
    try
    {
        using (var client = new HttpClient())
        {
            using (var downloadStream = await client.GetStreamAsync(fileURL))
            {
                if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Q)
                {
                    // Android 10+ 使用MediaStore写入公共下载目录
                    var values = new ContentValues();
                    values.Put(MediaStore.MediaColumns.DisplayName, fileName);
                    values.Put(MediaStore.MediaColumns.MimeType, "application/pdf");
                    values.Put(MediaStore.MediaColumns.RelativePath, Android.OS.Environment.DirectoryDownloads);

                    var uri = Android.App.Application.Context.ContentResolver.Insert(MediaStore.Downloads.ExternalContentUri, values);
                    using (var fileStream = Android.App.Application.Context.ContentResolver.OpenOutputStream(uri))
                    {
                        await downloadStream.CopyToAsync(fileStream);
                    }
                }
                else
                {
                    // 低于Android 10,直接写入公共下载目录
                    string publicDownloadPath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, Android.OS.Environment.DirectoryDownloads);
                    Directory.CreateDirectory(publicDownloadPath);
                    string filePath = Path.Combine(publicDownloadPath, fileName);
                    using (var fileStream = File.Create(filePath))
                    {
                        await downloadStream.CopyToAsync(fileStream);
                    }
                }
            }
        }
        return true;
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine($"下载失败:{ex.Message}");
        return false;
    }
}

方案2:从私有目录分享文件

若不想保存到公共目录,可在下载完成后通过分享功能让用户选择应用打开文件:

// 下载完成后调用此方法
public async Task ShareDownloadedFile()
{
    string filePath = Path.Combine(FileSystem.AppDataDirectory, "File.pdf");
    if (File.Exists(filePath))
    {
        await Share.RequestAsync(new ShareFileRequest
        {
            Title = "查看领养PDF",
            File = new ShareFile(filePath)
        });
    }
}

方案3:调试时查看私有目录

若仅需确认文件是否下载成功,可通过ADB命令查看:

adb shell run-as com.companyname.pawadopt_v5 ls files

或在Android Studio的Device File Explorer中找到data/data/com.companyname.pawadopt_v5/files目录。

三、关键注意事项

  • Android 11+(API 30)开始,requestLegacyExternalStorage属性失效,必须使用MediaStore或SAF访问公共目录,不能依赖旧的File API。
  • 若仅保存到应用私有目录,可直接移除StorageRead/StorageWrite权限申请代码,私有目录默认拥有读写权限。
  • 建议给文件名添加时间戳,避免覆盖已存在的文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 10:11:34