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

使用Xamarin以编程方式下载APK遇阻,求C#解决方案

解决Android C#环境下APK下载路径错误的问题

我太懂你这种找了一天资料全是Java、好不容易试了C#代码还碰路径报错的烦躁了!咱们一步步把这个问题拆解开解决:

先搞懂“路径部分不存在”的核心原因

这个报错本质和Android存储权限、目录访问逻辑直接相关:

  • Android 6.0(API 23)及以上版本,光在Manifest里加权限没用,必须动态申请存储访问权限;
  • 直接用Android.OS.Environment.DirectoryDownloads拼接路径时,可能因为权限不足导致程序无法识别该目录;
  • WebClient在Android异步场景下的兼容性不如更现代的HttpClient,容易踩坑。

具体解决方案步骤

1. 先把存储权限搞定

首先在AndroidManifest.xml里添加基础权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<!-- Android 13+ 需要的媒体权限 -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" android:minSdkVersion="33" />

然后在代码里动态申请权限(以Xamarin.Android为例):

private async Task CheckAndRequestPermissions()
{
    // 检查并申请存储写入权限
    var storageStatus = await Permissions.CheckStatusAsync<Permissions.StorageWrite>();
    if (storageStatus != PermissionStatus.Granted)
    {
        storageStatus = await Permissions.RequestAsync<Permissions.StorageWrite>();
    }

    // Android 13+ 额外申请媒体写入权限
    if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Tiramisu)
    {
        var mediaStatus = await Permissions.CheckStatusAsync<Permissions.MediaWrite>();
        if (mediaStatus != PermissionStatus.Granted)
        {
            mediaStatus = await Permissions.RequestAsync<Permissions.MediaWrite>();
        }
    }
}

2. 确保目标目录真实可访问

别直接硬拼路径,用系统API获取可靠的Downloads目录,还要确认目录存在:

// 获取系统Downloads目录的完整路径
var downloadDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads);
// 目录不存在就创建
if (!downloadDir.Exists)
{
    downloadDir.Mkdirs();
}
// 组合最终的APK保存路径
var apkSavePath = Path.Combine(downloadDir.AbsolutePath, "AppDownload.apk");

3. 用HttpClient替代WebClient(更稳定适配Android)

WebClient在.NET现代版本里已经被标记为过时,而且Android主线程不允许同步网络操作,改用异步的HttpClient更稳妥:

private async Task DownloadApkAsync()
{
    // 先检查权限,没权限啥都白搭
    await CheckAndRequestPermissions();

    var downloadDir = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads);
    if (!downloadDir.Exists)
    {
        downloadDir.Mkdirs();
    }
    var apkSavePath = Path.Combine(downloadDir.AbsolutePath, "AppDownload.apk");

    using (var httpClient = new HttpClient())
    {
        try
        {
            // 发起异步下载请求
            var response = await httpClient.GetAsync("http://mywebspace.bplaced.net/AppDownload.apk");
            response.EnsureSuccessStatusCode(); // 确保请求成功,失败会抛出异常

            // 把下载流写入本地文件
            using (var downloadStream = await response.Content.ReadAsStreamAsync())
            using (var fileStream = new FileStream(apkSavePath, FileMode.Create, FileAccess.Write))
            {
                await downloadStream.CopyToAsync(fileStream);
            }

            // 下载完成给个提示
            Toast.MakeText(this, "APK下载搞定啦!", ToastLength.Long).Show();
        }
        catch (Exception ex)
        {
            // 捕获异常,方便排查问题
            Toast.MakeText(this, $"下载失败:{ex.Message}", ToastLength.Long).Show();
        }
    }
}

4. 调用下载方法

记得在非主线程触发,比如按钮点击事件里:

private async void DownloadBtn_Click(object sender, EventArgs e)
{
    await DownloadApkAsync();
}

额外提醒

  • 如果你的应用适配Android 10(API 29)及以上,需要在Manifest里加android:requestLegacyExternalStorage="true"来兼容旧存储模型;
  • 下载完成后要自动安装的话,还得处理“未知来源应用”的安装权限,以及Android 11+的包安装API适配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:37:57