Share via


Criar um aplicativo .NET MAUIBlazor Hybrid com um aplicativo Web Blazor

Este artigo mostra como criar um aplicativo .NET MAUIBlazor Hybrid com um aplicativo Web Blazor que usa uma interface do usuário compartilhada por meio de uma biblioteca de classes Razor (RCL).

Pré-requisitos e etapas preliminares

Para ver pré-requisitos e etapas preliminares, confira Criar um aplicativo .NET MAUIBlazor Hybrid. É recomendável usar o tutorial .NET MAUIBlazor Hybrid para configurar o seu sistema local para desenvolvimento .NET MAUI antes de usar as diretrizes neste artigo.

.NET MAUIBlazor Aplicativo de exemplo do Aplicativo Web

Obtenha o aplicativo de exemplo nomeado MauiBlazorWeb do repositório GitHub de exemplos Blazor (dotnet/blazor-samples) (.NET 8 ou posterior).

O aplicativo de exemplo é uma solução inicial que contém um aplicativo (nativo, multiplataforma) .NET MAUIBlazor Hybrid, um aplicativo Web Blazor e uma biblioteca de classes (RCL) Razor que contém a interface do usuário compartilhada (componentes Razor) usada pelos aplicativos nativos e Web.

Migrar uma solução do .NET MAUIBlazor Hybrid

Em vez de usar o aplicativo de exemplo, você pode migrar um aplicativo .NET MAUIBlazor Hybrid existente com as diretrizes nesta seção usando o Visual Studio.

Adicione um novo projeto à solução com o modelo de projeto de aplicativo Web Blazor. Selecione as seguintes opções:

  • Nome do projeto: use o nome da solução acrescido de .Web. Os exemplos neste artigo pressupõem a seguinte nomenclatura:
    • Solução: MauiBlazorWeb
    • Projeto do MAUI: MauiBlazorWeb.Maui
    • Aplicativo Web Blazor: MauiBlazorWeb.Web
    • Biblioteca de classes Razor (RCL) (adicionada em uma etapa posterior): MauiBlazorWeb.Shared
  • Tipo de autenticação: Nenhum
  • Configurar para HTTPS: selecionado (habilitado)
  • Modo de renderização interativo: Servidor
  • Local de interatividade: Global
  • Páginas de exemplo: não selecionadas (desabilitadas)

A configuração de local de interatividade para Global é importante porque os aplicativos MAUI sempre são executados interativamente e lançam erros em páginas de componentes Razor que especificam explicitamente um modo de renderização. Se você não usar um modo de renderização global, deverá implementar a abordagem descrita na seção Usar Blazor modos de renderização depois de seguir as diretrizes nesta seção. Para obter mais informações, confira BlazorO WebView precisa de uma maneira de habilitar a substituição de ResolveComponentForRenderMode (dotnet/aspnetcore nº 51235).

Adicione um novo projeto da biblioteca de classes Razor (RCL) à solução. Os exemplos neste artigo pressupõem que o projeto seja denominado MauiBlazorWeb.Shared. Não selecione Páginas e modos de exibição do suporte ao adicionar o projeto à solução.

Adicione referências de projeto à RCL do projeto MAUI e do projeto de aplicativo Web Blazor.

Mova a pasta Components e todo o conteúdo do projeto MAUI para a RCL. Confirme se a pasta Components foi excluída do projeto MAUI.

Dica

Ao mover uma pasta ou arquivo no Visual Studio, use comandos de teclado ou o menu de atalho clicando com o botão direito do mouse para uma operação de recortar e colar. Arrastar a pasta no Visual Studio copia apenas de um local para outro, o que requer uma etapa extra para excluir o original.

Mova a pasta css da pasta wwwroot do projeto MAUI para a pasta wwwroot da RCL.

Exclua os seguintes arquivos da pasta wwwroot da RCL:

  • background.png
  • exampleJsInterop.js

Na RCL, substitua o arquivo raiz _Imports.razor pelo da pasta Components da RCL, substituindo o arquivo existente na RCL e excluindo o original na pasta Components. Depois de mover o arquivo, abra-o e renomeie as duas últimas instruções @using para corresponder ao namespace da RCL. No exemplo a seguir, o namespace da RCL é MauiBlazorWeb.Shared:

@using MauiBlazorWeb.Shared
@using MauiBlazorWeb.Shared.Components

Na raiz do projeto da RCL, exclua os seguintes arquivos:

  • Component1.razor
  • ExampleJsInterop.cs

