diff --git a/samples/MauiEmbedding/MauiEmbedding/App.cs b/samples/MauiEmbedding/MauiEmbedding/App.cs index f6af65142..bb72fd203 100644 --- a/samples/MauiEmbedding/MauiEmbedding/App.cs +++ b/samples/MauiEmbedding/MauiEmbedding/App.cs @@ -1,9 +1,8 @@ using MauiEmbedding.MauiControls; -using Uno.Extensions.Maui.Platform; namespace MauiEmbedding; -public class App : EmbeddingApplication +public class App : Application { protected Window? MainWindow { get; private set; } protected IHost? Host { get; private set; } diff --git a/src/Uno.Extensions.Maui.UI/MauiEmbedding.android.cs b/src/Uno.Extensions.Maui.UI/MauiEmbedding.android.cs index 89cb4ab99..b9f5335cf 100644 --- a/src/Uno.Extensions.Maui.UI/MauiEmbedding.android.cs +++ b/src/Uno.Extensions.Maui.UI/MauiEmbedding.android.cs @@ -34,15 +34,10 @@ partial class MauiEmbedding rootContext.InitializeScopedServices(); var iApp = mauiApp.Services.GetRequiredService(); - if(app is not EmbeddingApplication embeddingApp) - { - throw new MauiEmbeddingException(Properties.Resources.TheApplicationMustInheritFromEmbeddingApplication); - } - - embeddingApp.InitializeApplication(scope.ServiceProvider, iApp); - - // Initializing with the Activity to set the current activity. - // The Bundle is not actually used by Maui + _ = new EmbeddedApplication(mauiApp.Services, iApp); + + // Initializing with the Activity to set the current activity. + // The Bundle is not actually used by Maui Microsoft.Maui.ApplicationModel.Platform.Init(activity, null); androidApp.SetApplicationHandler(iApp, rootContext); diff --git a/src/Uno.Extensions.Maui.UI/MauiEmbedding.apple.cs b/src/Uno.Extensions.Maui.UI/MauiEmbedding.apple.cs index 03dbf5c5f..733728613 100644 --- a/src/Uno.Extensions.Maui.UI/MauiEmbedding.apple.cs +++ b/src/Uno.Extensions.Maui.UI/MauiEmbedding.apple.cs @@ -34,13 +34,9 @@ partial class MauiEmbedding rootContext.InitializeScopedServices(); var iApp = mauiApp.Services.GetRequiredService(); - if (app is not EmbeddingApplication embeddingApp) - { - throw new MauiEmbeddingException(Properties.Resources.TheApplicationMustInheritFromEmbeddingApplication); - } Microsoft.Maui.ApplicationModel.Platform.Init(() => mauiApp.Services.GetRequiredService().RootViewController!); - embeddingApp.InitializeApplication(mauiApp.Services, iApp); + _ = new EmbeddedApplication(mauiApp.Services, iApp); app.SetApplicationHandler(iApp, rootContext); InitializeApplicationMainPage(iApp); } diff --git a/src/Uno.Extensions.Maui.UI/MauiEmbedding.cs b/src/Uno.Extensions.Maui.UI/MauiEmbedding.cs index cb6e4b7e5..7c5f9e1a7 100644 --- a/src/Uno.Extensions.Maui.UI/MauiEmbedding.cs +++ b/src/Uno.Extensions.Maui.UI/MauiEmbedding.cs @@ -1,169 +1,185 @@ -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Maui.ApplicationModel; -using Uno.Extensions.Hosting; - -namespace Uno.Extensions.Maui; - -/// -/// Embedding support for Microsoft.Maui controls in Uno Platform app hosts. -/// -public static partial class MauiEmbedding -{ - /// - /// Registers Maui embedding in the Uno Platform app builder. - /// - /// The updated app builder. - /// The IHost builder. - /// Optional lambda to configure the Maui app builder. - public static IApplicationBuilder UseMauiEmbedding(this IApplicationBuilder builder, Action? configure = null) - where TApp : MauiApplication - => builder.Configure(hostBuilder => hostBuilder.UseMauiEmbedding(builder.App, builder.Window, configure)); - - /// - /// Registers Maui embedding in the Uno Platform app builder. - /// - /// The updated app builder. - /// The IHost builder. - /// The Uno app. - /// The Main Application Window. - /// Optional lambda to configure the Maui app builder. - public static IHostBuilder UseMauiEmbedding(this IHostBuilder builder, Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action? configure = null) - where TApp : MauiApplication - { -#if MAUI_EMBEDDING - var mauiAppBuilder = ConfigureMauiAppBuilder(app, window, configure); - builder.UseServiceProviderFactory(new UnoServiceProviderFactory(mauiAppBuilder, () => BuildMauiApp(mauiAppBuilder, app, window))); -#endif - return builder; - } - - /// - /// Registers Maui embedding with WinUI3 and WPF application builder. - /// - /// The Uno app. - /// The Main Application Window. - /// Optional lambda to configure the Maui app builder. - public static MauiApp UseMauiEmbedding(this Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action? configure = null) - where TApp : MauiApplication - { -#if MAUI_EMBEDDING - var mauiAppBuilder = ConfigureMauiAppBuilder(app, window, configure); - return BuildMauiApp(mauiAppBuilder, app, window); -#else - return default!; -#endif - } - -#if MAUI_EMBEDDING - - private static MauiAppBuilder ConfigureMauiAppBuilder(Application app, Microsoft.UI.Xaml.Window window, Action? configure) - where TApp : MauiApplication - { - var mauiAppBuilder = MauiApp.CreateBuilder() - .UseMauiEmbedding() - .RegisterPlatformServices(app); - - mauiAppBuilder.Services.AddSingleton(app) - .AddSingleton(window) - .AddSingleton(); - - // HACK: https://github.com/dotnet/maui/pull/16758 - mauiAppBuilder.Services.RemoveAll() - .AddSingleton(); - - configure?.Invoke(mauiAppBuilder); - - return mauiAppBuilder; - } - - private static MauiApp BuildMauiApp(MauiAppBuilder builder, Application app, Microsoft.UI.Xaml.Window window) - { - var mauiApp = builder.Build(); - mauiApp.InitializeMauiEmbeddingApp(app); - -#if WINDOWS - window.Activated += (s, args) => - { - WindowStateManager.Default.OnActivated(window, args); - }; -#endif - return mauiApp; - } - - private static void InitializeScopedServices(this IMauiContext scopedContext) - { - var scopedServices = scopedContext.Services.GetServices(); - - foreach (var service in scopedServices) - { - service.Initialize(scopedContext.Services); - } - } - - private static void InitializeApplicationMainPage(IApplication iApp) - { - if (iApp is not MauiApplication app || app.Handler?.MauiContext is null) - { - // NOTE: This method is supposed to be called immediately after we initialize the Application Handler - // This should never actually happen but is required due to nullability - return; - } - -#if ANDROID - var services = app.Handler.MauiContext.Services; - var context = new MauiContext(services, services.GetRequiredService()); -#else - var context = app.Handler.MauiContext; -#endif - - // Create an Application Main Page and initialize a Handler with the Maui Context - var page = new ContentPage(); - app.MainPage = page; - _ = page.ToPlatform(context); - - // Create a Maui Window and initialize a Handler shim. This will expose the actual Application Window - var virtualWindow = new Microsoft.Maui.Controls.Window(); - virtualWindow.Handler = new EmbeddedWindowHandler - { -#if IOS || MACCATALYST - PlatformView = context.Services.GetRequiredService(), -#elif ANDROID - PlatformView = context.Services.GetRequiredService(), -#elif WINDOWS - PlatformView = context.Services.GetRequiredService(), -#endif - VirtualView = virtualWindow, - MauiContext = context - }; - virtualWindow.Page = page; - - app.SetCoreWindow(virtualWindow); - } - - private static void SetCoreWindow(this IApplication app, Microsoft.Maui.Controls.Window window) - { - if (app.Windows is List windows) - { - windows.Add(window); - } - } - -#endif - - // NOTE: This was part of the POC and is out of scope for the MVP. Keeping it in case we want to add it back later. - /* - public static MauiAppBuilder MapControl(this MauiAppBuilder builder) - where TWinUI : FrameworkElement - where TMaui : Microsoft.Maui.Controls.View - { - Interop.MauiInterop.MapControl(); - return builder; - } - public static MauiAppBuilder MapStyleHandler(this MauiAppBuilder builder) - where THandler : Interop.IWinUIToMauiStyleHandler, new() - { - Interop.MauiInterop.MapStyleHandler(); - return builder; - } - */ -} +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Maui.ApplicationModel; +using Uno.Extensions.Hosting; + +namespace Uno.Extensions.Maui; + +/// +/// Embedding support for Microsoft.Maui controls in Uno Platform app hosts. +/// +public static partial class MauiEmbedding +{ + /// + /// Registers Maui embedding in the Uno Platform app builder. + /// + /// The updated app builder. + /// The IHost builder. + /// Optional lambda to configure the Maui app builder. + public static IApplicationBuilder UseMauiEmbedding(this IApplicationBuilder builder, Action? configure = null) + where TApp : MauiApplication + => builder.Configure(hostBuilder => hostBuilder.UseMauiEmbedding(builder.App, builder.Window, configure)); + + /// + /// Registers Maui embedding in the Uno Platform app builder. + /// + /// The updated app builder. + /// The IHost builder. + /// The Uno app. + /// The Main Application Window. + /// Optional lambda to configure the Maui app builder. + public static IHostBuilder UseMauiEmbedding(this IHostBuilder builder, Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action? configure = null) + where TApp : MauiApplication + { +#if MAUI_EMBEDDING + var mauiAppBuilder = ConfigureMauiAppBuilder(app, window, configure); + builder.UseServiceProviderFactory(new UnoServiceProviderFactory(mauiAppBuilder, () => BuildMauiApp(mauiAppBuilder, app, window))); +#endif + return builder; + } + + /// + /// Registers Maui embedding with WinUI3 and WPF application builder. + /// + /// The Uno app. + /// The Main Application Window. + /// Optional lambda to configure the Maui app builder. + public static MauiApp UseMauiEmbedding(this Microsoft.UI.Xaml.Application app, Microsoft.UI.Xaml.Window window, Action? configure = null) + where TApp : MauiApplication + { +#if MAUI_EMBEDDING + var mauiAppBuilder = ConfigureMauiAppBuilder(app, window, configure); + return BuildMauiApp(mauiAppBuilder, app, window); +#else + return default!; +#endif + } + +#if MAUI_EMBEDDING + + private static MauiAppBuilder ConfigureMauiAppBuilder(Application app, Microsoft.UI.Xaml.Window window, Action? configure) + where TApp : MauiApplication + { + // Forcing hot reload to false to prevent exceptions being raised + Microsoft.Maui.HotReload.MauiHotReloadHelper.IsEnabled = false; + + var mauiAppBuilder = MauiApp.CreateBuilder() + .UseMauiEmbedding() + .RegisterPlatformServices(app); + + mauiAppBuilder.Services.AddSingleton(app) + .AddSingleton(window) + .AddSingleton(); + + // HACK: https://github.com/dotnet/maui/pull/16758 + mauiAppBuilder.Services.RemoveAll() + .AddSingleton(); + + configure?.Invoke(mauiAppBuilder); + + return mauiAppBuilder; + } + + private static MauiApp BuildMauiApp(MauiAppBuilder builder, Application app, Microsoft.UI.Xaml.Window window) + { + var mauiApp = builder.Build(); + mauiApp.InitializeMauiEmbeddingApp(app); + +#if WINDOWS + window.Activated += (s, args) => + { + WindowStateManager.Default.OnActivated(window, args); + }; +#endif + return mauiApp; + } + + private static void InitializeScopedServices(this IMauiContext scopedContext) + { + var scopedServices = scopedContext.Services.GetServices(); + + foreach (var service in scopedServices) + { + service.Initialize(scopedContext.Services); + } + } + + private static void InitializeApplicationMainPage(IApplication iApp) + { + if (iApp is not MauiApplication app || app.Handler?.MauiContext is null) + { + // NOTE: This method is supposed to be called immediately after we initialize the Application Handler + // This should never actually happen but is required due to nullability + return; + } + +#if ANDROID + var services = app.Handler.MauiContext.Services; + var context = new MauiContext(services, services.GetRequiredService()); +#else + var context = app.Handler.MauiContext; +#endif + + // Create an Application Main Page and initialize a Handler with the Maui Context + var page = new ContentPage(); + app.MainPage = page; + _ = page.ToPlatform(context); + + // Create a Maui Window and initialize a Handler shim. This will expose the actual Application Window + var virtualWindow = new Microsoft.Maui.Controls.Window(); + virtualWindow.Handler = new EmbeddedWindowHandler + { +#if IOS || MACCATALYST + PlatformView = context.Services.GetRequiredService(), +#elif ANDROID + PlatformView = context.Services.GetRequiredService(), +#elif WINDOWS + PlatformView = context.Services.GetRequiredService(), +#endif + VirtualView = virtualWindow, + MauiContext = context + }; + virtualWindow.Page = page; + + app.SetCoreWindow(virtualWindow); + } + + private static void SetCoreWindow(this IApplication app, Microsoft.Maui.Controls.Window window) + { + if (app.Windows is List windows) + { + windows.Add(window); + } + } + +#endif + + internal record EmbeddedApplication : IPlatformApplication + { + public EmbeddedApplication(IServiceProvider services, IApplication application) + { + Services = services; + Application = application; + IPlatformApplication.Current = this; + } + + public IServiceProvider Services { get; } + public IApplication Application { get; } + } + + // NOTE: This was part of the POC and is out of scope for the MVP. Keeping it in case we want to add it back later. + /* + public static MauiAppBuilder MapControl(this MauiAppBuilder builder) + where TWinUI : FrameworkElement + where TMaui : Microsoft.Maui.Controls.View + { + Interop.MauiInterop.MapControl(); + return builder; + } + public static MauiAppBuilder MapStyleHandler(this MauiAppBuilder builder) + where THandler : Interop.IWinUIToMauiStyleHandler, new() + { + Interop.MauiInterop.MapStyleHandler(); + return builder; + } + */ +} diff --git a/src/Uno.Extensions.Maui.UI/MauiEmbedding.windows.cs b/src/Uno.Extensions.Maui.UI/MauiEmbedding.windows.cs index 14858447f..236778d34 100644 --- a/src/Uno.Extensions.Maui.UI/MauiEmbedding.windows.cs +++ b/src/Uno.Extensions.Maui.UI/MauiEmbedding.windows.cs @@ -1,6 +1,4 @@ -using Uno.Extensions.Maui.Platform; - -namespace Uno.Extensions.Maui; +namespace Uno.Extensions.Maui; partial class MauiEmbedding { @@ -26,12 +24,7 @@ partial class MauiEmbedding rootContext.InitializeScopedServices(); var iApp = mauiApp.Services.GetRequiredService(); - if (app is not EmbeddingApplication embeddingApp) - { - throw new MauiEmbeddingException(Properties.Resources.TheApplicationMustInheritFromEmbeddingApplication); - } - - embeddingApp.InitializeApplication(mauiApp.Services, iApp); + _ = new EmbeddedApplication(mauiApp.Services, iApp); app.SetApplicationHandler(iApp, rootContext); InitializeApplicationMainPage(iApp); } diff --git a/src/Uno.Extensions.Maui.UI/MauiHost.cs b/src/Uno.Extensions.Maui.UI/MauiHost.cs index 32750997e..76a051c4e 100644 --- a/src/Uno.Extensions.Maui.UI/MauiHost.cs +++ b/src/Uno.Extensions.Maui.UI/MauiHost.cs @@ -23,11 +23,7 @@ public partial class MauiHost : ContentControl if (IPlatformApplication.Current?.Application is null && MauiApplication.Current?.Handler.MauiContext is not null) { - if (Application.Current is not EmbeddingApplication embeddingApp) - { - throw new MauiEmbeddingInitializationException(); - } - embeddingApp.InitializeApplication(MauiApplication.Current.Handler.MauiContext.Services, MauiApplication.Current); + _ = new MauiEmbedding.EmbeddedApplication(MauiApplication.Current.Handler.MauiContext.Services, MauiApplication.Current); } if (args.NewValue is null || diff --git a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.android.cs b/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.android.cs deleted file mode 100644 index 481818eae..000000000 --- a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.android.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace Uno.Extensions.Maui.Platform; - -/// -/// Provides a base Application class for Maui Embedding -/// -public partial class EmbeddingApplication : Application, IPlatformApplication -{ - private IServiceProvider _serviceProvider = default!; - private IApplication _application = default!; - - IServiceProvider IPlatformApplication.Services => _serviceProvider; - IApplication IPlatformApplication.Application => _application; - - internal void InitializeApplication(IServiceProvider services, IApplication application) - { - _serviceProvider = services; - _application = application; - - // Hack: This is a workaround for https://github.com/dotnet/maui/pull/16803 - HackMauiApplication.Initialize(services, application); - IPlatformApplication.Current = this; - } - - private class HackMauiApplication : Microsoft.Maui.MauiApplication - { - private HackMauiApplication(IServiceProvider services, IApplication application) - : base(0, default) - { - // TODO: Adjust code to remove this warning (https://github.com/unoplatform/uno.extensions/issues/2142) -#pragma warning disable CS0618 // Type or member is obsolete - Services = services; - Application = application; -#pragma warning restore CS0618 // Type or member is obsolete - } - - protected override MauiApp CreateMauiApp() => throw new NotImplementedException(); - - public override void OnCreate() { } - - public static HackMauiApplication Initialize(IServiceProvider services, IApplication application) => - new (services, application); - } -} diff --git a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.apple.cs b/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.apple.cs deleted file mode 100644 index 9180e28e8..000000000 --- a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.apple.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Foundation; -using UIKit; - -namespace Uno.Extensions.Maui.Platform; - -/// -/// Provides a base Application class for Maui Embedding -/// -public partial class EmbeddingApplication : Application, IPlatformApplication -{ - private IServiceProvider _serviceProvider = default!; - private IApplication _application = default!; - - IServiceProvider IPlatformApplication.Services => _serviceProvider; - IApplication IPlatformApplication.Application => _application; - - internal void InitializeApplication(IServiceProvider services, IApplication application) - { - _serviceProvider = services; - _application = application; - - // Hack: This is a workaround for https://github.com/dotnet/maui/pull/16803 - HackMauiUIApplicationDelegate.Initialize(services, application); - IPlatformApplication.Current = this; - } - - private class HackMauiUIApplicationDelegate : MauiUIApplicationDelegate - { - private HackMauiUIApplicationDelegate(IServiceProvider services, IApplication application) - { - // TODO: Adjust code to remove this warning (https://github.com/unoplatform/uno.extensions/issues/2142) -#pragma warning disable CS0618 // Type or member is obsolete - Services = services; - Application = application; -#pragma warning restore CS0618 // Type or member is obsolete - - } - - public static HackMauiUIApplicationDelegate Initialize(IServiceProvider services, IApplication application) => - new(services, application); - protected override MauiApp CreateMauiApp() => throw new NotImplementedException(); - - public override bool WillFinishLaunching(UIApplication application, NSDictionary launchOptions) => true; - - public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true; - } -} diff --git a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.cs b/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.cs index 15f65b0b4..3753d4e7a 100644 --- a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.cs +++ b/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.cs @@ -1,13 +1,10 @@ -namespace Uno.Extensions.Maui.Platform; - +namespace Uno.Extensions.Maui.Platform; + /// /// Provides a base Application class for Maui Embedding /// -public partial class EmbeddingApplication +[Obsolete("The EmbeddingApplication is obsolete in .NET 8. Please use Microsoft.UI.Xaml.Application", error: true)] +public partial class EmbeddingApplication : Application { - static EmbeddingApplication() - { - // Forcing hot reload to false to prevent exceptions being raised - Microsoft.Maui.HotReload.MauiHotReloadHelper.IsEnabled = false; - } + } diff --git a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.standard.cs b/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.standard.cs deleted file mode 100644 index e30784d19..000000000 --- a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.standard.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Uno.Extensions.Maui.Platform; - -/// -/// Provides a base Application class for Maui Embedding -/// -public partial class EmbeddingApplication : Application -{ -} diff --git a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.windows.cs b/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.windows.cs deleted file mode 100644 index f82c952db..000000000 --- a/src/Uno.Extensions.Maui.UI/Platform/EmbeddingApplication.windows.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Uno.Extensions.Maui.Platform; - -/// -/// Provides a base Application class for Maui Embedding -/// -public partial class EmbeddingApplication : MauiWinUIApplication -{ - /// - protected sealed override MauiApp CreateMauiApp() => throw new NotImplementedException(); - - /// - protected override void OnLaunched(LaunchActivatedEventArgs args) { } - - internal void InitializeApplication(IServiceProvider services, IApplication application) - { - Services = services; - Application = application; - IPlatformApplication.Current = this; - } -} diff --git a/src/Uno.Extensions.Maui.WinUI.Markup/MauiHostMarkupExtensions.cs b/src/Uno.Extensions.Maui.WinUI.Markup/MauiHostMarkupExtensions.cs index f7f144e33..9a7683690 100644 --- a/src/Uno.Extensions.Maui.WinUI.Markup/MauiHostMarkupExtensions.cs +++ b/src/Uno.Extensions.Maui.WinUI.Markup/MauiHostMarkupExtensions.cs @@ -1,8 +1,8 @@ using System.Runtime.CompilerServices; -using Uno.Extensions.Markup.Internals; +using Uno.Extensions.Markup.Internals; + +namespace Uno.Extensions.Maui; -namespace Uno.Extensions.Maui; - public static class MauiHostMarkupExtensions { [MarkupExtension]