WebView

.NET Multi-platform App UI (.NET MAUI) WebView 可在应用中显示远程网页、本地 HTML 文件和 HTML 字符串。 WebView 显示的内容包含对级联样式表 (CSS) 和 JavaScript 的支持。 默认情况下,.NET MAUI 项目包含 WebView 显示远程网页所需的平台权限。

WebView 定义以下属性:

  • Cookies,类型为 CookieContainer,为 Cookie 集合提供存储。
  • CanGoBack,类型为 bool,指示用户是否可导航到之前的页面。 这是只读属性。
  • CanGoForward,类型为 bool,指示用户是否可以向前导航。 这是只读属性。
  • Source,类型为 WebViewSource,表示 WebView 的显示位置。
  • UserAgent,类型为 string,表示用户代理。 默认值为基础平台浏览器的用户代理,如果无法确定,则为 null

这些属性由 BindableProperty 对象提供支持,表示它们可以是数据绑定的目标,并可以设置样式。

可以将 Source 属性设置为均派生自 WebViewSourceUrlWebViewSource 对象或 HtmlWebViewSource 对象。 UrlWebViewSource 用于加载使用 URL 指定的网页,而 HtmlWebViewSource 对象用于加载本地 HTML 文件或本地 HTML。

WebView 定义在页面导航启动时引发的 Navigating 事件,以及在页面导航完成时引发的 Navigated 事件。 Navigating 事件附带的 WebNavigatingEventArgs 对象定义类型为 boolCancel 属性,可用于取消导航。 Navigated 事件附带的 WebNavigatedEventArgs 对象定义类型为 WebNavigationResultResult 属性,用于指示导航结果。

重要说明

WebView 包含在 HorizontalStackLayoutStackLayoutVerticalStackLayout 中时,它必须指定其 HeightRequestWidthRequest 属性。 如果无法指定这些属性,则 WebView 不会呈现。

显示网页

若要显示远程网页,需将 Source 属性设置为指定 URI 的 string

<WebView Source="https://learn.microsoft.com/dotnet/maui" />

等效 C# 代码如下:

WebView webvView = new WebView
{
    Source = "https://learn.microsoft.com/dotnet/maui"
};

URI 的格式必须完全符合指定的协议。

注意

尽管 Source 属性的类型为 WebViewSource,但可以将该属性设置为基于字符串的 URI。 这是因为 .NET MAUI 包含类型转换器和隐式转换运算符,可用于将基于字符串的 URI 转换为 UrlWebViewSource 对象。

在 iOS 和 Mac Catalyst 上配置应用传输安全

自版本 9 起,iOS 将仅允许应用与安全服务器通信。 应用必须选择启用与不安全服务器的通信。

以下 Info.plist 配置展示了如何使特定域绕过 Apple 传输安全 (ATS) 要求:

	<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSExceptionDomains</key>
		<dict>
			<key>mydomain.com</key>
			<dict>
				<key>NSIncludesSubdomains</key>
				<true/>
				<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
				<true/>
				<key>NSTemporaryExceptionMinimumTLSVersion</key>
				<string>TLSv1.1</string>
			</dict>
		</dict>
	</dict>

最佳做法是仅允许特定域绕过 ATS,从而允许使用受信任的站点,同时受益于针对不受信任域的额外安全保护。

以下 Info.plist 配置展示了如何为应用禁用 ATS:

	<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSAllowsArbitraryLoads</key>
		<true/>
	</dict>

重要说明

如果应用需要连接到不安全的网站,应始终使用 NSExceptionDomains 密钥将域作为例外输入,而不是使用 NSAllowsArbitraryLoads 密钥完全关闭 ATS。

显示本地 HTML

若要显示内联 HTML,需将 Source 属性设置为 HtmlWebViewSource 对象:

<WebView>
    <WebView.Source>
        <HtmlWebViewSource Html="&lt;HTML&gt;&lt;BODY&gt;&lt;H1&gt;.NET MAUI&lt;/H1&gt;&lt;P&gt;Welcome to WebView.&lt;/P&gt;&lt;/BODY&gt;&lt;HTML&gt;" />
    </WebView.Source>
</WebView>

在 XAML 中,由于对 <> 符号进行字符转义,HTML 字符串可能变得不可读取。 因此,为了提高可读性,可以在 CDATA 部分中内联 HTML:

<WebView>
    <WebView.Source>
        <HtmlWebViewSource>
            <HtmlWebViewSource.Html>
                <![CDATA[
                <HTML>
                <BODY>
                <H1>.NET MAUI</H1>
                <P>Welcome to WebView.</P>
                </BODY>
                </HTML>
                ]]>
            </HtmlWebViewSource.Html>
        </HtmlWebViewSource>
    </WebView.Source>
</WebView>

等效 C# 代码如下:

