我正在使用 Visual Studio 2022 开发一个包含 WebView 对象的 NET MAUI 移动应用程序。 源网站 mywebsite.com 已正确加载,并且其所有内部链接均有效。
我的目标是确保当单击指向不同网站(例如 microsoft.com)的链接时,该网站会在用户手机的默认浏览器中打开。
问题是,当我单击 microsoft.com(或任何其他外部链接)时,没有任何反应。
无论 HTML 中的目标是否设置为 _blank,这些外部链接都不会触发导航事件;此处提供的解决方案(MAUI Webview target =“_blank”href重定向不适用于android)和此处(拦截用户在WebView(.NET Maui)中点击的所有链接)对我不起作用。
单击 mywebsite.com 内部链接时会定期触发导航事件。
我的 MainPage.xaml.cs 包含:
public MainPage()
{
InitializeComponent();
// Subscribe to the Navigating event
proteoWebView.Navigating += OnNavigating;
// Subscribe to the Navigated event
proteoWebView.Navigated += OnNavigated;
}
private void OnNavigating(object sender, WebNavigatingEventArgs e)
{
// Check if the URL is external
if (!e.Url.StartsWith("https://mywebsite.com"))
{
// Cancel the navigation in the WebView
e.Cancel = true;
// Open the URL in the default browser of the user's phone
Launcher.TryOpenAsync(e.Url);
}
}
我的 MainPage.xaml 包含:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ProteoApp.MainPage"
NavigationPage.HasNavigationBar="False">
<Grid>
<WebView
x:Name="proteoWebView"
Source="https://mywebsite.com"
Grid.Row="0"
Grid.Column="0"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"/>
</Grid>
</ContentPage>
其他信息:我正在使用 Visual Studio 2022、.NET 7.0 进行开发,并且我在 Pixel 5 – API 33 (13.0 Android) 模拟器上遇到了该问题。
我应该纠正自己。
具有 target="_blank" 属性的外部链接不会触发 OnNavigating 事件。 没有 target="_blank" 属性的外部链接会触发 OnNavigating 事件。
此外,为了打开用户手机的默认浏览器,必须执行异步调用:
private void OnNavigating(object sender, WebNavigatingEventArgs e)
{
if (!e.Url.StartsWith("https://mywebsite.com"))
{
e.Cancel = true;
Task.Run(async () =>
{
await Launcher.OpenAsync(e.Url);
});
}
正如我所提到的,上面的代码仅适用于没有 target="_blank" 属性的外部链接。 为了使其也适用于具有 target="_blank" 属性的外部链接,需要将此代码添加到 OnNaviged 事件中:
private void OnNavigated(object sender, WebNavigatedEventArgs e)
{
//The following code changes the target of all the links in _self
proteoWebView.EvaluateJavaScriptAsync(@"(function() {
var links = document.getElementsByTagName('a');
for (var i = 0; i < links.length; i++)
{
links[i].setAttribute('target', '_self');
}
})()");
}
这解决了我的问题。
就我而言,无论链接的目标如何定义,在 Android 中我永远无法导航到外部链接(使用
Navigating
的 WebView
事件)。
我解决了这个问题,就像我为 Xamarin.Forms 项目所做的那样:
创建自定义
WebChromeClient
:
/// <summary>
/// External links tapped in a WebView don't open in .Net MAUI.
/// In order to be able to open links in Android in the web view, a <see cref="ExtendedWebViewChrome"/>
/// can be set to intercept taps on external links and open the default browser.
/// </summary>
internal class ExtendedWebViewChrome : WebChromeClient
{
/// <inheritdoc/>
public override bool OnCreateWindow(WebView view, bool isDialog, bool isUserGesture, Message resultMsg)
{
// Get information on where the user tapped in the web view.
var result = view.GetHitTestResult();
if (result == null)
{
return base.OnCreateWindow(view, isDialog, isUserGesture, resultMsg);
}
// Extract the external link URL of the link from the hit result Extra property.
var externalLinkUrl = result.Extra;
try
{
var externalLinkUri = Uri.Parse(externalLinkUrl);
Context context = view.Context;
Intent browserIntent = new Intent(Intent.ActionView, externalLinkUri);
context.StartActivity(browserIntent);
return false;
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(
$"There was an error trying to open the following link: {externalLinkUrl}.\n " +
$"Exception occurred: {exception.Message} at {exception.StackTrace}");
}
// Something went wrong, return what parent would return.
return base.OnCreateWindow(view, isDialog, isUserGesture, resultMsg);
}
}
然后您可以在自定义渲染器中使用它(仍然没有迁移到 MAUI 处理程序):
/// <summary>
/// Sets the AllowFileAccess flag to true and sets horizontal scroll to the right for RTL locales.
/// </summary>
public class ExtendedWebViewRenderer : WebViewRenderer
{
/// <summary>
/// Default constructor.
/// </summary>
public ExtendedWebViewRenderer(Context context) : base(context) { }
/// <summary>
/// Fires on element changed.
/// </summary>
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
return;
}
// Enables or disables file system access within WebView.
// This setting was by default true before API level 30 but now it is needed to be set explicitly.
// It needs to be set before the attempt to load the HTML is made.
Control.Settings.AllowFileAccess = true;
// External links tapped in a WebView don't open in .NET MAUI.
// In order to solve the issue, a custom web client can be set to intercept link taps.
Control.SetWebChromeClient(new ExtendedWebViewChrome());
...
}
}
奇怪的是,这个问题只发生在 Android 中,并且如果您使用
WebView
设置 UrlWebViewSource
源。如果使用 HtmlWebViewSource
,则可以使用 Navigating
事件处理程序打开外部链接。
当我在 MAUI 中工作时,我注意到一些 XAML 操作(例如附加到事件然后在后面的代码中处理)似乎是错误的。这也不例外。不要在 XAML 中附加事件,而是在 InitializeComponent 之后的 C# 页面构造函数中附加事件。
webView.Navigating += WebView_Navigating;这使得我的活动可以毫无问题地启动。 XAML 有问题,如果它不能按预期工作,请尝试使用 C#。