Xamarin Android使用PDFView-Android加载局域网SMB/内网PDF的问题
Xamarin.Bindings.PDFView-Android底层封装的是原生Android PDFView库,所有内置加载入口仅支持本地文件路径、Assets资源、二进制字节流、本地Content Uri四类数据源,本身没有内置SMB协议的解析和访问能力,所以直接传入SMB路径无法被识别加载。
解决方案
方案1:下载到本地临时目录加载(推荐,兼容性最高)
这是目前最稳定的实现方式,适配所有体积的PDF文件,无内存溢出风险:
- 先引入SMB协议支持库(如SMBJ的Xamarin绑定包)读取内网SMB共享的PDF文件流
- 将读取到的流写入App沙盒的临时缓存目录,推荐使用
CacheDir路径,系统会在存储空间不足时自动清理该目录下的文件 - 调用PDFView的
FromFile()方法传入临时文件的绝对路径加载即可 - 可以在PDF加载完成的回调中主动删除临时文件,避免占用存储空间
代码示例:
// 1. 从SMB共享读取文件流 var smbClient = new SMBClient(); using var connection = smbClient.Connect("SMB服务器内网IP"); var authContext = AuthenticationContext.Builder() .WithUsername("SMB访问用户名") .WithPassword("SMB访问密码") .Build(); using var session = connection.Authenticate(authContext); using var share = session.ConnectShare("共享文件夹名") as DiskShare; using var smbFileStream = share.OpenFile("共享内PDF文件路径", EnumSet.Of(AccessMask.GenericRead), null, SMB2ShareAccess.All, SMB2CreateDisposition.FileOpen, null); // 2. 写入本地临时文件 var tempPdfPath = Path.Combine(CacheDir.AbsolutePath, $"temp_{Guid.NewGuid()}.pdf"); using (var localFs = File.OpenWrite(tempPdfPath)) { smbFileStream.CopyTo(localFs); } // 3. 加载PDF FindViewById<PDFView>(Resource.Id.pdf_view) .FromFile(tempPdfPath) .OnLoad(success => { // 加载完成后删除临时文件 if (success) File.Delete(tempPdfPath); }) .Show();
方案2:直接加载字节流(无需本地存储,适合小体积PDF)
如果PDF文件体积较小(建议50M以内),可以直接读取为字节数组后加载,不需要落地到本地存储:
- 读取SMB文件流后直接转存为字节数组
- 调用库提供的
FromBytes()方法直接加载字节数组
代码示例:
// 前面SMB读取流步骤同方案1 using var memoryStream = new MemoryStream(); smbFileStream.CopyTo(memoryStream); var pdfBytes = memoryStream.ToArray(); FindViewById<PDFView>(Resource.Id.pdf_view) .FromBytes(pdfBytes) .Show();
注意事项
- SMB文件读取属于网络IO操作,必须放到子线程/异步任务中执行,禁止在主线程操作避免触发ANR
- 需要在
AndroidManifest.xml中添加网络权限:<uses-permission android:name="android.permission.INTERNET" />,Android 12及以上系统还需要额外配置局域网访问权限 - 单文件体积超过100M的PDF优先使用方案1,避免字节数组加载触发OOM问题
内容的提问来源于stack exchange,提问作者Andrew Taylor
相关产品推荐
相关产品推荐