Na RCL, abra o arquivo Components/Routes.razor e altere MauiProgram para Routes:

- <Router AppAssembly="@typeof(MauiProgram).Assembly">
+ <Router AppAssembly="@typeof(Routes).Assembly">

Abra o arquivo MainPage.xaml no projeto MAUI. Adicione uma referência xmlns:shared à RCL nos atributos ContentPage. No exemplo a seguir, o namespace da RCL é MauiBlazorWeb.Shared. Defina o valor correto para clr-namespace e assembly:

xmlns:shared="clr-namespace:MauiBlazorWeb.Shared;assembly=MauiBlazorWeb.Shared"

Também no arquivo MainPage.xaml, atualize o componente raiz do BlazorWebViewComponentType de local para shared:

- <RootComponent Selector="#app" ComponentType="{x:Type local:Components.Routes}" />
+ <RootComponent Selector="#app" ComponentType="{x:Type shared:Components.Routes}" />

No projeto MAUI, abra o arquivo wwwroot/index.html e altere as folhas de estilos para apontar para o caminho de ativo estático da RCL.

Remova as seguintes linhas:

- <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
- <link rel="stylesheet" href="css/app.css" />

Substitua as linhas anteriores pela marcação a seguir. No exemplo a seguir, o caminho do ativo estático da RCL é _content/MauiBlazorWeb.Shared/:

<link rel="stylesheet" href="_content/MauiBlazorWeb.Shared/css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="_content/MauiBlazorWeb.Shared/css/app.css" />

No aplicativo Web Blazor, abra o arquivo _Imports.razor e adicione as duas instruções @using a seguir para a RCL. No exemplo a seguir, o namespace da RCL é MauiBlazorWeb.Shared:

@using MauiBlazorWeb.Shared
@using MauiBlazorWeb.Shared.Components

No projeto do aplicativo Web Blazor, abra o componente App (Components/App.razor). Remova a folha de estilos app.css:

- <link rel="stylesheet" href="app.css" />

Substitua a linha anterior pelas referências de folha de estilos de ativo estático da RCL. No exemplo a seguir, o caminho do ativo estático da RCL é _content/MauiBlazorWeb.Shared/:

<link rel="stylesheet" href="_content/MauiBlazorWeb.Shared/css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="_content/MauiBlazorWeb.Shared/css/app.css" />

No projeto de aplicativo Web Blazor, exclua a pasta e os arquivos a seguir:

  • Components/Layout pasta
  • Components/Routes.razor
  • Components/Pages/Home.razor
  • wwwroot/app.css

Abra o arquivo Program.cs do aplicativo Web Blazor e adicione um assembly adicional para a RCL ao aplicativo. No exemplo a seguir, o namespace da RCL é MauiBlazorWeb.Shared:

app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddAdditionalAssemblies(typeof(MauiBlazorWeb.Shared._Imports).Assembly);

Execute o projeto MAUI selecionando o projeto no Gerenciador de Soluções e usando o botão Iniciar do Visual Studio.

Execute o projeto de aplicativo Web Blazor selecionando o projeto de aplicativo Web Blazor no Gerenciador de Soluções e usando o botão iniciar do Visual Studio com a configuração de build https.

Se você receber um erro de build afirmando que o assembly da RCL não pode ser resolvido, crie o projeto da RCL primeiro. Se ocorrerem erros de recurso de projeto do MAUI no build, recompile o projeto do MAUI para limpar os erros.

Usar modos de renderização do Blazor

Use as diretrizes em uma das seguintes subseções que correspondem às especificações do aplicativo para aplicar Blazormodos de renderização para um determinado local de interatividade no aplicativo Web Blazor, mas ignore as atribuições de modo de renderização no projeto MAUI.

Subseções de especificação de interatividade e modo de renderização:

Interatividade do Servidor Global

  • Modo de renderização interativo: Servidor
  • Local de interatividade: Global
  • Projetos de solução
    • MAUI (MauiBlazorWeb.Maui)
    • Blazor Aplicativo Web (MauiBlazorWeb.Web)
    • RCL (MauiBlazorWeb.Shared): contém os componentes Razor compartilhados sem definir modos de renderização em cada componente.

Referências de projeto: MauiBlazorWeb.Maui e MauiBlazorWeb.Web têm uma referência de projeto para MauiBlazorWeb.Shared.

