使用 BlazorWebView 在 .NET MAUI 应用中托管 Blazor Web 应用

.NET 多平台应用 UI (.NET MAUI) BlazorWebView 是一个控件,可用于在 .NET MAUI 应用中托管 Blazor Web 应用。 这些应用称为 Blazor 混合应用,使 Blazor Web 应用能够与平台功能和 UI 控件集成。 BlazorWebView 控件可以添加到 .NET MAUI 应用的任何页面,并指向 Blazor 应用的根目录。 Razor 组件在 .NET 进程中本机运行,并将 Web UI 呈现到嵌入式 Web 视图控件。 在 .NET MAUI 中,Blazor 混合应用可以在 .NET MAUI 支持的所有平台上运行。

BlazorWebView 定义以下属性:

  • HostPage,类型为 string?,用于定义 Blazor Web 应用的根目录页。
  • RootComponents,类型为 RootComponentsCollection,指定可添加到控件的根组件的集合。
  • HostPage,类型为 string?,用于定义 Blazor Web 应用的根页。
  • RootComponents,类型为 RootComponentsCollection,指定可添加到控件的根组件的集合。
  • StartPath,类型为 string,用于定义 Blazor 导航上下文中完成加载 Blazor 组件时初始导航的路径。

RootComponent 类定义以下属性:

  • Selector,类型为 string?,用于定义 CSS 选择器字符串,该字符串指定应在文档中放置组件的位置。
  • ComponentType,类型为 Type?,用于定义根组件的类型。
  • Parameters,类型为 IDictionary<string, object?>?,用于表示要传递给根组件的可选参数字典。

此外,BlazorWebView 定义以下事件:

  • BlazorWebViewInitializing,包含一个随附的 BlazorWebViewInitializingEventArgs 对象,该对象在 BlazorWebView 初始化之前引发。 此事件允许自定义 BlazorWebView 配置。
  • BlazorWebViewInitialized,附带 BlazorWebViewInitializedEventArgs 对象,该对象在 BlazorWebView 初始化后,呈现任何组件之前引发。 此事件允许检索特定于平台的 Web 视图实例。
  • UrlLoading,随附 UrlLoadingEventArgs 对象,单击 BlazorWebView 内某个超链接时引发。 此事件允许自定义超链接是否在 BlazorWebView 中,在外部应用中打开,或者是否 URL 加载尝试已取消。

现有 Razor 组件可以通过将代码移动到应用中,或通过引用包含组件的现有类库或包,在 .NET MAUI Blazor 应用中使用。 详情请参阅在 ASP.NET Core Blazor Hybrid 中重复使用 Razor 组件

浏览器开发者工具可用于检查 .NET MAUI Blazor 应用。 有关详细信息,请参阅 将浏览器开发者工具与“ASP.NET Core Blazor 混合”配合使用

注意

虽然 Visual Studio 安装开发 .NET MAUI Blazor 应用所需的所有工具,但 Windows 上的 .NET MAUI Blazor 应用的最终用户必须安装 WebView2 运行时。

有关 Blazor 混合应用的详细信息,请参阅 ASP.NET Core Blazor 混合

创建 .NET MAUI Blazor 应用

.NET MAUI Blazor 应用可以通过 .NET MAUI Blazor 应用模板在Visual Studio中创建:

.NET MAUI Blazor 应用项目模板屏幕截图。

这个项目模板创建了一个多目标 .NET MAUI Blazor 应用,可以部署到 Android、iOS、macOS 和 Windows 上。 有关创建 .NET MAUI Blazor 应用的分步说明,请参阅生成 .NET MAUI Blazor 应用

项目模板创建的 BlazorWebView 是在 MainPage.xaml 中定义的,并指向 Blazor 应用的根目录:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:BlazorWebViewDemo"
             x:Class="BlazorWebViewDemo.MainPage"
             BackgroundColor="{DynamicResource PageBackgroundColor}">

    <BlazorWebView HostPage="wwwroot/index.html">
        <BlazorWebView.RootComponents>
            <RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
        </BlazorWebView.RootComponents>
    </BlazorWebView>

</ContentPage>

应用的根 Razor 组件 位于 Main.razor 中,Razor 编译为应用程序根命名空间中命名为 Main 的类型。 其余 Razor 组件位于“Pages”“共享”项目文件夹中,与默认 Blazor Web 模板中使用的组件相同。 应用的静态 Web 资产位于 wwwroot 文件夹中。

将 BlazorWebView 添加到现有应用