WebView webView = new WebView
{
    Source = new HtmlWebViewSource
    {
        Html = @"<HTML><BODY><H1>.NET MAUI</H1><P>Welcome to WebView.</P></BODY></HTML>"
    }
};

显示本地 HTML 文件

若要显示本地 HTML 文件,需将该文件添加到应用项目的 Resources\Raw 文件夹中,并将其生成操作设置为 MauiAsset。 然后,可以从内联 HTML(在设置为 Source 属性值的 HtmlWebViewSource 对象中定义)加载此文件:

<WebView>
    <WebView.Source>
        <HtmlWebViewSource>
            <HtmlWebViewSource.Html>
                <![CDATA[
                <html>
                <head>
                </head>
                <body>
                <h1>.NET MAUI</h1>
                <p>The CSS and image are loaded from local files!</p>
                <p><a href="localfile.html">next page</a></p>
                </body>
                </html>                    
                ]]>
            </HtmlWebViewSource.Html>
        </HtmlWebViewSource>
    </WebView.Source>
</WebView>

本地 HTML 文件可以加载级联样式表 (CSS)、JavaScript 和图像(如果也已使用 MauiAsset 生成操作将它们添加到应用项目中)。

要详细了解原始资产,请参阅原始资产

重新加载内容

WebView 包含可以调用以重新加载其源内容的 Reload 方法:

WebView webView = new WebView();
...
webView.Reload();

调用 Reload 方法时,将触发 ReloadRequested 事件,指示已发出重新加载当前内容的请求。

执行导航

WebView 支持使用 GoBackGoForward 方法以编程方式导航。 这些方法支持在 WebView 页面堆栈中导航,并且只有在检查 CanGoBackCanGoForward 属性的值后才调用:

WebView webView = new WebView();
...

// Go backwards, if allowed.
if (webView.CanGoBack)
{
    webView.GoBack();
}

// Go forwards, if allowed.
if (webView.CanGoForward)
{
    webView.GoForward();
}

当页面导航在 WebView 中以编程方式启动或由用户启动时,会发生以下事件:

  • Navigating,页面导航启动时引发。 Navigating 事件附带的 WebNavigatingEventArgs 对象定义类型为 boolCancel 属性,可用于取消导航。
  • Navigated,页面导航完成时引发。 Navigated 事件附带的 WebNavigatedEventArgs 对象定义类型为 WebNavigationResultResult 属性,用于指示导航结果。

处理 Android 上的权限

浏览到请求访问设备的录制硬件(如摄像头或麦克风)的页面时,必须由 WebView 控件授予权限。 WebView 控件使用 Android 上的 Android.Webkit.WebChromeClient 类型来响应权限请求。 但是,.NET MAUI 提供的 WebChromeClient 实现将忽略权限请求。 你必须创建继承自 MauiWebChromeClient 的新类型并审批权限请求。

重要说明

使用此方法自定义 WebView 以审批权限请求时,必须使用 Android API 26 或更高版本。

从网页发送给 WebView 控件的权限请求不同于从 .NET MAUI 应用发送给用户的权限请求。 .NET MAUI 应用权限由用户请求和审批,针对整个应用。 WebView 控件依赖于应用访问硬件的能力。 为了说明此概念,请考虑请求访问设备摄像头的网页。 即使该请求得到 WebView 控件的批准,但如果 .NET MAUI 应用未从用户获得访问摄像头的权限,网页也无法访问摄像头。