Interatividade global Auto ou WebAssembly

  • Modo de renderização interativo: Auto ou WebAssembly
  • Local de interatividade: Global
  • Projetos de solução
    • MAUI (MauiBlazorWeb.Maui)
    • Aplicativo Web Blazor
      • Projeto do servidor: MauiBlazorWeb.Web
      • Projeto do cliente: MauiBlazorWeb.Web.Client
    • RCL (MauiBlazorWeb.Shared): contém os componentes Razor compartilhados sem definir modos de renderização em cada componente.

Referências de projeto:

  • Os projetos MauiBlazorWeb.Maui, MauiBlazorWeb.Web e MauiBlazorWeb.Web.Client têm uma referência de projeto para MauiBlazorWeb.Shared.
  • MauiBlazorWeb.Web tem uma referência de projeto a MauiBlazorWeb.Web.Client.

Interatividade de servidor por página/componente

  • Modo de renderização interativo: Servidor
  • Local de interatividade: Por página/componente
  • Projetos de solução
    • MAUI (MauiBlazorWeb.Maui): chama InteractiveRenderSettings.ConfigureBlazorHybridRenderModes em MauiProgram.cs.
    • Aplicativo Web Blazor (MauiBlazorWeb.Web): não define um atributo de diretiva @rendermode nos componentes HeadOutlet e Routes do componente App (Components/App.razor).
    • RCL (MauiBlazorWeb.Shared): contém os componentes compartilhados Razor que definem o modo de renderização InteractiveServer em cada componente.

MauiBlazorWeb.Maui e MauiBlazorWeb.Web têm uma referência de projeto para MauiBlazorWeb.Shared.

Adicione a classe a seguir à RCL InteractiveRenderSettings. As propriedades de classe são usadas para definir modos de renderização de componente.

O projeto do MAUI é interativo por padrão, portanto, nenhuma ação é tomada no nível do projeto do MAUI além de chamar InteractiveRenderSettings.ConfigureBlazorHybridRenderModes.

Para o aplicativo Web Blazor no cliente Web, os valores da propriedade são atribuídos de RenderMode. Quando os componentes são carregados em um BlazorWebView para o cliente nativo do projeto do MAUI, os modos de renderização não são atribuídos (null) porque o projeto do MAUI define explicitamente as propriedades do modo de renderização para null quando ConfigureBlazorHybridRenderModes é chamado.

InteractiveRenderSettings.cs:

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

namespace MauiBlazorWeb.Shared;

public static class InteractiveRenderSettings
{
    public static IComponentRenderMode? InteractiveServer { get; set; } = 
        RenderMode.InteractiveServer;
    public static IComponentRenderMode? InteractiveAuto { get; set; } = 
        RenderMode.InteractiveAuto;
    public static IComponentRenderMode? InteractiveWebAssembly { get; set; } = 
        RenderMode.InteractiveWebAssembly;

    public static void ConfigureBlazorHybridRenderModes()
    {
        InteractiveServer = null;
        InteractiveAuto = null;
        InteractiveWebAssembly = null;
    }
}

Em MauiProgram.CreateMauiApp de MauiProgram.cs, chame ConfigureBlazorHybridRenderModes:

InteractiveRenderSettings.ConfigureBlazorHybridRenderModes();

No arquivo _Imports.razor da RCL, adicione a seguinte diretiva @using estática global para disponibilizar as propriedades da classe aos componentes:

@using static InteractiveRenderSettings

Observação

A atribuição de modos de renderização por meio das propriedades de classe InteractiveRenderSettings da RCL difere de um aplicativo Web autônomo Blazor típico. Em um aplicativo Web Blazor, os modos de renderização normalmente são fornecidos por RenderMode meio da instrução @using static Microsoft.AspNetCore.Components.Web.RenderMode no arquivo do _Import aplicativo Web Blazor.

Interatividade automática por página/componente

  • Modo de renderização interativo: Auto
  • Local de interatividade: Por página/componente
  • Projetos de solução
    • MAUI (MauiBlazorWeb.Maui): chama InteractiveRenderSettings.ConfigureBlazorHybridRenderModes em MauiProgram.cs.
    • Aplicativo Web Blazor
      • Projeto do servidor: MauiBlazorWeb.Web: não define um atributo de diretiva @rendermode nos componentes HeadOutlet e componentes Routes do componente App (Components/App.razor).
      • Projeto do cliente: MauiBlazorWeb.Web.Client
    • RCL (MauiBlazorWeb.Shared): contém os componentes compartilhados Razor que definem o modo de renderização InteractiveAuto em cada componente.

