Xamarin Forms Android WebView自定义User Agent致Navigated事件触发两次
我之前也踩过这个坑!Android端的WebView在修改UserAgentString后,会自动触发一次页面重载,这就是你看到Navigated事件触发两次的原因——第一次是UA变更引发的重载启动,第二次才是真正的页面加载完成。给你几个亲测有效的解决方案:
方案1:全局设置User Agent(推荐)
直接在Android项目的全局层面配置自定义UA,让所有WebView初始化时就使用这个UA,从根源避免额外的导航触发,这也是最省心的方法。
你可以在MainActivity的OnCreate方法(或者自定义Application类的OnCreate方法)中添加以下代码:
protected override void OnCreate(Bundle savedInstanceState) { base.OnCreate(savedInstanceState); // 获取默认UA并添加自定义标识 var defaultUserAgent = Android.Webkit.WebSettings.DefaultUserAgent; if (!defaultUserAgent.Contains("MyApp")) { Android.Webkit.WebSettings.DefaultUserAgent = $"{defaultUserAgent} MyApp"; } Xamarin.Essentials.Platform.Init(this, savedInstanceState); global::Xamarin.Forms.Forms.Init(this, savedInstanceState); LoadApplication(new App()); }
这样所有WebView都会自动使用带MyApp标识的UA,渲染器里无需再做任何UA相关操作,Navigated事件也会只在页面加载完成时触发一次。
方案2:在渲染器中设置UA并过滤重复事件
如果必须针对单个WebView在渲染器中设置UA,可以通过标志位过滤掉UA变更引发的那次无效Navigated事件:
public class CustomWebViewRenderer : WebViewRenderer { private bool _isUaChangeNavigation = false; public CustomWebViewRenderer(Context context) : base(context) { } protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e) { base.OnElementChanged(e); if (e.NewElement != null && Control != null) { var userAgent = Control.Settings.UserAgentString; if (!userAgent.Contains("MyApp")) { _isUaChangeNavigation = true; userAgent += " MyApp"; Control.Settings.UserAgentString = userAgent; } // 替换默认WebViewClient,控制事件触发逻辑 Control.SetWebViewClient(new CustomWebViewClient(this)); } } private class CustomWebViewClient : WebViewClient { private readonly CustomWebViewRenderer _renderer; public CustomWebViewClient(CustomWebViewRenderer renderer) { _renderer = renderer; } public override void OnPageFinished(Android.Webkit.WebView view, string url) { base.OnPageFinished(view, url); // 过滤UA变更导致的导航事件,之后重置标志位 if (_renderer._isUaChangeNavigation) { _renderer._isUaChangeNavigation = false; return; } // 触发Forms层面的Navigated事件 var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, null, url, WebNavigationResult.Success); _renderer.Element.SendNavigated(args); } } }
这个方法通过自定义WebViewClient拦截页面完成事件,跳过UA变更引发的那次无效导航,确保只有真正的页面加载完成才触发Navigated事件。
方案3:延迟设置UA(临时 workaround)
如果上面的方法都不适用,还可以尝试在WebView第一次加载完成后再设置UA,但这样首次加载会使用默认UA,适合对首次加载UA要求不高的场景:
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e) { base.OnElementChanged(e); if (e.NewElement != null && Control != null) { Control.SetWebViewClient(new WebViewClient { OverrideUrlLoading = (view, request) => false, OnPageFinished = (view, url) => { var userAgent = view.Settings.UserAgentString; if (!userAgent.Contains("MyApp")) { userAgent += " MyApp"; view.Settings.UserAgentString = userAgent; // 可选:如果需要后续请求都用新UA,可在此重新加载页面 // view.LoadUrl(url); } } }); } }
总结下来,方案1是最简洁可靠的,全局设置UA不仅能解决事件重复触发的问题,还能保证所有WebView的UA一致性。
内容的提问来源于stack exchange,提问作者jpcoder
相关产品推荐
相关产品推荐

