Incorporação nativa
Normalmente, um aplicativo do .NET Multi-platform App UI (.NET MAUI) inclui páginas que contêm layouts, como Grid, e layouts que contêm exibições, como Button. Páginas, layouts e exibições derivam de Element. A inserção nativa permite que os controles do .NET MAUI que derivam de Element sejam consumidos em aplicativos nativos .NET para Android, .NET para iOS, .NET para Mac Catalyst e WinUI.
O processo de consumo de um controle MAUI DO .NET em um aplicativo nativo se dá da seguinte forma:
- Crie métodos de extensão para inicializar seu aplicativo nativo inserido. Para obter mais informações, consulte Criar métodos de extensão.
- Crie um único projeto do MAUI do .NET que contenha sua interface do usuário do MAUI do .NET e quaisquer dependências. Para obter mais informações, consulte Criar um projeto único do MAUI do .NET.
- Crie um aplicativo nativo e habilite o suporte ao MAUI do .NET nele. Para obter mais informações, consulte a Política de suporte do MAUI do .NET.
- Inicialize o .NET MAUI em seu projeto de aplicativo nativo. Para obter mais informações, consulte Inicializar o MAUI do .NET.
- Crie a interface de usuário do MAUI do .NET e converta-a no tipo nativo apropriado com o método de extensão
ToPlatformEmbedding
. Para obter mais informações, consulte Consumir os controles do MAUI do .NET.
- Crie um único projeto do MAUI do .NET que contenha sua interface do usuário do MAUI do .NET e quaisquer dependências. Para obter mais informações, consulte Criar um projeto único do MAUI do .NET.
- Crie um aplicativo nativo e habilite o suporte ao MAUI do .NET nele. Para obter mais informações, consulte a Política de suporte do MAUI do .NET.
- Inicialize o .NET MAUI em seu projeto de aplicativo nativo. Para obter mais informações, consulte Inicializar o MAUI do .NET.
- Crie a interface de usuário do MAUI do .NET e converta-a no tipo nativo apropriado com o método de extensão
ToPlatformEmbedding
. Para obter mais informações, consulte Consumir os controles do MAUI do .NET.
Observação
Ao usar a inserção nativa, o mecanismo de associação de dados do MAUI do .NET ainda funciona. Porém, a navegação de página deve ser executada usando a API de navegação nativa.
Criar métodos de extensão
Antes de criar um aplicativo nativo que consome os controles do MAUI do .NET, primeiro você deve criar um projeto de biblioteca de classes do MAUI do .NET e excluir a pasta Plataformas e a classe Class1
dele. Em seguida, adicione uma classe a ela chamada EmbeddedExtensions
que contém o seguinte código:
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Maui.Platform;
#if ANDROID
using PlatformView = Android.Views.View;
using PlatformWindow = Android.App.Activity;
using PlatformApplication = Android.App.Application;
#elif IOS || MACCATALYST
using PlatformView = UIKit.UIView;
using PlatformWindow = UIKit.UIWindow;
using PlatformApplication = UIKit.IUIApplicationDelegate;
#elif WINDOWS
using PlatformView = Microsoft.UI.Xaml.FrameworkElement;
using PlatformWindow = Microsoft.UI.Xaml.Window;
using PlatformApplication = Microsoft.UI.Xaml.Application;
#endif
namespace Microsoft.Maui.Controls;
public static class EmbeddedExtensions
{
public static MauiAppBuilder UseMauiEmbedding(this MauiAppBuilder builder, PlatformApplication? platformApplication = null)
{
#if ANDROID
platformApplication ??= (Android.App.Application)Android.App.Application.Context;
#elif IOS || MACCATALYST
platformApplication ??= UIKit.UIApplication.SharedApplication.Delegate;
#elif WINDOWS
platformApplication ??= Microsoft.UI.Xaml.Application.Current;
#endif
builder.Services.AddSingleton(platformApplication);
builder.Services.AddSingleton<EmbeddedPlatformApplication>();
builder.Services.AddScoped<EmbeddedWindowProvider>();
// Returning null is acceptable here as the platform window is optional - but we don't know until we resolve it
builder.Services.AddScoped<PlatformWindow>(svc => svc.GetRequiredService<EmbeddedWindowProvider>().PlatformWindow!);
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IMauiInitializeService, EmbeddedInitializeService>());
builder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(Window), typeof(EmbeddedWindowHandler));
});
return builder;
}
public static IMauiContext CreateEmbeddedWindowContext(this MauiApp mauiApp, PlatformWindow platformWindow, Window? window = null)
{
var windowScope = mauiApp.Services.CreateScope();
#if ANDROID
var windowContext = new MauiContext(windowScope.ServiceProvider, platformWindow);
#else
var windowContext = new MauiContext(windowScope.ServiceProvider);
#endif
window ??= new Window();
var wndProvider = windowContext.Services.GetRequiredService<EmbeddedWindowProvider>();
wndProvider.SetWindow(platformWindow, window);
window.ToHandler(windowContext);
return windowContext;
}
public static PlatformView ToPlatformEmbedded(this IElement element, IMauiContext context)
{
var wndProvider = context.Services.GetService<EmbeddedWindowProvider>();
if (wndProvider is not null && wndProvider.Window is Window wnd && element is VisualElement visual)
wnd.AddLogicalChild(visual);
return element.ToPlatform(context);
}
private class EmbeddedInitializeService : IMauiInitializeService
{
public void Initialize(IServiceProvider services) =>
services.GetRequiredService<EmbeddedPlatformApplication>();
}
}
Esses métodos de extensão localizam-se no namespace Microsoft.Maui.Controls
e são usados para inicializar seu aplicativo nativo inserido em cada plataforma. Os métodos de extensão referenciam os tipos EmbeddedPlatformApplication
, EmbeddedWindowHandler
e EmbeddedWindowProvider
que você também deve adicionar ao projeto de biblioteca do MAUI do .NET.
O código a seguir mostra a classe EmbeddedPlatformApplication
, que deve ser adicionada ao mesmo projeto de biblioteca do MAUI do .NET que a classe EmbeddedExtensions
:
#if ANDROID
using PlatformApplication = Android.App.Application;
#elif IOS || MACCATALYST
using PlatformApplication = UIKit.IUIApplicationDelegate;
#elif WINDOWS
using PlatformApplication = Microsoft.UI.Xaml.Application;
#endif
namespace Microsoft.Maui.Controls;
internal class EmbeddedPlatformApplication : IPlatformApplication
{
private readonly MauiContext rootContext;
private readonly IMauiContext applicationContext;
public IServiceProvider Services { get; }
public IApplication Application { get; }
public EmbeddedPlatformApplication(IServiceProvider services)
{
IPlatformApplication.Current = this;
#if ANDROID
var platformApp = services.GetRequiredService<PlatformApplication>();
rootContext = new MauiContext(services, platformApp);
#else
rootContext = new MauiContext(services);
#endif
applicationContext = MakeApplicationScope(rootContext);
Services = applicationContext.Services;
Application = Services.GetRequiredService<IApplication>();
}
private static IMauiContext MakeApplicationScope(IMauiContext rootContext)
{
var scopedContext = new MauiContext(rootContext.Services);
InitializeScopedServices(scopedContext);
return scopedContext;
}
private static void InitializeScopedServices(IMauiContext scopedContext)
{
var scopedServices = scopedContext.Services.GetServices<IMauiInitializeScopedService>();
foreach (var service in scopedServices)
service.Initialize(scopedContext.Services);
}
}
O código a seguir mostra a classe EmbeddedWindowHandler
, que deve ser adicionada ao mesmo projeto de biblioteca do MAUI do .NET que a classe EmbeddedExtensions
:
using Microsoft.Maui.Handlers;
#if ANDROID
using PlatformWindow = Android.App.Activity;
#elif IOS || MACCATALYST
using PlatformWindow = UIKit.UIWindow;
#elif WINDOWS
using PlatformWindow = Microsoft.UI.Xaml.Window;
#endif
namespace Microsoft.Maui.Controls;
internal class EmbeddedWindowHandler : ElementHandler<IWindow, PlatformWindow>, IWindowHandler
{
public static IPropertyMapper<IWindow, IWindowHandler> Mapper =
new PropertyMapper<IWindow, IWindowHandler>(ElementHandler.ElementMapper)
{
};
public static CommandMapper<IWindow, IWindowHandler> CommandMapper =
new CommandMapper<IWindow, IWindowHandler>(ElementHandler.ElementCommandMapper)
{
};
public EmbeddedWindowHandler() : base(Mapper)
{
}
protected override PlatformWindow CreatePlatformElement() =>
MauiContext!.Services.GetRequiredService<PlatformWindow>() ??
throw new InvalidOperationException("EmbeddedWindowHandler could not locate a platform window.");
}
O código a seguir mostra a classe EmbeddedWindowProvider
, que deve ser adicionada ao mesmo projeto de biblioteca do MAUI do .NET que a classe EmbeddedExtensions
:
#if ANDROID
using PlatformWindow = Android.App.Activity;
#elif IOS || MACCATALYST
using PlatformWindow = UIKit.UIWindow;
#elif WINDOWS
using PlatformWindow = Microsoft.UI.Xaml.Window;
#endif
namespace Microsoft.Maui.Controls;
public class EmbeddedWindowProvider
{
WeakReference<PlatformWindow?>? platformWindow;
WeakReference<Window?>? window;
public PlatformWindow? PlatformWindow => Get(platformWindow);
public Window? Window => Get(window);
public void SetWindow(PlatformWindow? platformWindow, Window? window)
{
this.platformWindow = new WeakReference<PlatformWindow?>(platformWindow);
this.window = new WeakReference<Window?>(window);
}
private static T? Get<T>(WeakReference<T?>? weak) where T : class =>
weak is not null && weak.TryGetTarget(out var target) ? target : null;
}
Criar um projeto único do MAUI do .NET
Antes de criar um aplicativo nativo que consome os controles do MAUI do .NET, você deve adicionar um projeto de aplicativo do MAUI do .NET à mesma solução que o projeto de biblioteca de classes do MAUI do .NET criado anteriormente. O projeto de aplicativo do MAUI do .NET armazenará a interface do usuário que você pretende reusar no seu aplicativo nativo inserido. Depois de adicionar um novo projeto de aplicativo do MAUI do .NET à solução, execute as seguintes etapas:
Exclua a pasta Propriedades do projeto.
Exclua a pasta Plataformas do projeto.
Exclua a pasta Recursos/AppIcon do projeto.
Exclua a pasta Recursos/bruto do projeto.
Exclua a pasta Recursos/Splash do projeto.
Exclua a classe
AppShell
do projeto.Verifique se a
App
classe não define aMainPage
propriedade ou substitui oCreateWindow
método:public partial class App : Application { public App() { InitializeComponent(); } }
Exclua a classe
MainPage
do projeto.Modifique o arquivo do projeto para que a propriedade de compilação
$(TargetFramework)
seja definida comonet8.0
, e a propriedade de compilação$(OutputType)
seja removida:<PropertyGroup> <TargetFramework>net8.0</TargetFramework> <RootNamespace>MyMauiApp</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> ... </PropertyGroup>
Importante
Certifique-se de definir a propriedade
$(TargetFramework)
build, não a propriedade$(TargetFrameworks)
build.Modifique o método
CreateMauiApp
na classeMauiProgram
para que ele aceite um argumentoAction<MauiAppBuilder>
opcional que é invocado antes que o método retorne:public static MauiApp CreateMauiApp(Action<MauiAppBuilder>? additional = null) { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); #if DEBUG builder.Logging.AddDebug(); #endif additional?.Invoke(builder); return builder.Build(); }
Neste ponto, você deve adicionar a interface do usuário do MAUI do .NET necessária ao projeto, incluindo dependências e recursos, e garantir que o projeto seja compilado corretamente.
Criar um projeto único do MAUI do .NET
Antes de criar um aplicativo nativo que consome os controles do MAUI do .NET, você deve adicionar um projeto de aplicativo do MAUI do .NET à mesma solução que o projeto de biblioteca de classes do MAUI do .NET criado anteriormente. O projeto de aplicativo do MAUI do .NET armazenará a interface do usuário que você pretende reusar no seu aplicativo nativo inserido. Depois de adicionar um novo projeto de aplicativo do MAUI do .NET à solução, execute as seguintes etapas:
Exclua a pasta Propriedades do projeto.
Exclua a pasta Plataformas do projeto.
Exclua a pasta Recursos/AppIcon do projeto.
Exclua a pasta Recursos/bruto do projeto.
Exclua a pasta Recursos/Splash do projeto.
Exclua a classe
AppShell
do projeto.Verifique se a
App
classe não define aMainPage
propriedade ou substitui oCreateWindow
método:public partial class App : Application { public App() { InitializeComponent(); } }
Exclua a classe
MainPage
do projeto.Modifique o arquivo do projeto para que a propriedade de compilação
$(TargetFramework)
seja definida comonet9.0
, e a propriedade de compilação$(OutputType)
seja removida:<PropertyGroup> <TargetFramework>net9.0</TargetFramework> <RootNamespace>MyMauiApp</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> ... </PropertyGroup>
Importante
Certifique-se de definir a propriedade
$(TargetFramework)
build, não a propriedade$(TargetFrameworks)
build.MauiProgram
Na classe, modifique oCreateMauiApp
método para aceitar umTApp
argumento genérico e aceite um argumento opcionalAction<MauiAppBuilder>
que é invocado antes que o método retorne. Além disso, altere a chamada deUseMauiApp<App>
paraUseMauiEmbeddedApp<TApp>
:public static class MauiProgram { // Create a MauiApp using the specified application. public static MauiApp CreateMauiApp<TApp>(Action<MauiAppBuilder>? additional = null) where TApp : App { var builder = MauiApp.CreateBuilder(); builder .UseMauiEmbeddedApp<TApp>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); #if DEBUG builder.Logging.AddDebug(); #endif additional?.Invoke(builder); return builder.Build(); } }
MauiProgram
Na classe, adicione umaCreateMauiApp
sobrecarga que aceite um argumento opcionalAction<MauiAppBuilder>
:public static class MauiProgram { ... // Create a MauiApp using the default application. public static MauiApp CreateMauiApp(Action<MauiAppBuilder>? additional = null) => CreateMauiApp<App>(additional); }
Em seguida, você deve adicionar a interface do usuário do .NET MAUI necessária ao projeto, incluindo quaisquer dependências e recursos, e garantir que o projeto seja compilado corretamente.
Habilitar o suporte ao MAUI do .NET
Para consumir controles do .NET MAUI que derivam de Element em um aplicativo .NET para Android, .NET para iOS, .NET para Mac Catalyst ou WinUI, adicione seu projeto de aplicativo nativo à mesma solução do projeto de biblioteca de classes .NET MAUI criado anteriormente. Em seguida, você deve habilitar o suporte ao MAUI do .NET no arquivo de projeto do aplicativo nativo definindo as propriedades de compilação $(UseMaui)
e $(MauiEnablePlatformUsings)
para true
no primeiro nó <PropertyGroup>
no arquivo de projeto:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Quanto aos aplicativos .NET para Mac Catalyst, você também precisará definir a propriedade de build $(SupportedOSPlatformVersion)
como, no mínimo, 14.0:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>14.2</SupportedOSPlatformVersion>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Para aplicativos .NET para Mac Catalyst, você também precisará definir a $(SupportedOSPlatformVersion)
propriedade build como um mínimo de 15.0:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
Quanto aos aplicativos WinUI, você também precisará definir a propriedade de compilação $(EnableDefaultXamlItems)
como false
:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
<EnableDefaultXamlItems>false</EnableDefaultXamlItems>
</PropertyGroup>
Isso impedirá que você receba erros de compilação sobre o método InitializeComponent
que já está sendo definido.
Em seguida, adicione os itens de compilação $(PackageReference)
ao arquivo de projeto nos pacotes NuGet Microsoft.Maui.Controls
e Microsoft.Maui.Controls.Compatiblity
:
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
</ItemGroup>
Em seguida, adicione $(PackageReference)
itens de build ao arquivo de projeto para o Microsoft.Maui.Controls
pacote NuGet:
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
</ItemGroup>
Inicializar o MAUI do .NET
O MAUI do .NET deve ser inicializado antes que um projeto de aplicativo nativo possa construir um controle do MAUI do .NET. Escolher quando inicializá-lo depende principalmente de quando ele é mais conveniente no fluxo do aplicativo – ele pode ser executado na inicialização ou pouco antes de um controle do MAUI do .NET ser construído. A abordagem descrita aqui é inicializar o MAUI do .NET quando a interface do usuário inicial do aplicativo é criada.
Normalmente, o padrão para inicializar o MAUI do .NET em um projeto de aplicativo nativo se dá da seguinte forma:
- Crie um objeto MauiApp.
- Crie um objeto MauiContext do objeto MauiApp. O MauiContext objeto será usado para obter uma exibição nativa da exibição MAUI do .NET.
No Android, a substituição OnCreate
na classe MainActivity
normalmente é o local para executar tarefas relacionadas à inicialização do aplicativo. O exemplo de código a seguir mostra o MAUI do .NET sendo inicializado na classe MainActivity
:
namespace MyNativeEmbeddedApp.Droid;
[Activity(Label = "@string/app_name", MainLauncher = true, Theme = "@style/AppTheme")]
public class MainActivity : Activity
{
public static readonly Lazy<MauiApp> MauiApp = new(() =>
{
var mauiApp = MauiProgram.CreateMauiApp(builder =>
{
builder.UseMauiEmbedding();
});
return mauiApp;
});
public static bool UseWindowContext = true;
protected override void OnCreate(Bundle? savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Ensure .NET MAUI app is built before creating .NET MAUI views
var mauiApp = MainActivity.MauiApp.Value;
// Create .NET MAUI context
var context = UseWindowContext
? mauiApp.CreateEmbeddedWindowContext(this) // Create window context
: new MauiContext(mauiApp.Services, this); // Create app context
...
}
}
No iOS e no Mac Catalyst, a classe AppDelegate
deve ser modificada para retornar true
para a substituição FinishedLaunching
:
namespace MyNativeEmbeddedApp.iOS;
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}
O método WillConnect
na classe SceneDelegate
deve então ser modificado para criar seu controlador de visualização principal e defini-lo como a visualização do UINavigationController
:
namespace MyNativeEmbeddedApp.iOS;
[Register("SceneDelegate")]
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
{
[Export("window")]
public UIWindow? Window { get; set; }
[Export("scene:willConnectToSession:options:")]
public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
if (scene is not UIWindowScene windowScene)
return;
Window = new UIWindow(windowScene);
var mainVC = new MainViewController();
var navigationController = new UINavigationController(mainVC);
navigationController.NavigationBar.PrefersLargeTitles = true;
Window.RootViewController = navigationController;
Window.MakeKeyAndVisible();
}
...
}
Em seguida, no editor XML, abra o arquivo Info.plist e adicione o seguinte XML ao final do arquivo:
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
O MAUI do .NET pode ser inicializado no método ViewDidLoad
no seu controlador de exibição principal:
using Microsoft.Maui.Platform;
namespace MyNativeEmbeddedApp.iOS;
public class MainViewController : UIViewController
{
UIWindow GetWindow() =>
View?.Window ??
ParentViewController?.View?.Window ??
MainViewController.MauiApp.Value.Services.GetRequiredService<IUIApplicationDelegate>().GetWindow() ??
UIApplication.SharedApplication.Delegate.GetWindow();
public static readonly Lazy<MauiApp> MauiApp = new(() =>
{
var mauiApp = MauiProgram.CreateMauiApp(builder =>
{
builder.UseMauiEmbedding();
});
return mauiApp;
});
public static bool UseWindowContext = true;
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Ensure app is built before creating .NET MAUI views
var mauiApp = MainViewController.MauiApp.Value;
// Create .NET MAUI context
var context = UseWindowContext
? mauiApp.CreateEmbeddedWindowContext(GetWindow()) // Create window context
: new MauiContext(mauiApp.Services); // Create app context
...
}
}
No Windows, a classe MainWindow
normalmente é o local para executar as tarefas de inicialização de aplicativo relacionadas à interface do usuário:
namespace MyNativeEmbeddedApp.WinUI;
public sealed partial class MainWindow : Microsoft.UI.Xaml.Window
{
public static readonly Lazy<MauiApp> MauiApp = new(() =>
{
var mauiApp = MauiProgram.CreateMauiApp(builder =>
{
builder.UseMauiEmbedding();
});
return mauiApp;
});
public static bool UseWindowContext = true;
public MainWindow()
{
this.InitializeComponent();
// Ensure .NET MAUI app is built before creating .NET MAUI views
var mauiApp = MainWindow.MauiApp.Value;
// Create .NET MAUI context
var context = UseWindowContext
? mauiApp.CreateEmbeddedWindowContext(this) // Create window context
: new MauiContext(mauiApp.Services); // Create app context
...
}
}
Neste exemplo, o objeto MauiApp é criado usando a inicialização lenta. O método de extensão UseMauiEmbedding
é invocado no objeto MauiAppBuilder. Portanto, seu projeto de aplicativo nativo deve incluir uma referência ao projeto de biblioteca de classes do MAUI do .NET que você criou contendo esse método de extensão. Assim, um objeto MauiContext é criado no objeto MauiApp, com um determinando bool
, do local de onde o contexto tem escopo. O objeto MauiContext será usado ao converter controles os MAUI do .NET nos tipos nativos.
A inserção pode ser executada em um contexto de aplicativo ou em um contexto de janela, mas para compatibilidade máxima com o .NET MAUI, ela deve ser executada em um contexto de janela.
Contexto do aplicativo
A inserção nativa pode ser executada em um contexto de aplicativo, em que o aplicativo nativo não tem conhecimento de uma janela. Com essa abordagem, a inicialização de incorporação nativa exige que você:
- Crie um objeto MauiApp.
- Crie um objeto MauiContext do objeto MauiApp. O MauiContext objeto será usado para obter uma exibição nativa da exibição MAUI do .NET.
O exemplo a seguir mostra essa abordagem:
var mauiApp = MauiProgram.CreateMauiApp();
var context = new MauiContext(mauiApp.Services); // Activity also needs passing on Android
Uma exibição .NET MAUI pode ser criada e convertida em uma exibição nativa com o ToPlatformEmbedded
método de extensão, que requer o MauiContext objeto como um argumento.
Essa abordagem é adequada para cenários em que um aplicativo nativo precisa inserir uma interface do usuário simples do .NET MAUI, mas não requer acesso a todos os recursos do .NET MAUI. A desvantagem dessa abordagem é que ferramentas, como recarga dinâmica e alguns recursos do .NET MAUI, não funcionarão.
Dica
Não é recomendável criar um MauiApp objeto sempre que uma exibição .NET MAUI é inserida como uma exibição nativa. Isso pode ser problemático se as exibições inseridas acessarem a Application.Current
propriedade. Em vez disso, o MauiApp objeto pode ser criado como uma instância estática compartilhada:
public static class MyEmbeddedMauiApp
{
static MauiApp? _shared;
public static MauiApp Shared => _shared ??= MauiProgram.CreateMauiApp();
}
Com essa abordagem, você pode instanciar o objeto no início do ciclo de vida do MauiApp aplicativo para evitar um pequeno atraso na primeira vez que inserir uma exibição .NET MAUI em seu aplicativo.
No Android, um fragmento representa uma parte da IU em uma atividade. O exemplo de código a seguir mostra o .NET MAUI sendo inicializado em um fragmento:
using Android.Runtime;
using Android.Views;
using AndroidX.Navigation.Fragment;
using Microsoft.Maui.Controls.Embedding;
using Fragment = AndroidX.Fragment.App.Fragment;
using View = Android.Views.View;
namespace MyNativeEmbeddedApp.Droid;
[Register("com.companyname.nativeembeddingdemo." + nameof(FirstFragment))]
public class FirstFragment : Fragment
{
public override View? OnCreateView(LayoutInflater inflater, ViewGroup? container, Bundle? savedInstanceState) =>
inflater.Inflate(Resource.Layout.fragment_first, container, false);
public override void OnViewCreated(View view, Bundle? savedInstanceState)
{
base.OnViewCreated(view, savedInstanceState);
// Ensure .NET MAUI app is built before creating .NET MAUI views
var mauiApp = MyEmbeddedMauiApp.Shared;
// Create .NET MAUI context
var context = new MauiContext(mauiApp.Services, Activity);
...
}
}
No iOS e no Mac Catalyst, a classe AppDelegate
deve ser modificada para retornar true
para a substituição FinishedLaunching
:
namespace MyNativeEmbeddedApp.iOS;
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}
O método WillConnect
na classe SceneDelegate
deve então ser modificado para criar seu controlador de visualização principal e defini-lo como a visualização do UINavigationController
:
namespace MyNativeEmbeddedApp.iOS;
[Register("SceneDelegate")]
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
{
[Export("window")]
public UIWindow? Window { get; set; }
[Export("scene:willConnectToSession:options:")]
public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
if (scene is not UIWindowScene windowScene)
return;
Window = new UIWindow(windowScene);
var mainVC = new MainViewController();
var navigationController = new UINavigationController(mainVC);
navigationController.NavigationBar.PrefersLargeTitles = true;
Window.RootViewController = navigationController;
Window.MakeKeyAndVisible();
}
...
}
Em seguida, no editor XML, abra o arquivo Info.plist e adicione o seguinte XML ao final do arquivo:
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
O MAUI do .NET pode ser inicializado no método ViewDidLoad
no seu controlador de exibição principal:
using Microsoft.Maui.Controls.Embedding;
namespace MyNativeEmbeddedApp.iOS;
public class MainViewController : UIViewController
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Ensure .NET MAUI app is built before creating .NET MAUI views
var mauiApp = MyEmbeddedMauiApp.Shared;
// Create .NET MAUI context
var context = new MauiContext(mauiApp.Services);
...
}
}
No Windows, a classe MainWindow
normalmente é o local para executar as tarefas de inicialização de aplicativo relacionadas à interface do usuário:
using Microsoft.Maui.Controls.Embedding;
using Microsoft.UI.Xaml;
namespace MyNativeEmbeddedApp.WinUI;
public sealed partial class MainWindow : Microsoft.UI.Xaml.Window
{
public MainWindow()
{
this.InitializeComponent();
}
private async void OnRootLayoutLoaded(object? sender, RoutedEventArgs e)
{
await Task.Yield();
// Ensure .NET MAUI app is built before creating .NET MAUI views
var mauiApp = MyEmbeddedMauiApp.Shared;
// Create .NET MAUI context
var context = new MauiContext(mauiApp.Services);
...
}
}
Neste exemplo, o MauiApp objeto é criado como uma instância estática compartilhada. Quando esse objeto é criado, é chamado que, por sua vez, MauiProgram.CreateMauiApp
chama o UseMauiEmbedding
método de extensão no MauiAppBuilder objeto. Portanto, seu projeto de aplicativo nativo deve incluir uma referência ao projeto de biblioteca de classes .NET MAUI que você criou que contém sua MauiProgram
classe e sua interface do usuário do .NET MAUI. Um MauiContext objeto é então criado a partir do MauiApp objeto, que tem como escopo o MauiApp objeto. O objeto MauiContext será usado ao converter controles os MAUI do .NET nos tipos nativos.
Contexto da janela
A inserção nativa pode ser executada em um contexto de janela, em que o aplicativo nativo tem conhecimento de uma janela. Em alguns cenários, as exibições do .NET MAUI exigem acesso a uma janela para funcionar corretamente. Por exemplo, os gatilhos adaptáveis exigem acesso à janela de uma exibição e, se não houver janela, eles não funcionam.
Com essa abordagem, a inicialização de incorporação nativa exige que você:
- Crie um objeto MauiApp.
- Crie um MauiContext objeto com o
CreateEmbeddedWindowContext
método. O MauiContext objeto será usado para obter uma exibição nativa da exibição MAUI do .NET.
O CreateEmbeddedWindowContext
método cria um contexto de janela que relaciona uma janela nativa a uma janela MAUI do .NET:
var mauiApp = MauiProgram.CreateMauiApp();
var context = mauiApp.CreateEmbeddedWindowContext(this);
Uma exibição .NET MAUI pode ser criada e convertida em uma exibição nativa com o ToPlatformEmbedded
método de extensão, que requer o MauiContext objeto como um argumento.
Observação
O ToPlatformEmbedded
método de extensão tem uma sobrecarga que adiciona uma exibição .NET MAUI a uma janela inserida.
A vantagem dessa abordagem é que há uma única janela .NET MAUI para cada janela nativa, as APIs relacionadas à janela funcionarão corretamente e as ferramentas, como recarga dinâmica, funcionarão corretamente.
Dica
Não é recomendável criar um MauiApp objeto sempre que uma exibição .NET MAUI é inserida como uma exibição nativa. Isso pode ser problemático se as exibições inseridas acessarem a Application.Current
propriedade. Em vez disso, o MauiApp objeto pode ser criado como uma instância estática compartilhada:
public static class MyEmbeddedMauiApp
{
static MauiApp? _shared;
public static MauiApp Shared => _shared ??= MauiProgram.CreateMauiApp();
}
Com essa abordagem, você pode instanciar o objeto no início do ciclo de vida do MauiApp aplicativo para evitar um pequeno atraso na primeira vez que inserir uma exibição .NET MAUI em seu aplicativo.
No Android, um fragmento representa uma parte da IU em uma atividade. O exemplo de código a seguir mostra o .NET MAUI sendo inicializado em um fragmento:
using Android.Runtime;
using Android.Views;
using AndroidX.Navigation.Fragment;
using Microsoft.Maui.Controls.Embedding;
using Fragment = AndroidX.Fragment.App.Fragment;
using View = Android.Views.View;
namespace MyNativeEmbeddedApp.Droid;
[Register("com.companyname.nativeembeddingdemo." + nameof(FirstFragment))]
public class FirstFragment : Fragment
{
Activity? _window;
IMauiContext? _windowContext;
public IMauiContext WindowContext =>
_windowContext ??= MyEmbeddedMauiApp.Shared.CreateEmbeddedWindowContext(_window ?? throw new InvalidOperationException());
public override View? OnCreateView(LayoutInflater inflater, ViewGroup? container, Bundle? savedInstanceState) =>
inflater.Inflate(Resource.Layout.fragment_first, container, false);
public override void OnViewCreated(View view, Bundle? savedInstanceState)
{
base.OnViewCreated(view, savedInstanceState);
_window ??= Activity;
// Create MAUI embedded window context
var context = WindowContext;
...
}
}
No iOS e no Mac Catalyst, a classe AppDelegate
deve ser modificada para retornar true
para a substituição FinishedLaunching
:
namespace MyNativeEmbeddedApp.iOS;
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}
O método WillConnect
na classe SceneDelegate
deve então ser modificado para criar seu controlador de visualização principal e defini-lo como a visualização do UINavigationController
:
namespace MyNativeEmbeddedApp.iOS;
[Register("SceneDelegate")]
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
{
[Export("window")]
public UIWindow? Window { get; set; }
[Export("scene:willConnectToSession:options:")]
public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
if (scene is not UIWindowScene windowScene)
return;
Window = new UIWindow(windowScene);
var mainVC = new MainViewController();
var navigationController = new UINavigationController(mainVC);
navigationController.NavigationBar.PrefersLargeTitles = true;
Window.RootViewController = navigationController;
Window.MakeKeyAndVisible();
}
...
}
Em seguida, no editor XML, abra o arquivo Info.plist e adicione o seguinte XML ao final do arquivo:
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
O MAUI do .NET pode ser inicializado no método ViewDidLoad
no seu controlador de exibição principal:
using Microsoft.Maui.Controls.Embedding;
namespace MyNativeEmbeddedApp.iOS;
public class MainViewController : UIViewController
{
UIKit.UIWindow? _window;
IMauiContext? _windowContext;
public IMauiContext WindowContext =>
_windowContext ??= MyEmbeddedMauiApp.Shared.CreateEmbeddedWindowContext(_window ?? throw new InvalidOperationException());
public override void ViewDidLoad()
{
base.ViewDidLoad();
_window ??= ParentViewController!.View!.Window;
// Create MAUI embedded window context
var context = WindowContext;
...
}
}
No Windows, a classe MainWindow
normalmente é o local para executar as tarefas de inicialização de aplicativo relacionadas à interface do usuário:
using Microsoft.Maui.Controls.Embedding;
using Microsoft.UI.Xaml;
namespace MyNativeEmbeddedApp.WinUI;
public sealed partial class MainWindow : Microsoft.UI.Xaml.Window
{
Microsoft.UI.Xaml.Window? _window;
IMauiContext? _windowContext;
public IMauiContext WindowContext =>
_windowContext ??= MyEmbeddedMauiApp.Shared.CreateEmbeddedWindowContext(_window ?? throw new InvalidOperationException());
public MainWindow()
{
this.InitializeComponent();
_window ??= this;
}
private async void OnRootLayoutLoaded(object? sender, RoutedEventArgs e)
{
await Task.Yield();
// Create MAUI embedded window context
var context = WindowContext;
...
}
}
Neste exemplo, o MauiApp objeto é criado como uma instância estática compartilhada. Quando esse objeto é criado, é chamado que, por sua vez, MauiProgram.CreateMauiApp
chama o UseMauiEmbedding
método de extensão no MauiAppBuilder objeto. Portanto, seu projeto de aplicativo nativo deve incluir uma referência ao projeto de biblioteca de classes .NET MAUI que você criou que contém sua MauiProgram
classe e sua interface do usuário do .NET MAUI. Em seguida, um MauiContext objeto é criado com o CreateEmbeddedWindowContext
método, que tem como escopo a janela. O objeto MauiContext será usado ao converter controles os MAUI do .NET nos tipos nativos.
Consumir os controles do MAUI do .NET
Depois que o MAUI do .NET tiver sido inicializado no seu aplicativo nativo, você poderá adicionar a interface do usuário do MAUI do .NET ao layout do aplicativo nativo. Isso pode ser feito criando uma instância da interface do usuário e convertendo-a no tipo nativo apropriado com o método de extensão ToPlatformEmbedded
.
No Android, o método de extensão ToPlatformEmbedded
converte o controle do MAUI do .NET em um objeto Android View:
var mauiView = new MyMauiContent();
Android.Views.View nativeView = mauiView.ToPlatformEmbedded(context);
Neste exemplo, um objeto derivado de ContentView é convertido em um objeto Android View.
Observação
O método de extensão ToPlatformEmbedded
se localiza na biblioteca de classes do MAUI do .NET que você criou anteriormente. Por isso, seu projeto de aplicativo nativo deve incluir uma referência a esse projeto.
Observação
O ToPlatformEmbedded
método de extensão está no Microsoft.Maui.Controls.Embedding namespace. Portanto, seu projeto de aplicativo nativo deve incluir uma using
instrução para esse namespace.
O objeto View pode ser adicionado a um layout no seu aplicativo nativo:
rootLayout.AddView(nativeView, new LinearLayout.LayoutParams(MatchParent, WrapContent));
No iOS e no Mac Catalyst, o método de extensão ToPlatformEmbedded
converte o controle do MAUI do .NET em um objeto UIView:
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(context);
nativeView.WidthAnchor.ConstraintEqualTo(View.Frame.Width).Active = true;
nativeView.HeightAnchor.ConstraintEqualTo(500).Active = true;
Nesse exemplo, um objeto derivado de ContentView-é convertido em um objeto UIView e, em seguida, restrições de largura e altura são definidas nele para permitir a interação.
Observação
O método de extensão ToPlatformEmbedded
se localiza na biblioteca de classes do MAUI do .NET que você criou anteriormente. Por isso, seu projeto de aplicativo nativo deve incluir uma referência a esse projeto.
O objeto UIView pode ser adicionado a uma exibição no controlador de exibição:
stackView.AddArrangedSubView(nativeView);
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(context);
Neste exemplo, um objeto derivado de ContentView é convertido em um objeto UIView.
Observação
O ToPlatformEmbedded
método de extensão está no Microsoft.Maui.Controls.Embedding namespace. Portanto, seu projeto de aplicativo nativo deve incluir uma using
instrução para esse namespace.
O objeto UIView pode ser adicionado a uma exibição no controlador de exibição:
stackView.AddArrangedSubView(new ContainerView(nativeView));
ContainerView
é um tipo personalizado que encapsula a exibição MAUI do .NET para garantir que ela seja dimensionada corretamente. Isso é feito redirecionando IntrinsicContentSize
para a exibição .NET MAUI:SizeThatFits
class ContainerView : UIView
{
public ContainerView(UIView view)
{
AddSubview(view);
}
public override CGSize IntrinsicContentSize =>
SizeThatFits(new CGSize(nfloat.MaxValue, nfloat.MaxValue));
public override CGSize SizeThatFits(CGSize size) =>
Subviews?.FirstOrDefault()?.SizeThatFits(size) ?? CGSize.Empty;
public override void LayoutSubviews()
{
if (Subviews?.FirstOrDefault() is { } view)
view.Frame = Bounds;
}
public override void SetNeedsLayout()
{
base.SetNeedsLayout();
InvalidateIntrinsicContentSize();
}
}
Além disso, um ToUIViewController
método de extensão no .NET MAUI pode ser usado para converter uma página .NET MAUI em um UIViewController:
MyMauiPage myMauiPage = new MyMauiPage();
UIViewController myPageController = myMauiPage.ToUIViewController(context);
Neste exemplo, um objeto derivado de ContentPage é convertido em um UIViewController.
No Windows, o método de extensão ToPlatformEmbedded
converte o controle do MAUI do .NET em um objeto FrameworkElement:
var mauiView = new MyMauiContent();
FrameworkElement nativeView = myMauiPage.ToPlatformEmbedded(context);
Neste exemplo, um objeto derivado de ContentView é convertido em um objeto FrameworkElement. O objeto FrameworkElement pode ser definido como o conteúdo de uma página WinUI.
Observação
O método de extensão ToPlatformEmbedded
se localiza na biblioteca de classes do MAUI do .NET que você criou anteriormente. Por isso, seu projeto de aplicativo nativo deve incluir uma referência a esse projeto.
Observação
O ToPlatformEmbedded
método de extensão está no Microsoft.Maui.Controls.Embedding namespace. Portanto, seu projeto de aplicativo nativo deve incluir uma using
instrução para esse namespace.
O objeto FrameworkElement pode ser adicionado a um layout no seu aplicativo nativo:
stackPanel.Children.Add(nativeView);
Importante
Para evitar que ocorra um erro, o recarregamento dinâmico XAML deve ser desabilitado antes de executar um aplicativo nativo inserido na configuração de depuração.
Suporte à Recarga Dinâmica de XAML
Não há suporte para a Recarga Dinâmica de XAML em aplicativos nativos inseridos. No entanto, você ainda pode usar a Recarga Dinâmica de XAML para iterar rapidamente sobre sua interface do usuário .NET MAUI, criando um aplicativo .NET MAUI que consuma a interface do usuário .NET MAUI.
Para exibir a interface do usuário .NET MAUI com Recarga Dinâmica de XAML:
No projeto que contém sua interface do usuário .NET MAUI, atualize a classe
MauiProgram
para adicionar um método de sobrecargaCreateMauiApp
e modifique o métodoCreateMauiApp
existente para aceitar um argumento genérico:public static class MauiProgram { public static MauiApp CreateMauiApp(Action<MauiAppBuilder>? additional = null) => CreateMauiApp<App>(additional); public static MauiApp CreateMauiApp<TApp>(Action<MauiAppBuilder>? additional = null) where TApp : App { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<TApp>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }); #if DEBUG builder.Logging.AddDebug(); #endif additional?.Invoke(builder); return builder.Build(); } }
No projeto que contém sua interface do usuário .NET MAUI, converta cada dicionário de recursos de um arquivo XAML independente para um dicionário de recursos que seja apoiado por um arquivo de código por trás.
No projeto que contém sua interface do usuário .NET MAUI, atualize a instância do seu dicionário de recursos, geralmente em App.xaml, para que a propriedade
Source
também especifique o assembly que contém o dicionário de recursos:<ResourceDictionary Source="Resources/Styles/Colors.xaml;assembly=NativeEmbeddingDemo" /> <ResourceDictionary Source="Resources/Styles/Styles.xaml;assembly=NativeEmbeddingDemo" />
Crie um novo aplicativo .NET MAUI e adicione-o à solução que contém seu projeto de interface do usuário .NET MAUI e aplicativos nativos inseridos.
No projeto do seu aplicativo .NET MAUI, adicione uma referência ao projeto que contém sua interface do usuário .NET MAUI.
No projeto do seu aplicativo .NET MAUI, exclua quaisquer pastas filhas Resource onde o recurso é fornecido pelo projeto da sua interface do usuário .NET MAUI. Por exemplo, se o projeto da interface do usuário .NET MAUI contém as pastas Resources > Fonts, Resources > Images e Resources > Styles, essas pastas devem ser excluídas do aplicativo .NET MAUI que você acabou de criar. Isso permite que seu aplicativo .NET MAUI consuma os recursos do projeto que contém sua interface do usuário .NET MAUI.
No seu aplicativo .NET MAUI, atualize a classe
App
para que ela herde da classeApp
no seu projeto de interface do usuário .NET MAUI:<myMauiUIProject:App xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:myMauiUIProject="clr-namespace:NativeEmbeddingDemo;assembly=NativeEmbeddingDemo" x:Class="TestHarnessApp.TestApp"> <myMauiUIProject:App.Resources> <!-- App specific resources go here --> </myMauiUIProject:App.Resources> </myMauiUIProject:App>
Em seguida, atualize o arquivo de código por trás da classe
App
para que ele herde da classeApp
no seu projeto de interface do usuário .NET MAUI e carregue quaisquer recursos XAML deste projeto:public partial class TestApp : myMauiUIProject.App { public TestApp() { var baseResources = Resources; InitializeComponent(); Resources.MergedDictionaries.Add(baseResources); MainPage = new HostPage(); } }
No seu aplicativo .NET MAUI, adicione uma página que exiba a interface do usuário do projeto que contém sua interface do usuário .NET MAUI:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:myMauiUIProject="clr-namespace:NativeEmbeddingDemo;assembly=NativeEmbeddingDemo" x:Class="TestHarnessApp.HostPage" Title="HostPage"> <myMauiUIProject:MyMauiContent /> </ContentPage>
No seu aplicativo .NET MAUI, atualize a classe
MauiProgram
para chamar o métodoCreateMauiApp
no projeto que contém sua interface do usuário .NET MAUI:public static class MauiProgram { public static MauiApp CreateMauiApp() => NativeEmbeddingDemo.MauiProgram.CreateMauiApp<TestApp>(builder => { // Add any test harness configuration such as service stubs or mocks. }); }
Agora você deve ser capaz de executar o projeto do seu aplicativo .NET MAUI em cada plataforma e usar a Recarga Dinâmica de XAML para iterar sobre a sua interface do usuário .NET MAUI.
Para obter um exemplo dessa abordagem, consulte o aplicativo de exemplo.