以下步骤演示了如何从 WebView 控件截获使用摄像头的权限请求。 如果尝试使用麦克风,则步骤将类似,区别在于将使用与麦克风相关的权限,而不是与摄像头相关的权限。

  1. 首先,将所需的应用权限添加到 Android 清单。 打开 Platforms/Android/AndroidManifest.xml 文件,并在 manifest 节点中添加以下内容:

    <uses-permission android:name="android.permission.CAMERA" />
    
  2. 在应用中的某个时间点(例如加载包含 WebView 控件的页面时),会提出权限请求,要求用户允许应用访问摄像头。

    private async Task RequestCameraPermission()
    {
        PermissionStatus status = await Permissions.CheckStatusAsync<Permissions.Camera>();
    
        if (status != PermissionStatus.Granted)
            await Permissions.RequestAsync<Permissions.Camera>();
    }
    
  3. 将以下类添加到 Platforms/Android 文件夹,更改根命名空间以匹配项目的命名空间:

    using Android.Webkit;
    using Microsoft.Maui.Handlers;
    using Microsoft.Maui.Platform;
    
    namespace MauiAppWebViewHandlers.Platforms.Android;
    
    internal class MyWebChromeClient: MauiWebChromeClient
    {
        public MyWebChromeClient(IWebViewHandler handler) : base(handler)
        {
    
        }
    
        public override void OnPermissionRequest(PermissionRequest request)
        {
            // Process each request
            foreach (var resource in request.GetResources())
            {
                // Check if the web page is requesting permission to the camera
                if (resource.Equals(PermissionRequest.ResourceVideoCapture, StringComparison.OrdinalIgnoreCase))
                {
                    // Get the status of the .NET MAUI app's access to the camera
                    PermissionStatus status = Permissions.CheckStatusAsync<Permissions.Camera>().Result;
    
                    // Deny the web page's request if the app's access to the camera is not "Granted"
                    if (status != PermissionStatus.Granted)
                        request.Deny();
                    else
                        request.Grant(request.GetResources());
    
                    return;
                }
            }
    
            base.OnPermissionRequest(request);
        }
    }
    

    在前面的代码片段中,MyWebChromeClient 类继承自 MauiWebChromeClient,并替代 OnPermissionRequest 方法来截获网页权限请求。 将检查每个权限项,以确定是否与表示摄像头的 PermissionRequest.ResourceVideoCapture 字符串常量匹配。 如果摄像头权限匹配,则代码将检查以确定应用是否有权使用摄像头。 如果有权限,则会允许网页的请求。

  4. 使用 Android 的 WebView 控件上的 SetWebChromeClient 方法将 Chrome 客户端设置为 MyWebChromeClient。 以下两个项演示了如何设置 Chrome 客户端:

    • 通过使用名为 theWebViewControl 的 .NET MAUI WebView 控件,可以直接在平台视图(即 Android 控件)上设置 Chrome 客户端:

      ((IWebViewHandler)theWebViewControl.Handler).PlatformView.SetWebChromeClient(new MyWebChromeClient((IWebViewHandler)theWebViewControl.Handler));
      
    • 还可以使用处理程序属性映射来强制所有 WebView 控件使用 Chrome 客户端。 有关详细信息,请参阅处理程序

      当应用启动时,应调用以下代码片段的 CustomizeWebViewHandler 方法,例如在 MauiProgram.CreateMauiApp 方法中。

      private static void CustomizeWebViewHandler()
      {
      #if ANDROID26_0_OR_GREATER
          Microsoft.Maui.Handlers.WebViewHandler.Mapper.ModifyMapping(
              nameof(Android.Webkit.WebView.WebChromeClient),
              (handler, view, args) => handler.PlatformView.SetWebChromeClient(new MyWebChromeClient(handler)));
      #endif
      }
      

设置 Cookie

可以在 WebView 上设置 Cookie,以便将其与 Web 请求一起发送到指定的 URL。 通过将 Cookie 对象添加到 CookieContainer 来设置 Cookie,然后将容器设置为 WebView.Cookies 可绑定属性的值。 以下代码演示了一个示例:

using System.Net;

CookieContainer cookieContainer = new CookieContainer();
Uri uri = new Uri("https://learn.microsoft.com/dotnet/maui", UriKind.RelativeOrAbsolute);

Cookie cookie = new Cookie
{
    Name = "DotNetMAUICookie",
    Expires = DateTime.Now.AddDays(1),
    Value = "My cookie",
    Domain = uri.Host,
    Path = "/"
};
cookieContainer.Add(uri, cookie);
webView.Cookies = cookieContainer;
webView.Source = new UrlWebViewSource { Url = uri.ToString() };

在此示例中,将向 CookieContainer 对象添加一个 Cookie,然后将其设置为 WebView.Cookies 属性的值。 当 WebView 向指定的 URL 发送 Web 请求时,将随请求一起发送 Cookie。

调用 JavaScript

WebView 包含从 C# 调用 JavaScript 函数并将任何结果返回给执行调用的 C# 代码的功能。 此互操作可通过 EvaluateJavaScriptAsync 方法完成,如以下示例所示:

Entry numberEntry = new Entry { Text = "5" };
Label resultLabel = new Label();
WebView webView = new WebView();
...

int number = int.Parse(numberEntry.Text);
string result = await webView.EvaluateJavaScriptAsync($"factorial({number})");
resultLabel.Text = $"Factorial of {number} is {result}.";

WebView.EvaluateJavaScriptAsync 方法计算指定为参数的 JavaScript,并返回任何结果作为 string。 在此示例中,将调用 factorial JavaScript 函数,该函数将返回 number 的阶乘作为结果。 此 JavaScript 函数在 WebView 加载的本地 HTML 文件中定义,如以下示例所示:

<html>
<body>
<script type="text/javascript">
function factorial(num) {
        if (num === 0 || num === 1)
            return 1;
        for (var i = num - 1; i >= 1; i--) {
            num *= i;
        }
        return num;
}
</script>
</body>
</html>

在 iOS 和 Mac Catalyst 上配置本机 WebView