向现有 .NET MAUI 应用添加 BlazorWebView 的过程如下所示:

  1. 通过编辑其 CSPROJ 项目文件的第一行,将 Razor SDK,Microsoft.NET.Sdk.Razor 添加到项目:

    <Project Sdk="Microsoft.NET.Sdk.Razor">
    

    为 Blazor 项目生成和打包包含 Razor 文件的项目需要 Razor SDK。

  2. 将应用的根 Razor组件添加到项目中。

  3. Razor 组件添加到名为“Pages”“共享”的项目文件夹中。

  4. 将静态 Web 资产添加到名为 wwwroot 的项目文件夹中。

  5. 将任何可选的 _Imports.razor 文件添加到项目。

  6. BlazorWebView 添加到 .NET MAUI 应用中的页面,并将其指向 Blazor 应用的根目录:

    <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:local="clr-namespace:MyBlazorApp"
                 x:Class="MyBlazorApp.MainPage">
    
        <BlazorWebView HostPage="wwwroot/index.html">
            <BlazorWebView.RootComponents>
                <RootComponent Selector="#app" ComponentType="{x:Type local:Main}" />
            </BlazorWebView.RootComponents>
        </BlazorWebView>
    
    </ContentPage>
    
  7. 修改 MauiProgram 类的 CreateMauiApp 方法,以注册 BlazorWebView 控件以在应用中使用。 为此,请在 IServiceCollection 对象上调用 AddMauiBlazorWebView 方法,将组件 Web 视图服务添加到服务集合:

    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
            var builder = MauiApp.CreateBuilder();
            builder
                .UseMauiApp<App>()
                .ConfigureFonts(fonts =>
                {
                    fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                });
    
            builder.Services.AddMauiBlazorWebView();
    #if DEBUG
            builder.Services.AddBlazorWebViewDeveloperTools();
    #endif
            // Register any app services on the IServiceCollection object
            // e.g. builder.Services.AddSingleton<WeatherForecastService>();
    
            return builder.Build();
        }
    }
    

通过本机 UI 访问范围内的服务

BlazorWebView 具有一种 TryDispatchAsync 方法,该方法以异步方式调用指定的 Action<ServiceProvider>,并传入 Razor 组件中可用的作用域服务。 这样,本机 UI 中的代码就可以访问范围内服务,例如 NavigationManager

private async void OnMyMauiButtonClicked(object sender, EventArgs e)
{
    var wasDispatchCalled = await blazorWebView.TryDispatchAsync(sp =>
    {
        var navMan = sp.GetRequiredService<NavigationManager>();
        navMan.CallSomeNavigationApi(...);
    });

    if (!wasDispatchCalled)
    {
        // Consider what to do if it the dispatch fails - that's up to your app to decide.
    }
}

诊断问题

BlazorWebView 具有内置日志记录,可帮助诊断 Blazor Hybrid 应用中的问题。 启用此日志记录分为两个步骤:

  1. 启用 BlazorWebView 和相关组件来记录诊断信息。
  2. 配置记录器以将日志输出写入到可以查看的位置。

有关日志记录的详细信息,请参阅 C# 和 .NET 中的日志记录

启用 BlazorWebView 日志记录

所有日志记录配置都可以作为依赖项注入系统中服务注册的一部分执行。 要在 Microsoft.AspNetCore.Components.WebView 命名空间下为 BlazorWebView 和相关组件启用最大日志记录,请在应用服务的注册位置添加以下代码:

services.AddLogging(logging =>
{
    logging.AddFilter("Microsoft.AspNetCore.Components.WebView", LogLevel.Trace);
});

或者,使用以下代码为使用 Microsoft.Extensions.Logging 的每个组件启用最大日志记录:

services.AddLogging(logging =>
{
    logging.SetMinimumLevel(LogLevel.Trace);
});

配置日志记录输出并查看输出

配置组件以写入日志信息后,需要配置记录器应写入日志的位置,然后查看日志输出。

“调试”日志记录提供程序使用 Debug 语句写入输出,可以从 Visual Studio 查看输出。

要配置“调试”日志记录提供程序,请在项目中添加对 Microsoft.Extensions.Logging.Debug NuGet 包的引用。 然后,调用 AddDebug 扩展方法,将调用内的提供程序注册至在上一步中添加的 AddLogging

services.AddLogging(logging =>
{
    logging.AddFilter("Microsoft.AspNetCore.Components.WebView", LogLevel.Trace);
    logging.AddDebug();
});

从已启用调试的 Visual Studio 运行应用时,可以在 Visual Studio 的“输出”窗口中查看调试输出。

在 iOS 上播放内联视频

若要在 iOS 上的 Blazor 混合应用中播放内联视频,应在 BlazorWebView 中:

  • UrlLoadingStrategy 属性设置为 OpenInWebView。 可以在 UrlLoading 事件的事件处理程序中完成此操作:

    private void BlazorUrlLoading(object? sender, UrlLoadingEventArgs e)
    {
    #if IOS
        e.UrlLoadingStrategy = UrlLoadingStrategy.OpenInWebView;
    #endif
    }
    
  • 确保 Configuration 对象中的 AllowsInlineMediaPlayback 属性设置为 true。 可以在 BlazorWebViewInitializing 事件的事件处理程序中完成此操作:

    private void BlazorWebViewInitializing(object? sender, BlazorWebViewInitializingEventArgs e)
    {
    #if IOS
        e.Configuration.AllowsInlineMediaPlayback = true;
    #endif
    }