Referências de projeto:

  • MauiBlazorWeb.Maui, MauiBlazorWeb.Web e MauiBlazorWeb.Web.Client têm uma referência de projeto para MauiBlazorWeb.Shared.
  • MauiBlazorWeb.Web tem uma referência de projeto a MauiBlazorWeb.Web.Client.

Adicionar a classe InteractiveRenderSettings a seguir é adicionado à RCL. As propriedades de classe são usadas para definir modos de renderização de componente.

O projeto do MAUI é interativo por padrão, portanto, nenhuma ação é tomada no nível do projeto do MAUI além de chamar InteractiveRenderSettings.ConfigureBlazorHybridRenderModes.

Para o aplicativo Web Blazor no cliente Web, os valores da propriedade são atribuídos de RenderMode. Quando os componentes são carregados em um BlazorWebView para o cliente nativo do projeto do MAUI, os modos de renderização não são atribuídos (null) porque o projeto do MAUI define explicitamente as propriedades do modo de renderização para null quando ConfigureBlazorHybridRenderModes é chamado.

InteractiveRenderSettings.cs:

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

namespace MauiBlazorWeb.Shared;

public static class InteractiveRenderSettings
{
    public static IComponentRenderMode? InteractiveServer { get; set; } = 
        RenderMode.InteractiveServer;
    public static IComponentRenderMode? InteractiveAuto { get; set; } = 
        RenderMode.InteractiveAuto;
    public static IComponentRenderMode? InteractiveWebAssembly { get; set; } = 
        RenderMode.InteractiveWebAssembly;

    public static void ConfigureBlazorHybridRenderModes()
    {
        InteractiveServer = null;
        InteractiveAuto = null;
        InteractiveWebAssembly = null;
    }
}

Em MauiProgram.CreateMauiApp de MauiProgram.cs, chame ConfigureBlazorHybridRenderModes:

InteractiveRenderSettings.ConfigureBlazorHybridRenderModes();

No arquivo _Imports.razor da RCL, adicione a seguinte diretiva @using estática global para disponibilizar as propriedades da classe aos componentes:

@using static InteractiveRenderSettings

Observação

A atribuição de modos de renderização por meio das propriedades de classe InteractiveRenderSettings da RCL difere de um aplicativo Web autônomo Blazor típico. Em um aplicativo Web Blazor, os modos de renderização normalmente são fornecidos por RenderMode meio da instrução @using static Microsoft.AspNetCore.Components.Web.RenderMode no arquivo do _Import aplicativo Web Blazor.

Interatividade do WebAssembly por página/componente

  • Modo de renderização interativo: WebAssembly
  • Local de interatividade: Por página/componente
  • Projetos de solução
    • MAUI (MauiBlazorWeb.Maui)
    • Aplicativo Web Blazor
      • Projeto do servidor: MauiBlazorWeb.Web: não define um atributo de diretiva @rendermode nos componentes HeadOutlet e componentes Routes do componente App (Components/App.razor).
      • Projeto do cliente: MauiBlazorWeb.Web.Client
    • RCLs
      • MauiBlazorWeb.Shared
      • MauiBlazorWeb.Shared.Client: contém os componentes compartilhados Razor que definem o modo de renderização InteractiveWebAssembly em cada componente. A RCL .Shared.Client é mantida separadamente da RCL .Shared porque o aplicativo deve manter os componentes necessários para execução no WebAssembly separadamente dos componentes executados no servidor e que permanecem no servidor.

Referências de projeto:

  • MauiBlazorWeb.Maui e MauiBlazorWeb.Web têm referências de projeto para MauiBlazorWeb.Shared.
  • MauiBlazorWeb.Web tem uma referência de projeto a MauiBlazorWeb.Web.Client.
  • MauiBlazorWeb.Web.Client e MauiBlazorWeb.Shared têm uma referência de projeto para MauiBlazorWeb.Shared.Client.

Adicione o seguinte parâmetro AdditionalAssemblies à instância do componente Router para o assembly do projeto MauiBlazorWeb.Shared.Client (por meio de seu arquivo _Imports) no arquivo Routes.razor do projeto MauiBlazorWeb.Shared:

