问题描述
我想将打开的 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"
并对我的 OnElementChanged
的 WebVieWrenderer
中的属性进行硬编码:
(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.Android
类 WebViewClient
。我只是通过从 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");
}
...
}
}