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

如何处理Xamarin.Forms WebView加载错误?try-catch无效问题解决

解决Xamarin.Forms WebView加载错误(无网络/地址不可达)的自定义提示问题

你的try-catch没生效是因为WebView的加载是异步操作——设置WebView.Source只是发起加载请求,这个过程本身不会抛出网络或地址相关的异常,真正的错误是在后台加载流程中产生的,所以try-catch根本捕获不到这些错误。要实现自定义错误提示,需要通过原生平台的WebView回调来拦截错误,或者使用自定义渲染器来完全控制错误处理逻辑。

下面是两种可行的解决方案,优先推荐自定义渲染器的方式(能彻底替换原生错误页):

方案一:自定义WebView + 原生渲染器(推荐)

这种方式能在Android和iOS上直接拦截加载错误,无缝替换成自定义错误页面,不会显示原生错误提示或空白页。

1. 在共享项目中创建扩展WebView

先定义一个带错误事件的自定义WebView,用来跨平台传递错误信息:

using Xamarin.Forms;

namespace YourAppName
{
    public class ExtendedWebView : WebView
    {
        // 定义错误事件,供共享层监听
        public event EventHandler<string> LoadFailed;

        // 供原生渲染器调用,触发错误事件
        public void RaiseLoadFailed(string errorMsg)
        {
            LoadFailed?.Invoke(this, errorMsg);
        }
    }
}

2. Android平台自定义渲染器

创建Android专属的渲染器,拦截WebView的加载错误:

using Android.Content;
using Android.Webkit;
using YourAppName;
using YourAppName.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace YourAppName.Droid
{
    public class ExtendedWebViewRenderer : WebViewRenderer
    {
        public ExtendedWebViewRenderer(Context context) : base(context) { }

        protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
        {
            base.OnElementChanged(e);

            if (Control != null && e.NewElement is ExtendedWebView webView)
            {
                // 设置自定义WebViewClient拦截错误
                Control.SetWebViewClient(new ErrorHandlingWebViewClient(webView));
            }
        }

        private class ErrorHandlingWebViewClient : WebViewClient
        {
            private readonly ExtendedWebView _formsWebView;

            public ErrorHandlingWebViewClient(ExtendedWebView formsWebView)
            {
                _formsWebView = formsWebView;
            }

            public override void OnReceivedError(WebView view, IWebResourceRequest request, WebResourceError error)
            {
                base.OnReceivedError(view, request, error);
                // 触发共享层的错误事件
                _formsWebView.RaiseLoadFailed(error.DescriptionFormatted.ToString());
                // 加载自定义错误HTML
                view.LoadDataWithBaseURL(null, @"<html><body><h1>加载失败</h1><p>错误信息:" + error.DescriptionFormatted.ToString() + "</p></body></html>", "text/html", "UTF-8", null);
            }
        }
    }
}

3. iOS平台自定义渲染器

同样创建iOS的渲染器,拦截WKWebView的加载错误:

using Foundation;
using UIKit;
using WebKit;
using YourAppName;
using YourAppName.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(ExtendedWebView), typeof(ExtendedWebViewRenderer))]
namespace YourAppName.iOS
{
    public class ExtendedWebViewRenderer : WkWebViewRenderer
    {
        private ExtendedWebView _formsWebView;

        protected override void OnElementChanged(VisualElementChangedEventArgs e)
        {
            base.OnElementChanged(e);

            if (e.NewElement is ExtendedWebView webView)
            {
                _formsWebView = webView;
                // 设置自定义导航代理拦截错误
                NavigationDelegate = new ErrorHandlingNavigationDelegate(_formsWebView);
            }
        }

        private class ErrorHandlingNavigationDelegate : WKNavigationDelegate
        {
            private readonly ExtendedWebView _formsWebView;

            public ErrorHandlingNavigationDelegate(ExtendedWebView formsWebView)
            {
                _formsWebView = formsWebView;
            }

            // 拦截加载过程中的错误
            public override void DidFailNavigation(WKWebView webView, WKNavigation navigation, NSError error)
            {
                base.DidFailNavigation(webView, navigation, error);
                HandleError(webView, error.LocalizedDescription);
            }

            // 拦截初始导航的错误(比如无网络、地址不可达)
            public override void DidFailProvisionalNavigation(WKWebView webView, WKNavigation navigation, NSError error)
            {
                base.DidFailProvisionalNavigation(webView, navigation, error);
                HandleError(webView, error.LocalizedDescription);
            }

            private void HandleError(WKWebView webView, string errorMsg)
            {
                _formsWebView.RaiseLoadFailed(errorMsg);
                // 加载自定义错误HTML
                var errorHtml = @"<html><body><h1>加载失败</h1><p>错误信息:" + errorMsg + "</p></body></html>";
                webView.LoadHtmlString(errorHtml, null);
            }
        }
    }
}

4. 在共享项目中使用ExtendedWebView

在页面里初始化并使用自定义WebView,还可以监听错误事件做额外处理:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();

        var webView = new ExtendedWebView();
        // 可选:监听错误事件,做弹窗提示等操作
        webView.LoadFailed += (s, errorMsg) =>
        {
            DisplayAlert("加载错误", errorMsg, "确定");
        };
        // 设置要加载的URL
        webView.Source = "http://viva-t.000webhostapp.com/vivaapp";

        Content = webView;
    }
}

方案二:使用WebView的Navigated事件(简易版)

如果不想写自定义渲染器,可以尝试监听WebView的Navigated事件,检查导航结果是否成功。不过这种方式在Android上可能会短暂显示原生错误页,然后才替换成自定义页面:

var webView = new WebView();
webView.Source = "http://viva-t.000webhostapp.com/vivaapp";

webView.Navigated += (sender, args) =>
{
    if (args.Result != WebNavigationResult.Success)
    {
        var errorHtml = new HtmlWebViewSource
        {
            Html = @"<html><body><h1>An Error!!!!</h1><p>Could not be loaded</p></body></html>"
        };
        webView.Source = errorHtml;
    }
};

Content = webView;

关键说明

  • Android的WebViewClient.OnReceivedError和iOS的WKNavigationDelegate.DidFailProvisionalNavigation是拦截初始加载错误(比如无网络、地址不可达)的关键回调。
  • 自定义渲染器的方式能完全避免显示原生错误页,是更可靠的方案。

内容的提问来源于stack exchange,提问作者Vivaan Mathur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:50:11