<Router AppAssembly="@typeof(Routes).Assembly" 
        AdditionalAssemblies="new [] { typeof(MauiBlazorWeb.Shared.Client._Imports).Assembly }">
    <Found Context="routeData">
        <RouteView RouteData="@routeData" DefaultLayout="@typeof(Components.Layout.MainLayout)" />
        <FocusOnNavigate RouteData="@routeData" Selector="h1" />
    </Found>
</Router>

Adicione o assembly do projeto MauiBlazorWeb.Shared.Client (por meio de seu arquivo _Imports) com a seguinte chamada AddAdditionalAssemblies no arquivo MauiBlazorWeb.Web do projeto Program.cs:

app.MapRazorComponents<App>()    
    .AddInteractiveWebAssemblyRenderMode()
    .AddAdditionalAssemblies(typeof(MauiBlazorWeb.Shared._Imports).Assembly)
    .AddAdditionalAssemblies(typeof(MauiBlazorWeb.Shared.Client._Imports).Assembly); 

Adicionar a classe InteractiveRenderSettings a seguir é adicionado à RCL .Shared.Client. As propriedades de classe são usadas para definir modos de renderização de componentes para componentes baseados em servidor.

O projeto do MAUI é interativo por padrão, portanto, nenhuma ação é tomada no nível do projeto do MAUI além de chamar InteractiveRenderSettings.ConfigureBlazorHybridRenderModes.

Para o aplicativo Web Blazor no cliente Web, os valores da propriedade são atribuídos de RenderMode. Quando os componentes são carregados em um BlazorWebView para o cliente nativo do projeto do MAUI, os modos de renderização não são atribuídos (null) porque o projeto do MAUI define explicitamente as propriedades do modo de renderização para null quando ConfigureBlazorHybridRenderModes é chamado.

InteractiveRenderSettings.cs (.Shared.Client RCL):

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

namespace MauiBlazorWeb.Shared;

public static class InteractiveRenderSettings
{
    public static IComponentRenderMode? InteractiveServer { get; set; } = 
        RenderMode.InteractiveServer;
    public static IComponentRenderMode? InteractiveAuto { get; set; } = 
        RenderMode.InteractiveAuto;
    public static IComponentRenderMode? InteractiveWebAssembly { get; set; } = 
        RenderMode.InteractiveWebAssembly;

    public static void ConfigureBlazorHybridRenderModes()
    {
        InteractiveServer = null;
        InteractiveAuto = null;
        InteractiveWebAssembly = null;
    }
}

Uma versão ligeiramente diferente da classe InteractiveRenderSettings é adicionada à RCL .Shared. Na classe adicionada à RCL .Shared, InteractiveRenderSettings.ConfigureBlazorHybridRenderModes da RCL .Shared.Client é chamado. Isso garante que o modo de renderização de componentes WebAssembly renderizados no cliente MAUI não seja atribuído (null) porque ele é interativo por padrão no cliente nativo.

InteractiveRenderSettings.cs (.Shared RCL):

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;

namespace MauiBlazorWeb.Shared
{
    public static class InteractiveRenderSettings
    {
        public static IComponentRenderMode? InteractiveServer { get; set; } = 
            RenderMode.InteractiveServer;
        public static IComponentRenderMode? InteractiveAuto { get; set; } = 
            RenderMode.InteractiveAuto;
        public static IComponentRenderMode? InteractiveWebAssembly { get; set; } = 
            RenderMode.InteractiveWebAssembly;

        public static void ConfigureBlazorHybridRenderModes()
        {
            InteractiveServer = null;
            InteractiveAuto = null;
            InteractiveWebAssembly = null;
            MauiBlazorWeb.Shared.Client.InteractiveRenderSettings
                .ConfigureBlazorHybridRenderModes();
        }
    }
}

Em MauiProgram.CreateMauiApp de MauiProgram.cs, chame ConfigureBlazorHybridRenderModes:

InteractiveRenderSettings.ConfigureBlazorHybridRenderModes();

No arquivo _Imports.razor da RCL .Shared.Client, adicione @using static InteractiveRenderSettings para disponibilizar as propriedades da classe InteractiveRenderSettings aos componentes:

@using static InteractiveRenderSettings

Observação

A atribuição de modos de renderização por meio das propriedades de classe InteractiveRenderSettings da RCL difere de um aplicativo Web autônomo Blazor típico. Em um aplicativo Web Blazor, os modos de renderização normalmente são fornecidos por RenderMode meio da instrução @using static Microsoft.AspNetCore.Components.Web.RenderMode no arquivo do _Import aplicativo Web Blazor.

Usar interfaces para dar suporte a diferentes implementações de dispositivo

