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

Xamarin中Android的MainActivity如何修改文件下载路径?

把下载文件移到公共Download目录 + 解决权限报错

嘿,你已经实现了下载功能还能正常运行,很棒!现在想把文件从应用专属的storage/emulated/0/Application/data/file/Download移到系统公共的storage/emulated/0/Download,还碰到了权限报错的问题,我来帮你捋清楚怎么解决~

一、先改路径:从应用专属到公共Download目录

你当前代码里用的ApplicationContext.GetExternalFilesDir(Android.OS.Environment.DirectoryDownloads),获取的是应用自己独占的外部存储目录,这就是文件跑到Application/data/file/Download的原因。要拿到公共的Download目录,得换个方式获取路径:

适配Android 9及以下版本

对于Android 9(API 28)及更早的系统,直接用GetExternalStoragePublicDirectory就能拿到公共Download目录,代码改成这样:

public void Downloaded()
{
    CrossDownloadManager.Current.PathNameForDownloadedFile = new System.Func<IDownloadFile, string>(file => 
    {
        // 从URL里提取文件名
        string fileName = Android.Net.Uri.Parse(file.Url).Path.Split('/').Last();
        // 获取系统公共Download目录
        var publicDownloadDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads);
        // 拼接最终路径
        return Path.Combine(publicDownloadDir.AbsolutePath, fileName);
    });
}

适配Android 10及以上(Scoped Storage)

从Android 10(API 29)开始,Google推出了Scoped Storage(分区存储),GetExternalStoragePublicDirectory被废弃,而且直接写入公共目录不再受WRITE_EXTERNAL_STORAGE权限保护。这里有两种适配思路:

思路1:用MediaStore写入公共目录(Google推荐)

这种方式不需要特殊权限,直接通过MediaStore把文件插入公共Download目录,结合你的CrossDownloadManager使用的代码示例:

public void Downloaded()
{
    CrossDownloadManager.Current.PathNameForDownloadedFile = new System.Func<IDownloadFile, string>(file => 
    {
        string fileName = Android.Net.Uri.Parse(file.Url).Path.Split('/').Last();
        string publicDownloadPath;

        if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Q)
        {
            // Android 10+ 通过MediaStore获取公共Download的存储入口
            var contentValues = new ContentValues();
            contentValues.Put(MediaStore.Downloads.Columns.DisplayName, fileName);
            contentValues.Put(MediaStore.Downloads.Columns.MimeType, "application/octet-stream"); // 根据你的文件类型修改
            contentValues.Put(MediaStore.Downloads.Columns.RelativePath, Android.OS.Environment.DirectoryDownloads);

            var contentUri = ContentResolver.Insert(MediaStore.Downloads.ExternalContentUri, contentValues);
            // 若CrossDownloadManager需要路径,可临时获取公共目录路径(但直接写入需特殊权限,更推荐MediaStream写入)
            publicDownloadPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
        }
        else
        {
            publicDownloadPath = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath;
        }

        return Path.Combine(publicDownloadPath, fileName);
    });
}

思路2:用系统DownloadManager(最省心)

其实如果只是要把文件下到公共Download目录,完全可以不用自己折腾路径和权限,直接用Android系统自带的DownloadManager,它会自动处理所有细节:

// 获取系统DownloadManager服务
var downloadManager = (DownloadManager)GetSystemService(Context.DownloadService);
// 创建下载请求
DownloadManager.Request request = new DownloadManager.Request(Android.Net.Uri.Parse(yourFileUrl));
// 设置通知栏显示的信息
request.SetTitle("你的文件下载");
request.SetDescription("正在下载,请稍候");
// 直接指定保存到公共Download目录
request.SetDestinationInExternalPublicDir(Android.OS.Environment.DirectoryDownloads, fileName);
// 下载完成后显示通知
request.SetNotificationVisibility(DownloadManager.Request.VisibilityVisibleNotifyCompleted);
// 开始下载
long downloadId = downloadManager.Enqueue(request);

这种方式不需要你手动处理路径,权限也由系统自动搞定,超级省心!

二、解决权限报错的问题

你说已经加了WRITE_EXTERNAL_STORAGE权限但还是报错,这是因为Android版本不同,权限规则变了:

Android 9及以下

只需要两步:

  1. 在AndroidManifest.xml里声明权限:
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  2. 运行时动态请求权限(Android 6开始需要动态申请危险权限):
    if (ContextCompat.CheckSelfPermission(this, Manifest.Permission.WriteExternalStorage) != Permission.Granted)
    {
        ActivityCompat.RequestPermissions(this, new string[] { Manifest.Permission.WriteExternalStorage }, 100);
    }
    

Android 10及以上

WRITE_EXTERNAL_STORAGE权限只能访问应用自己的专属目录,要写入公共Download目录,得二选一:

  1. 用MediaStore写入:不需要额外权限,这是Google推荐的合规方式,只是代码稍微繁琐一点。
  2. 申请MANAGE_EXTERNAL_STORAGE权限:这是个特殊权限,需要在AndroidManifest.xml里添加:
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
    
    然后运行时引导用户去应用设置里手动授权:
    if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.R)
    {
        if (!Environment.IsExternalStorageManager)
        {
            Intent intent = new Intent(Settings.ActionManageAppAllFilesAccessPermission);
            intent.SetData(Android.Net.Uri.Parse("package:" + PackageName));
            StartActivity(intent);
        }
    }
    
    注意:这个权限比较敏感,Google Play对它的审核很严格,只有确实需要访问所有外部文件的应用才能使用,所以尽量优先选择MediaStore的方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 18:28:10