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

安卓端WebView下载PDF/TXT文件代码不生效问题咨询

问题原因排查及解决建议
  • 现有代码失效的核心原因:
    1. Navigating事件仅能捕获页面主动跳转的URL,无法覆盖JS触发的下载请求、POST接口返回的附件流、无显式.pdf/.txt后缀的动态下载链接
    2. 仅做了.pdf格式的匹配,未覆盖.txt格式
    3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 09:18:01