O exemplo a seguir demonstra como usar uma interface para chamar diferentes implementações no aplicativo Web e no aplicativo nativo (MAUI). O exemplo a seguir cria um componente que exibe o fator forma do dispositivo. Use a camada de abstração do MAUI para aplicativos nativos e forneça uma implementação para o aplicativo Web.

Na biblioteca de classes Razor (RCL), crie uma pasta e adicione um arquivo Interfaces nomeado IFormFactor.cs com o código a seguir.

Interfaces/IFormFactor.cs:

namespace MauiBlazorWeb.Shared.Interfaces;

public interface IFormFactor
{
    public string GetFormFactor();
    public string GetPlatform();
}

Na pasta Components da RCL, adicione o seguinte componente DeviceFormFactor.

Components/Pages/DeviceFormFactor.razor:

@page "/device-form-factor"
@using MauiBlazorWeb.Shared.Interfaces
@inject IFormFactor FormFactor

<PageTitle>Form Factor</PageTitle>

<h1>Device Form Factor</h1>

<p>You are running on:</p>

<ul>
    <li>Form Factor: @factor</li>
    <li>Platform: @platform</li>
</ul>

<p>
    <em>This component is defined in the MauiBlazorWeb.Shared library.</em>
</p>

@code {
    private string factor => FormFactor.GetFormFactor();
    private string platform => FormFactor.GetPlatform();
}

Na RCL, adicione uma entrada para o componente DeviceFormFactor ao menu de navegação.

Em Components/Layout/NavMenu.razor:

<div class="nav-item px-3">
    <NavLink class="nav-link" href="device-form-factor">
        <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Form Factor
    </NavLink>
</div>

Forneça implementações em aplicativos Web e nativos.

No Aplicativo Web Blazor, adicione uma pasta chamada Services. Adicione um arquivo à pasta Services nomeada FormFactor.cs com o código a seguir.

Services/FormFactor.cs (Projeto de aplicativo Web do Blazor):

using MauiBlazorWeb.Shared.Interfaces;

namespace MauiBlazorWeb.Web.Services;

public class FormFactor : IFormFactor
{
    public string GetFormFactor()
    {
        return "Web";
    }
    public string GetPlatform()
    {
        return Environment.OSVersion.ToString();
    }
}

No projeto MAUI, adicione uma pasta nomeada Services e adicione um arquivo chamado FormFactor.cs. A camada de abstrações do MAUI é usada para escrever código que funciona em todas as plataformas de dispositivo nativas.

Services/FormFactor.cs (projeto MAUI):

using MauiBlazorWeb.Shared.Interfaces;

namespace MauiBlazorWeb.Maui.Services;

public class FormFactor : IFormFactor
{
    public string GetFormFactor()
    {
        return DeviceInfo.Idiom.ToString();
    }
    public string GetPlatform()
    {
        return DeviceInfo.Platform.ToString() + " - " + DeviceInfo.VersionString;
    }
}

Use a injeção de dependência para obter as implementações desses serviços.

No projeto MAUI, abra o arquivo MauiProgram.cs e adicione as seguintes instruções using à parte superior do arquivo:

using MauiBlazorWeb.Maui.Services;
using MauiBlazorWeb.Shared.Interfaces;

Imediatamente antes da chamada para builder.Build(), adicione o seguinte código para adicionar serviços específicos do dispositivo usados pela RCL:

builder.Services.AddSingleton<IFormFactor, FormFactor>();

No aplicativo Web Blazor, abra o arquivo Program e adicione as seguintes instruções using à parte superior do arquivo:

using MauiBlazorWeb.Shared.Interfaces;
using MauiBlazorWeb.Web.Services;  

Imediatamente antes da chamada para builder.Build(), adicione o seguinte código para adicionar serviços específicos do dispositivo usados pela RCL:

builder.Services.AddScoped<IFormFactor, FormFactor>();

Se a solução também for direcionada ao WebAssembly por meio de um projeto .Web.Client, uma implementação da API anterior também será necessária no projeto .Web.Client.

Você também pode usar diretivas de pré-processador do compilador em sua RCL para implementar uma interface do usuário diferente, dependendo do dispositivo em que o aplicativo está sendo executado. Para este cenário, o aplicativo deve ter vários destinos para a RCL, assim como faz o aplicativo MAUI. Para obter um exemplo, confira o repositório GitHub BethMassi/BethTimeUntil.

Recursos adicionais