安卓端WebView下载PDF/TXT文件代码不生效问题咨询
问题原因排查及解决建议
- 现有代码失效的核心原因:
Navigating事件仅能捕获页面主动跳转的URL,无法覆盖JS触发的下载请求、POST接口返回的附件流、无显式.pdf/.txt后缀的动态下载链接- 仅做了
.pdf格式的匹配,未覆盖.txt格式 Device.OpenUri属于已废弃API,在高版本安卓、iOS系统上存在权限适配问题,无法正常触发跳转
通用层代码修改
首先替换跨平台端的事件逻辑,使用Xamarin.Essentials提供的LauncherAPI替代废弃接口,同时补充.txt格式的匹配:
// 需引用Xamarin.Essentials命名空间,MAUI环境自带无需额外安装 protected async void webOnNavigating(object sender, WebNavigatingEventArgs e) { // 忽略大小写匹配两种格式后缀 if (e.Url.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase) || e.Url.EndsWith(".txt", StringComparison.OrdinalIgnoreCase)) { e.Cancel = true; await Launcher.OpenAsync(new Uri(e.Url)); return; } }
适配动态下载场景
如果文件是动态接口返回的附件(URL无后缀,通过Content-Disposition标识为下载),需要在各平台自定义WebView渲染器监听下载事件:
安卓端实现
在安卓项目中添加自定义WebView渲染器,注册下载监听器:
using Android.Content; using Android.Webkit; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; [assembly: ExportRenderer(typeof(WebView), typeof(YourAppNamespace.Droid.CustomWebViewRenderer))] namespace YourAppNamespace.Droid { public class CustomWebViewRenderer : WebViewRenderer { public CustomWebViewRenderer(Context context) : base(context) { } protected override void OnElementChanged(ElementChangedEventArgs<WebView> e) { base.OnElementChanged(e); if (Control != null) { Control.SetDownloadListener(new CustomDownloadListener(Context)); } } } public class CustomDownloadListener : Java.Lang.Object, IDownloadListener { private readonly Context _context; public CustomDownloadListener(Context context) => _context = context; public void OnDownloadStart(string url, string userAgent, string contentDisposition, string mimetype, long contentLength) { // 匹配pdf、txt格式的下载请求 if (mimetype == "application/pdf" || mimetype == "text/plain") { Android.Net.Uri uri = Android.Net.Uri.Parse(url); Intent intent = new Intent(Intent.ActionView, uri); intent.AddFlags(ActivityFlags.NewTask); _context.StartActivity(intent); } } } }
iOS端实现
在iOS项目中添加自定义WebView渲染器,监听响应头判断文件类型:
using Foundation; using WebKit; using Xamarin.Essentials; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; [assembly: ExportRenderer(typeof(WebView), typeof(YourAppNamespace.iOS.CustomWebViewRenderer))] namespace YourAppNamespace.iOS { public class CustomWebViewRenderer : WkWebViewRenderer { protected override void OnElementChanged(VisualElementChangedEventArgs e) { base.OnElementChanged(e); if (e.NewElement != null) { NavigationDelegate = new CustomWKNavigationDelegate(); } } } public class CustomWKNavigationDelegate : WKNavigationDelegate { public override void DecidePolicy(WKWebView webView, WKNavigationResponse navigationResponse, Action<WKNavigationResponsePolicy> decisionHandler) { if (navigationResponse.Response is NSHttpUrlResponse response) { var mimeType = response.MimeType.ToLower(); if (mimeType == "application/pdf" || mimeType == "text/plain") { _ = Launcher.OpenAsync(new Uri(response.Url.ToString())); decisionHandler(WKNavigationResponsePolicy.Cancel); return; } } decisionHandler(WKNavigationResponsePolicy.Allow); } } }
权限配置检查
- 安卓端在
AndroidManifest.xml中添加必要权限:
<!-- 基础网络权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 文件读写权限,按需添加 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 安卓13+下载通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
- iOS端如果使用HTTP链接,需要在
Info.plist中添加ATS配置:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
可选优化
如果不希望跳转到外部浏览器,可以先通过HttpClient将文件下载到本地缓存目录,再调用Launcher.OpenAsync打开本地文件路径,用户体验更连贯。
内容的提问来源于stack exchange,提问作者user16937336
相关产品推荐
相关产品推荐