本机 WebView 控件是 iOS 和 Mac Catalyst 上派生自 WKWebViewMauiWKWebView。 其中一个 MauiWKWebView 构造函数重载支持指定 WKWebViewConfiguration 对象,该对象提供有关如何配置 WKWebView 对象的信息。 典型的配置包括设置用户代理、指定可用于 Web 内容的 Cookie,以及将自定义脚本注入到 Web 内容中。

可以在应用中创建 WKWebViewConfiguration 对象,然后根据需要配置其属性。 或者,也可以调用静态 MauiWKWebView.CreateConfiguration 方法来检索 .NET MAUI 的 WKWebViewConfiguration 对象,然后对其进行修改。 然后,可以将 WKWebViewConfiguration 对象指定为 MauiWKWebView 构造函数重载的参数。

由于在 iOS 和 Mac Catalyst 上创建处理程序的平台视图后,就无法更改本机 WebView 的配置,因此应创建自定义处理程序工厂委托以对其进行修改:

#if IOS || MACCATALYST
using WebKit;
using CoreGraphics;
using Microsoft.Maui.Platform;
using Microsoft.Maui.Handlers;
#endif
...

#if IOS || MACCATALYST
    Microsoft.Maui.Handlers.WebViewHandler.PlatformViewFactory = (handler) =>
    {
        WKWebViewConfiguration config = MauiWKWebView.CreateConfiguration();
        config.ApplicationNameForUserAgent = "MyProduct/1.0.0";
        return new MauiWKWebView(CGRect.Empty, (WebViewHandler)handler, config);
    };
#endif

注意

在应用中显示 WebView 之前,应使用 WKWebViewConfiguration 对象配置 MauiWKWebView。 执行此操作的适当位置位于应用的启动路径中,例如 MauiProgram.cs 或 App.xaml.cs

在 iOS 和 Mac Catalyst 上设置媒体播放首选项

默认情况下,会为 iOS 和 Mac Catalyst 上的 WebView 启用 HTML5 视频的内联媒体播放,包括自动播放和画中画。 若要更改默认设置或设置其他媒体播放首选项,应创建自定义处理程序工厂委托,因为创建处理程序的平台视图后,就无法更改媒体播放首选项。 下面的代码展示了执行此操作的示例:

#if IOS || MACCATALYST
using WebKit;
using CoreGraphics;
using Microsoft.Maui.Platform;
using Microsoft.Maui.Handlers;
#endif
...

#if IOS || MACCATALYST
    Microsoft.Maui.Handlers.WebViewHandler.PlatformViewFactory = (handler) =>
    {
        WKWebViewConfiguration config = MauiWKWebView.CreateConfiguration();

        // True to play HTML5 videos inliine, false to use the native full-screen controller.
        config.AllowsInlineMediaPlayback = false;

        // True to play videos over AirPlay, otherwise false.
        config.AllowsAirPlayForMediaPlayback = false;

        // True to let HTML5 videos play Picture in Picture.
        config.AllowsPictureInPictureMediaPlayback = false;

        // Media types that require a user gesture to begin playing.
        config.MediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypes.All;

        return new MauiWKWebView(CGRect.Empty, (WebViewHandler)handler, config);
    };
#endif

有关在 iOS 上配置 WebView 的详细信息,请参阅在 iOS 和 Mac Catalyst 上配置本机 WebView

在 Mac Catalyst 上检查 WebView

若要在 Mac Catalyst 上使用 Safari 开发人员工具检查 WebView 的内容,需将以下代码添加到应用:

#if MACCATALYST
        Microsoft.Maui.Handlers.WebViewHandler.Mapper.AppendToMapping("Inspect", (handler, view) =>
        {
            if (OperatingSystem.IsMacCatalystVersionAtLeast(16, 6))
                handler.PlatformView.Inspectable = true;
        });
#endif

此代码自定义 Mac Catalyst 上的 WebViewHandler 属性映射器,以使 WebView 内容可由 Safari 开发人员工具检查。 有关处理程序的详细信息,请参阅处理程序

若要在 Mac Catalyst 应用中使用 Safari 开发人员工具:

  1. 在 Mac 上打开 Safari。
  2. 在 Safari 中,选中“Safari > 设置 > 高级 > 在菜单栏中显示‘开发’菜单”复选框。
  3. 运行 .NET MAUI Mac Catalyst 应用。
  4. 在 Safari 中,选择“开发 > {Device name}”菜单,其中 {Device name} 占位符是设备名称,如 Macbook Pro。 然后选择应用名称下的条目,该条目还会突出显示正在运行的应用。 这会导致“Web 检查器”窗口出现。

启动系统浏览器

可以使用由 Microsoft.Maui.Essentials 提供的 Launcher 类在系统 Web 浏览器中打开 URI。 调用启动器的 OpenAsync 方法并传入表示要打开的 URI 的 stringUri 参数:

await Launcher.OpenAsync("https://learn.microsoft.com/dotnet/maui");

有关详细信息,请参阅启动器