Xamarin.Forms WebView:使用自定义 WebViewRenderer 时,导航事件中的 e.Cancel = true 在 Android 上不起作用

问题描述

我想将打开的 URL 重定向到我的 WebView 中的外部浏览器,所以我挂钩了它的 Navigated 事件:

webView.Navigating += (s,e) =>
{
    if (IsExternalUrl(e.Url))
    {
        try
        {
            var uri = new Uri(e.Url);
            Device.OpenUri(uri);        // show external links in external browser
        }
        catch (Exception)
        {
        }
            
        e.Cancel = true;   // <- not having any effects on Android
    }
};

在 Android 下,这会导致 URL 同时在 Chrome 和 WebView 中打开。在 iOS 上,e.Cancel = true 确实按预期工作。

我在网络上进行了广泛的搜索,但没有找到对我有帮助的内容包括这个 Xamarin 论坛主题https://forums.xamarin.com/discussion/144314/using-webviewrenderer-and-webviewclient-causes-cancel-navigation-not-working

我现在有一个解决方法,使用后退导航:

XAML:

<local:HybridWebView x:Name="webView" CanGoBack="True"  WidthRequest="1000" HeightRequest="1000" />

背后的代码

webView.Navigated += (s,e) =>
{
    if (e.Result == WebNavigationResult.Success)
    {
        if (Device.RuntimePlatform == Device.Android)  // on Android,prohibit webview from mirroring urls 
            if (IsExternalUrl(e.Url))                  // that are shown on external browser
                webView.GoBack();                      // this is necessary because e.Cancel = true doesn't 
    }                                                  // work in webView.Navigating() event
};

注意:最初,Navigated 事件没有触发,所以我用带有此覆盖的 HybridWebView 拉皮条我的 WebViewClient

public override void OnPageFinished(Android.Webkit.WebView view,string url)
{
    RaisePageFinishedEvent(url,view.Title);

    ...
    ...

    var source = new UrlWebViewSource { Url = url };
    var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage,source,url,WebNavigationResult.Success);
    _renderer.ElementController.SendNavigated(args);
}

我目前使用的是 Xamarin.Forms 4.5。

以编程方式按下后退按钮是一种非常粗糙的解决方法。因此,非常感谢实际取消 url 打开事件的解决方案。

更新:

我必须删除 XAML 中的 CanGoBack="True" 并对我的 OnElementChangedWebVieWrenderer 中的属性进行硬编码:

(Element as IWebViewController).CanGoBack = true;

在 VS 2019 调试器附加运行时,在 XAML 中设置 CanGoBack 属性工作正常,但如果独立运行,应用程序会立即关闭。可以在没有自定义渲染器的简单 WebView 上重现:

ApplyPropertiesVisitor.SetPropertyValue (System.Object xamlelement,Xamarin.Forms.Xaml.XmlName propertyName,System.Object value,System.Object rootElement,Xamarin.Forms.Xaml.INode node,Xamarin.Forms.Xaml.HydrationContext context,System.Xml.IXmlLineInfo lineInfo)
ApplyPropertiesVisitor.Visit (Xamarin.Forms.Xaml.ValueNode node,Xamarin.Forms.Xaml.INode parentNode)
ValueNode.Accept (Xamarin.Forms.Xaml.IXamlNodeVisitor visitor,Xamarin.Forms.Xaml.INode parentNode)
ElementNode.Accept (Xamarin.Forms.Xaml.IXamlNodeVisitor visitor,Xamarin.Forms.Xaml.INode parentNode)
RootNode.Accept (Xamarin.Forms.Xaml.IXamlNodeVisitor visitor,Xamarin.Forms.Xaml.INode parentNode)
XamlLoader.Visit (Xamarin.Forms.Xaml.RootNode rootnode,Xamarin.Forms.Xaml.HydrationContext visitorContext,System.Boolean useDesignProperties)
XamlLoader.Load (System.Object view,System.String xaml,System.Reflection.Assembly rootAssembly,System.Type callingType)
Extensions.LoadFromXaml[TXaml] (TXaml view,System.Type callingType)
WebPageCollabora.InitializeComponent ()
CloudplanMobileClient.WebPageCollabora..ctor (System.String url) [0x00031] in <6b79d357cd4641c5bd9a69278958d871>:0
WebPage+<>c__displayClass9_0.<OpenNewPage>b__0 ()
Thread+RunnableImplementor.Run ()
IRunnableInvoker.n_Run (system.intPtr jnienv,system.intPtr native__this)
(wrapper dynamic-method) Android.Runtime.DynamicmethodNameCounter.27(intptr,intptr)

解决方法

我想知道为什么错误明显 has been fixed in 2020 并且我仍然遇到问题。然后我注意到该修复仅应用于 FormsWebViewClient 而不是原生的 Xamarin.AndroidWebViewClient。我只是通过从 HybridWebViewRenderer 而不是 FormsWebViewClient 派生在我的 WebViewClient 中使用的网络客户端解决了这个问题,并稍微修改了构造函数:

using Xamarin.Forms.Platform.Android;

...

namespace MyApp.Droid
{    
    // note: class was derived from 'WebViewClient' before
    public class JavascriptWebViewClient : FormsWebViewClient  
    {
        HybridWebViewRenderer _renderer;
        string _javascript;

        // note: now also calling base class constructor with renderer as parameter
        public JavascriptWebViewClient(string javascript,HybridWebViewRenderer renderer) : base(renderer)
        {
            _javascript = javascript;
            _renderer = renderer ?? throw new ArgumentNullException("renderer");
        }

    ...

    }
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...