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

Xamarin.Forms (Android) 从本地共享仓库下载APK实现应用更新的问题

问题原因

你当前用的WebClient仅支持HTTP/HTTPS/FTP这类标准Web协议,而\\192.168.0.15\images\example.jpg这类路径属于SMB/CIFS局域网共享协议,WebClient无法直接解析该类协议的地址,因此会调用失败。

推荐解决方案

方案一:服务端搭建内网HTTP文件服务(最优,改动最小)

该方案无需修改你现有的下载逻辑,仅需要在存APK的本地服务器上部署轻量HTTP服务即可:

  • 你可以在Windows服务器上用IIS新建虚拟目录指向APK存储的共享文件夹,也可以用更轻量的Nginx、甚至Python一行命令python -m http.server 8080(在共享文件夹目录下执行)快速搭建文件服务,只要保证移动端和服务器在同一局域网下可以访问对应端口即可。
  • 配置完成后把原来的SMB下载地址替换为内网HTTP地址即可,比如http://192.168.0.15:8080/app-release.apk,你原有的WebClient下载逻辑完全可以复用,稳定性和兼容性远高于直接访问SMB共享。

方案二:客户端集成SMB协议适配库

如果必须保留SMB共享的使用方式,可以引入SMB客户端库实现共享文件访问,这里推荐使用纯C#实现的SMBLibrary库:

  1. 首先在Xamarin.Android项目中安装SMBLibrary NuGet包
  2. 替换原有下载逻辑,示例代码如下:
using SMBLibrary;
using SMBLibrary.Client;
using System.IO;
using System.Linq;

public void DownloadFileFromSMB(string smbFullPath, string localSaveDir, string smbUsername = "", string smbPassword = "")
{
    // 创建本地存储目录
    Directory.CreateDirectory(localSaveDir);
    var fileName = Path.GetFileName(smbFullPath);
    var localSavePath = Path.Combine(localSaveDir, fileName);

    // 解析SMB路径
    var pathSegments = smbFullPath.TrimStart('\\').Split('\\');
    if (pathSegments.Length < 3)
    {
        OnFileDownloaded?.Invoke(this, new DownloadEventArgs(false));
        return;
    }
    string serverIp = pathSegments[0];
    string shareName = pathSegments[1];
    string remoteFilePath = string.Join("\\", pathSegments.Skip(2));

    SMB2Client smbClient = new SMB2Client();
    try
    {
        // 连接SMB服务器
        bool connectSuccess = smbClient.Connect(System.Net.IPAddress.Parse(serverIp), SMBTransportType.DirectTCPTransport);
        if (!connectSuccess) throw new Exception("SMB服务器连接失败");

        // 登录认证,匿名访问直接传空账号密码
        NTStatus loginStatus = smbClient.Login(string.Empty, smbUsername, smbPassword);
        if (loginStatus != NTStatus.STATUS_SUCCESS) throw new Exception("SMB认证失败");

        // 接入共享目录
        var share = smbClient.TreeConnect(shareName, out NTStatus treeStatus);
        if (treeStatus != NTStatus.STATUS_SUCCESS) throw new Exception("共享目录访问失败");

        // 打开远程文件
        object fileHandle;
        FileStatus fileStatus;
        NTStatus openFileStatus = share.CreateFile(out fileHandle, out fileStatus, remoteFilePath, 
            AccessMask.GENERIC_READ, FileAttributes.Normal, ShareAccess.Read, 
            CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE, null);
        if (openFileStatus != NTStatus.STATUS_SUCCESS) throw new Exception("远程文件打开失败");

        // 读取文件写入本地
        long fileSize = share.GetFileInformation(fileHandle).EndOfFile;
        using var localFs = new FileStream(localSavePath, FileMode.Create, FileAccess.Write);
        long offset = 0;
        int bufferSize = 4096;
        while (offset < fileSize)
        {
            NTStatus readStatus = share.ReadFile(out byte[] data, fileHandle, offset, bufferSize);
            if (readStatus != NTStatus.STATUS_SUCCESS) throw new Exception("文件读取失败");
            localFs.Write(data, 0, data.Length);
            offset += data.Length;
        }

        // 释放资源
        share.CloseFile(fileHandle);
        share.Disconnect();
        smbClient.Logoff();
        smbClient.Disconnect();

        OnFileDownloaded?.Invoke(this, new DownloadEventArgs(true));
    }
    catch
    {
        if (smbClient.IsConnected)
        {
            smbClient.Logoff();
            smbClient.Disconnect();
        }
        OnFileDownloaded?.Invoke(this, new DownloadEventArgs(false));
    }
}
  1. 注意要在AndroidManifest.xml中添加必要权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- 安卓8.0以上安装APK需要的权限 -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 07:45:04