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

Xamarin Forms WebView:基础认证实现与导航事件失效问题排查

问题

在Xamarin Forms项目中使用Hybrid Renderer和WebView,需要向页面注入JavaScript代码。主项目包含CustomWebView.cs,用于处理导航事件(如拨号、文件下载跳转);Android项目包含HybridWebViewRenderer.cs。原本功能正常,为实现基础认证,在HybridWebViewRenderer中添加了自定义AuthWebViewClient,认证功能生效后,WebViewNavigating事件仅触发一次,后续不再执行。请问:

  1. 能否不使用自定义WebViewClient实现基础认证?
  2. 如何在使用自定义客户端的同时保留CustomWebView的原有功能?

相关代码

主项目CustomWebView.cs

namespace ClotureSiadForms.Renderer
{
    public class CustomWebView : WebView
    {
        public string js = "";

        public CustomWebView()
        {
            Navigating+= WebViewNavigating;
            Navigated+=WebViewNavigated;
        }

        private void WebViewNavigated(object sender, WebNavigatedEventArgs args)
        {
            EvaluateJavaScriptAsync(js);
        }

        public void WebViewNavigating(object sender, WebNavigatingEventArgs args)
        {
            if (args.Url.StartsWith("tel:"))
            {
                var tel = args.Url.Split(':')[1];
                args.Cancel = true;

                Xamarin.Essentials.PhoneDialer.Open(tel);
            }
            else if (!args.Url.StartsWith("http") || args.Url.EndsWith(".apk") || args.Url.EndsWith(".pdf") || args.Url.EndsWith(".zip"))
            {
                args.Cancel = true;
                Xamarin.Essentials.Launcher.OpenAsync(args.Url);
            }
        }
    }
}

Android项目原有HybridWebViewRenderer.cs

[assembly: ExportRenderer(typeof(CustomWebView), typeof(HybridWebViewRenderer))]
namespace ClotureSiadForms.Droid.Renderer
{
    internal class HybridWebViewRenderer : WebViewRenderer
    {
        public HybridWebViewRenderer(Context context) : base(context)
        {
        }
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                CustomWebView webview = e.NewElement as CustomWebView;

                Control.Settings.JavaScriptEnabled = true;
                Control.Settings.DomStorageEnabled = true;
                Control.Settings.SavePassword = true;
            }
        }
    }
}

添加认证后的HybridWebViewRenderer.cs

[assembly: ExportRenderer(typeof(CustomWebView), typeof(HybridWebViewRenderer))]
namespace ClotureSiadForms.Droid.Renderer
{
    internal class HybridWebViewRenderer : WebViewRenderer
    {
        public HybridWebViewRenderer(Context context) : base(context)
        {
        }
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                CustomWebView webview = e.NewElement as CustomWebView;

                Control.Settings.JavaScriptEnabled = true;
                Control.Settings.DomStorageEnabled = true;
                Control.Settings.SavePassword = true;

                var login = Preferences.Get("login", "");
                var password = Preferences.Get("password", "");
                Control.SetWebViewClient(new AuthWebViewClient(login, password));
            }
        }
        public class AuthWebViewClient : WebViewClient
        {
            private string Username;
            private string Password;
            public AuthWebViewClient(string username, string password)
            {
                Username = username;
                Password = password;
            }
            public override void OnReceivedHttpAuthRequest(Android.Webkit.WebView view, HttpAuthHandler handler, string host, string realm)
            {
                handler.Proceed( Username,Password);
            }
        }
    }
}

解决方案

一、不使用自定义WebViewClient实现基础认证

可以通过在请求URL中直接拼接基础认证信息的方式实现,格式为https://用户名:密码@目标域名。示例代码如下:

// 在CustomWebView加载URL时拼接认证信息
string login = Preferences.Get("login", "");
string password = Preferences.Get("password", "");
string targetUrl = "https://your-target-domain.com";
// 对用户名密码进行URL编码,避免特殊字符导致错误
string encodedLogin = Uri.EscapeDataString(login);
string encodedPassword = Uri.EscapeDataString(password);
Uri targetUri = new Uri(targetUrl);
string authUrl = $"https://{encodedLogin}:{encodedPassword}@{targetUri.Host}{targetUri.PathAndQuery}";

// 给CustomWebView设置带认证的URL
CustomWebView webView = new CustomWebView();
webView.Source = new UrlWebViewSource { Url = authUrl };

注意:这种方式受部分WebView安全策略限制(比如Chrome的部分版本会屏蔽明文携带认证信息的URL),需要针对目标设备做兼容性测试。

二、使用自定义WebViewClient同时保留原有功能

问题核心是你自定义的AuthWebViewClient继承了原生WebViewClient,替换了Xamarin Forms默认的客户端,导致导航事件无法转发到Forms层的WebViewNavigating和WebViewNavigated。正确做法是继承Xamarin Forms提供的FormsWebViewClient,而非原生WebViewClient,这样既能保留认证逻辑,又能保证Forms层事件正常触发。

修改后的Android项目HybridWebViewRenderer.cs代码:

[assembly: ExportRenderer(typeof(CustomWebView), typeof(HybridWebViewRenderer))]
namespace ClotureSiadForms.Droid.Renderer
{
    internal class HybridWebViewRenderer : WebViewRenderer
    {
        public HybridWebViewRenderer(Context context) : base(context)
        {
        }

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

            if (Control != null)
            {
                CustomWebView webview = e.NewElement as CustomWebView;

                Control.Settings.JavaScriptEnabled = true;
                Control.Settings.DomStorageEnabled = true;
                Control.Settings.SavePassword = true;

                var login = Preferences.Get("login", "");
                var password = Preferences.Get("password", "");
                // 传入当前Renderer实例,保证事件转发
                Control.SetWebViewClient(new AuthWebViewClient(login, password, this));
            }
        }

        // 继承FormsWebViewClient而非原生WebViewClient
        public class AuthWebViewClient : FormsWebViewClient
        {
            private string Username;
            private string Password;

            public AuthWebViewClient(string username, string password, WebViewRenderer renderer) 
                : base(renderer)
            {
                Username = username;
                Password = password;
            }

            public override void OnReceivedHttpAuthRequest(Android.Webkit.WebView view, HttpAuthHandler handler, string host, string realm)
            {
                handler.Proceed(Username, Password);
            }

            // 如需额外处理导航逻辑,重写方法时必须调用base方法,保证Forms层事件触发
            public override bool ShouldOverrideUrlLoading(Android.Webkit.WebView view, IWebResourceRequest request)
            {
                // 先让FormsWebViewClient处理基础导航逻辑
                var result = base.ShouldOverrideUrlLoading(view, request);
                // 可在此添加自定义原生导航逻辑
                return result;
            }
        }
    }
}

修改后,自定义认证功能正常生效的同时,Forms层的WebViewNavigating和WebViewNavigated事件会持续触发,原有拨号、下载跳转的功能也能完整保留。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 12:15:40