ネイティブ埋め込み
通常、.NET Multi-platform App UI (.NET MAUI) アプリには、Grid などのレイアウトを含むページや、Button などのビューを含むレイアウトが含まれます。 ページ、レイアウト、ビューはすべて、Element から派生します。 ネイティブ埋め込みを使用すると、.NET for Android、.NET for iOS、.NET for Mac Catalyst、WinUI ネイティブ アプリで Element から派生するすべての .NET MAUI コントロールを使用できます。
ネイティブ アプリで .NET MAUI コントロールを使用するプロセスは次のとおりです。
- ネイティブ埋め込みアプリをブートストラップする拡張メソッドを作成します。 詳細については、「拡張メソッドの作成」を参照してください。
- .NET MAUI UI と依存関係を含む .NET MAUI 単一プロジェクトを作成します。 詳細については、「.NET MAUI 単一プロジェクトの作成」を参照してください。
- ネイティブ アプリを作成し、その中で .NET MAUI のサポートを有効にします。 詳細については、「.NET MAUI のサポート を有効にする」を参照してください。
- ネイティブ アプリ プロジェクトで .NET MAUI を初期化します。 詳細については、「.NET MAUI の初期化」を参照してください。
- .NET MAUI UI を作成し、
ToPlatformEmbedding
拡張メソッドを使用して適切なネイティブ型に変換します。 詳細については、「.NET MAUI コントロール の使用」を参照してください。
- .NET MAUI UI と依存関係を含む .NET MAUI 単一プロジェクトを作成します。 詳細については、「.NET MAUI 単一プロジェクトの作成」を参照してください。
- ネイティブ アプリを作成し、その中で .NET MAUI のサポートを有効にします。 詳細については、「.NET MAUI のサポート を有効にする」を参照してください。
- ネイティブ アプリ プロジェクトで .NET MAUI を初期化します。 詳細については、「.NET MAUI の初期化」を参照してください。
- .NET MAUI UI を作成し、
ToPlatformEmbedding
拡張メソッドを使用して適切なネイティブ型に変換します。 詳細については、「.NET MAUI コントロール の使用」を参照してください。
Note
ネイティブ埋め込みを使用しても、.NET MAUI のデータ バインディング エンジンは引き続き機能します。 ただし、ページ ナビゲーションはネイティブ ナビゲーション API を使用して実行する必要があります。
拡張メソッドを作成する
.NET MAUI コントロールを使用するネイティブ アプリを作成する前に、まず .NET MAUI クラス ライブラリ プロジェクトを作成し、Platforms フォルダーとその Class1
クラスを削除する必要があります。 次に、次のコードを含む EmbeddedExtensions
という名前のクラスをそれに追加します:
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>();
}
}
これらの拡張メソッドは Microsoft.Maui.Controls
名前空間内にあり、各プラットフォームでネイティブ埋め込みアプリをブートストラップするために使用されます。 拡張メソッドは、.NET MAUI ライブラリ プロジェクトにも追加する必要のある EmbeddedPlatformApplication
、EmbeddedWindowHandler
、EmbeddedWindowProvider
型を参照します。
次のコードは、EmbeddedPlatformApplication
クラスを示しています。このクラスは、EmbeddedExtensions
クラスと同じ .NET MAUI ライブラリ プロジェクトに追加する必要があります:
#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);
}
}
次のコードは、EmbeddedWindowHandler
クラスを示しています。このクラスは、EmbeddedExtensions
クラスと同じ .NET MAUI ライブラリ プロジェクトに追加する必要があります:
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.");
}
次のコードは、EmbeddedWindowProvider
クラスを示しています。このクラスは、EmbeddedExtensions
クラスと同じ .NET MAUI ライブラリ プロジェクトに追加する必要があります:
#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;
}
.NET MAUI 単一プロジェクトの作成
.NET MAUI コントロールを使用するネイティブ アプリを作成する前に、以前に作成した .NET MAUI クラス ライブラリ プロジェクトと同じソリューションに .NET MAUI アプリ プロジェクトを追加する必要があります。 .NET MAUI アプリ プロジェクトには、ネイティブ埋め込みアプリで再利用する予定の UI が格納されます。 ソリューションに新しい .NET MAUI アプリ プロジェクトを追加した後、次の手順を実行します:
プロジェクトから [プロパティ] フォルダーを削除します。
Platforms フォルダーをプロジェクトから削除します。
プロジェクトから Resources/AppIcon フォルダーを削除します。
プロジェクトから Resources/raw フォルダーを削除します。
プロジェクトから Resources/Splash フォルダーを削除します。
プロジェクトから
AppShell
クラスを削除します。App
クラスがMainPage
プロパティを設定したり、CreateWindow
メソッドをオーバーライドしたりしていないことを確認します。public partial class App : Application { public App() { InitializeComponent(); } }
プロジェクトから
MainPage
クラスを削除します。プロジェクト ファイルを変更して、
$(TargetFramework)
ビルド プロパティがnet8.0
に設定され、$(OutputType)
ビルド プロパティが削除されるようにします:<PropertyGroup> <TargetFramework>net8.0</TargetFramework> <RootNamespace>MyMauiApp</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> ... </PropertyGroup>
重要
$(TargetFrameworks)
ビルド プロパティではなく、$(TargetFramework)
ビルド プロパティを設定するように注意してください。CreateMauiApp
メソッドが戻る前に呼び出される省略可能なAction<MauiAppBuilder>
引数を受け入れるように、MauiProgram
クラス内のメソッドを変更します: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(); }
この時点で、必要な .NET MAUI UI (依存関係やリソースを含む) をプロジェクトに追加し、プロジェクトが正しくビルドされていることを確認する必要があります。
.NET MAUI 単一プロジェクトの作成
.NET MAUI コントロールを使用するネイティブ アプリを作成する前に、以前に作成した .NET MAUI クラス ライブラリ プロジェクトと同じソリューションに .NET MAUI アプリ プロジェクトを追加する必要があります。 .NET MAUI アプリ プロジェクトには、ネイティブ埋め込みアプリで再利用する予定の UI が格納されます。 ソリューションに新しい .NET MAUI アプリ プロジェクトを追加した後、次の手順を実行します:
プロジェクトから [プロパティ] フォルダーを削除します。
Platforms フォルダーをプロジェクトから削除します。
プロジェクトから Resources/AppIcon フォルダーを削除します。
プロジェクトから Resources/raw フォルダーを削除します。
プロジェクトから Resources/Splash フォルダーを削除します。
プロジェクトから
AppShell
クラスを削除します。App
クラスがMainPage
プロパティを設定したり、CreateWindow
メソッドをオーバーライドしたりしていないことを確認します。public partial class App : Application { public App() { InitializeComponent(); } }
プロジェクトから
MainPage
クラスを削除します。プロジェクト ファイルを変更して、
$(TargetFramework)
ビルド プロパティがnet9.0
に設定され、$(OutputType)
ビルド プロパティが削除されるようにします:<PropertyGroup> <TargetFramework>net9.0</TargetFramework> <RootNamespace>MyMauiApp</RootNamespace> <UseMaui>true</UseMaui> <SingleProject>true</SingleProject> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> ... </PropertyGroup>
重要
$(TargetFrameworks)
ビルド プロパティではなく、$(TargetFramework)
ビルド プロパティを設定するように注意してください。MauiProgram
クラスで、TApp
ジェネリック引数を受け入れるようにCreateMauiApp
メソッドを変更し、メソッドが戻る前に呼び出される省略可能なAction<MauiAppBuilder>
引数を受け入れます。 さらに、呼び出しをUseMauiApp<App>
からUseMauiEmbeddedApp<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
クラスで、省略可能なAction<MauiAppBuilder>
引数を受け入れるCreateMauiApp
オーバーロードを追加します。public static class MauiProgram { ... // Create a MauiApp using the default application. public static MauiApp CreateMauiApp(Action<MauiAppBuilder>? additional = null) => CreateMauiApp<App>(additional); }
その後、依存関係やリソースを含め、必要な .NET MAUI UI をプロジェクトに追加し、プロジェクトが正しくビルドされていることを確認する必要があります。
.NET MAUI のサポートを有効にする
.NET for Android、.NET for iOS、.NET for Mac Catalyst、または WinUI アプリの Element から派生する .NET MAUI コントロールを使用するには、前に作成した .NET MAUI クラス ライブラリ プロジェクトと同じソリューションにネイティブ アプリ プロジェクトを追加する必要があります。 次に、プロジェクト ファイルの最初の <PropertyGroup>
ノードで $(UseMaui)
ビルド プロパティと $(MauiEnablePlatformUsings)
ビルド プロパティを true
に設定して、ネイティブ アプリのプロジェクト ファイルで .NET MAUI のサポートを有効にする必要があります:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
.NET for Mac Catalyst アプリの場合は、$(SupportedOSPlatformVersion)
ビルド プロパティを 14.0 以上に設定する必要もあります。
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>14.2</SupportedOSPlatformVersion>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
.NET for Mac Catalyst アプリの場合は、 $(SupportedOSPlatformVersion)
ビルド プロパティを 15.0 以上に設定する必要もあります。
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<SupportedOSPlatformVersion>15.0</SupportedOSPlatformVersion>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
</PropertyGroup>
WinUI アプリの場合は、$(EnableDefaultXamlItems)
ビルド プロパティを false
に設定する必要もあります:
<PropertyGroup>
...
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<UseMaui>true</UseMaui>
<MauiEnablePlatformUsings>true</MauiEnablePlatformUsings>
<EnableDefaultXamlItems>false</EnableDefaultXamlItems>
</PropertyGroup>
これにより、既に定義されている InitializeComponent
メソッドに関するビルド エラーが受信されなくなります。
次に、$(PackageReference)
ビルド項目を Microsoft.Maui.Controls
NuGet パッケージと Microsoft.Maui.Controls.Compatiblity
NuGet パッケージのプロジェクト ファイルに追加します:
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
</ItemGroup>
次に、Microsoft.Maui.Controls
NuGet パッケージ$(PackageReference)
プロジェクト ファイルにビルド項目を追加します。
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
</ItemGroup>
.NET MAUI を初期化する
ネイティブ アプリ プロジェクトで .NET MAUI コントロールを構築する前に、.NET MAUI を初期化する必要があります。 それを初期化するタイミングの選択は、主にアプリ フローで最も便利なタイミングによって異なります。これは起動時または .NET MAUI コントロールが構築される直前に実行できます。 ここで説明する方法は、アプリの初期 UI が作成されたときに .NET MAUI を初期化することです。
通常、ネイティブ アプリ プロジェクトで .NET MAUI を初期化するパターンは次のとおりです:
- MauiApp オブジェクトを作成します。
- MauiApp オブジェクトから MauiContext オブジェクトを作成します。 MauiContext オブジェクトは、.NET MAUI ビューからネイティブ ビューを取得するために使用されます。
Android では通常、MainActivity
クラスの OnCreate
オーバーライドが、アプリの起動に関連するタスクを実行する場所となります。 次のコード例は、MainActivity
クラスで初期化される .NET MAUI を示します。
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
...
}
}
iOS および Mac Catalyst では、以下のように FinishedLaunching
のオーバーライドで true
を返すように AppDelegate
クラスを変更する必要があります。
namespace MyNativeEmbeddedApp.iOS;
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}
その後、以下のように、メイン ビュー コントローラーを作成してそれを UINavigationController
のビューとして設定するように SceneDelegate
クラス内の WillConnect
メソッドを変更する必要があります。
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();
}
...
}
次に、XML エディターで Info.plist ファイルを開き、ファイルの末尾に次の XML を追加します。
<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>
.NET MAUI は、メイン ビュー コントローラーの ViewDidLoad
メソッドで初期化できます:
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
...
}
}
Windows では、MainWindow
クラスは通常、UI 関連のアプリのスタートアップ タスクを実行する場所です:
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
...
}
}
この例では、MauiApp オブジェクトは遅延初期化を使用して作成されます。 UseMauiEmbedding
拡張メソッドが MauiAppBuilder オブジェクトで呼び出されます。 そのため、ネイティブ アプリ プロジェクトには、この拡張メソッドを含む作成した .NET MAUI クラス ライブラリ プロジェクトへの参照を含める必要があります。 その後、MauiContext オブジェクトから MauiApp オブジェクトが生成され、bool
がコンテキストのスコープ元を決定します。 MauiContext オブジェクトは、.NET MAUI コントロールをネイティブ型に変換するときに使用します。
埋め込みはアプリ コンテキストまたはウィンドウ コンテキストで実行できますが、.NET MAUI の互換性を最大限に高める場合は、ウィンドウ コンテキストで実行する必要があります。
アプリのコンテキスト
ネイティブ埋め込みは、ネイティブ アプリがウィンドウに関する知識を持たないアプリ コンテキストで実行できます。 この方法では、ネイティブ埋め込み初期化では次の操作を行う必要があります。
- MauiApp オブジェクトを作成します。
- MauiApp オブジェクトから MauiContext オブジェクトを作成します。 MauiContext オブジェクトは、.NET MAUI ビューからネイティブ ビューを取得するために使用されます。
この方法の例を次に示します。
var mauiApp = MauiProgram.CreateMauiApp();
var context = new MauiContext(mauiApp.Services); // Activity also needs passing on Android
その後、.NET MAUI ビューを作成し、 ToPlatformEmbedded
拡張メソッドを使用してネイティブ ビューに変換できます。そのためには、 MauiContext オブジェクトを引数として必要とします。
このアプローチは、ネイティブ アプリで単純な .NET MAUI UI を埋め込む必要があるが、すべての .NET MAUI 機能にアクセスする必要がないシナリオに適しています。 この方法の欠点は、ホット リロードや一部の .NET MAUI 機能などのツールが機能しなくなる点です。
ヒント
.NET MAUI ビューをネイティブ ビューとして埋め込むたびに、 MauiApp オブジェクトを作成することはお勧めしません。 埋め込みビューが Application.Current
プロパティにアクセスする場合、これは問題になる可能性があります。 代わりに、 MauiApp オブジェクトを共有の静的インスタンスとして作成できます。
public static class MyEmbeddedMauiApp
{
static MauiApp? _shared;
public static MauiApp Shared => _shared ??= MauiProgram.CreateMauiApp();
}
この方法を使用すると、アプリのライフサイクルの早い段階で MauiApp オブジェクトをインスタンス化して、.NET MAUI ビューをアプリに初めて埋め込む際に少し遅延が発生しないようにすることができます。
Android では、フラグメントはアクティビティ内の UI の一部を表します。 次のコード例は、フラグメント内で初期化されている .NET MAUI を示しています。
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);
...
}
}
iOS および Mac Catalyst では、以下のように FinishedLaunching
のオーバーライドで true
を返すように AppDelegate
クラスを変更する必要があります。
namespace MyNativeEmbeddedApp.iOS;
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}
その後、以下のように、メイン ビュー コントローラーを作成してそれを UINavigationController
のビューとして設定するように SceneDelegate
クラス内の WillConnect
メソッドを変更する必要があります。
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();
}
...
}
次に、XML エディターで Info.plist ファイルを開き、ファイルの末尾に次の XML を追加します。
<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>
.NET MAUI は、メイン ビュー コントローラーの ViewDidLoad
メソッドで初期化できます:
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);
...
}
}
Windows では、MainWindow
クラスは通常、UI 関連のアプリのスタートアップ タスクを実行する場所です:
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);
...
}
}
この例では、 MauiApp オブジェクトは共有の静的インスタンスとして作成されます。 このオブジェクトが作成されると、MauiProgram.CreateMauiApp
が呼び出され、MauiAppBuilder オブジェクトに対して UseMauiEmbedding
拡張メソッドが呼び出されます。 そのため、ネイティブ アプリ プロジェクトには、 MauiProgram
クラスと .NET MAUI UI を含む、作成した .NET MAUI クラス ライブラリ プロジェクトへの参照を含める必要があります。 その後、MauiApp オブジェクトからMauiContext オブジェクトが作成され、MauiApp オブジェクトのスコープが設定されます。 MauiContext オブジェクトは、.NET MAUI コントロールをネイティブ型に変換するときに使用します。
ウィンドウ コンテキスト
ネイティブ埋め込みは、ネイティブ アプリがウィンドウに関する知識を持つウィンドウ コンテキストで実行できます。 一部のシナリオでは、.NET MAUI ビューが正常に動作するためにウィンドウへのアクセスが必要です。 たとえば、アダプティブ トリガーではビューのウィンドウにアクセスする必要があり、ウィンドウがない場合は機能しません。
この方法では、ネイティブ埋め込み初期化では次の操作を行う必要があります。
- MauiApp オブジェクトを作成します。
CreateEmbeddedWindowContext
メソッドを使用してMauiContext オブジェクトを作成します。 MauiContext オブジェクトは、.NET MAUI ビューからネイティブ ビューを取得するために使用されます。
CreateEmbeddedWindowContext
メソッドは、ネイティブ ウィンドウを .NET MAUI ウィンドウに関連付けるウィンドウ コンテキストを作成します。
var mauiApp = MauiProgram.CreateMauiApp();
var context = mauiApp.CreateEmbeddedWindowContext(this);
その後、.NET MAUI ビューを作成し、 ToPlatformEmbedded
拡張メソッドを使用してネイティブ ビューに変換できます。そのためには、 MauiContext オブジェクトを引数として必要とします。
Note
ToPlatformEmbedded
拡張メソッドには、埋め込みウィンドウに .NET MAUI ビューを追加するオーバーロードがあります。
この方法の利点は、ネイティブ ウィンドウごとに 1 つの .NET MAUI ウィンドウがあり、ウィンドウ関連の API が正しく機能し、ホット リロードなどのツールが正しく機能するという点です。
ヒント
.NET MAUI ビューをネイティブ ビューとして埋め込むたびに、 MauiApp オブジェクトを作成することはお勧めしません。 埋め込みビューが Application.Current
プロパティにアクセスする場合、これは問題になる可能性があります。 代わりに、 MauiApp オブジェクトを共有の静的インスタンスとして作成できます。
public static class MyEmbeddedMauiApp
{
static MauiApp? _shared;
public static MauiApp Shared => _shared ??= MauiProgram.CreateMauiApp();
}
この方法を使用すると、アプリのライフサイクルの早い段階で MauiApp オブジェクトをインスタンス化して、.NET MAUI ビューをアプリに初めて埋め込む際に少し遅延が発生しないようにすることができます。
Android では、フラグメントはアクティビティ内の UI の一部を表します。 次のコード例は、フラグメント内で初期化されている .NET MAUI を示しています。
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;
...
}
}
iOS および Mac Catalyst では、以下のように FinishedLaunching
のオーバーライドで true
を返すように AppDelegate
クラスを変更する必要があります。
namespace MyNativeEmbeddedApp.iOS;
[Register("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
public override UIWindow? Window { get; set; }
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) => true;
}
その後、以下のように、メイン ビュー コントローラーを作成してそれを UINavigationController
のビューとして設定するように SceneDelegate
クラス内の WillConnect
メソッドを変更する必要があります。
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();
}
...
}
次に、XML エディターで Info.plist ファイルを開き、ファイルの末尾に次の XML を追加します。
<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>
.NET MAUI は、メイン ビュー コントローラーの ViewDidLoad
メソッドで初期化できます:
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;
...
}
}
Windows では、MainWindow
クラスは通常、UI 関連のアプリのスタートアップ タスクを実行する場所です:
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;
...
}
}
この例では、 MauiApp オブジェクトは共有の静的インスタンスとして作成されます。 このオブジェクトが作成されると、MauiProgram.CreateMauiApp
が呼び出され、MauiAppBuilder オブジェクトに対して UseMauiEmbedding
拡張メソッドが呼び出されます。 そのため、ネイティブ アプリ プロジェクトには、 MauiProgram
クラスと .NET MAUI UI を含む、作成した .NET MAUI クラス ライブラリ プロジェクトへの参照を含める必要があります。 MauiContext オブジェクトは、ウィンドウにスコープが設定された CreateEmbeddedWindowContext
メソッドを使用して作成されます。 MauiContext オブジェクトは、.NET MAUI コントロールをネイティブ型に変換するときに使用します。
.NET MAUI コントロールを使用する
ネイティブ アプリで .NET MAUI が初期化されたら、ネイティブ アプリのレイアウトに .NET MAUI UI を追加できます。 これは、UI のインスタンスを作成し、ToPlatformEmbedded
拡張メソッドを使用して適切なネイティブ型に変換することで実現できます。
Android では、ToPlatformEmbedded
拡張メソッドは .NET MAUI コントロールを Android View オブジェクトに変換します:
var mauiView = new MyMauiContent();
Android.Views.View nativeView = mauiView.ToPlatformEmbedded(context);
この例では、ContentView から派生したオブジェクトが Android View オブジェクトに変換されます。
Note
ToPlatformEmbedded
拡張メソッドは、前に作成した .NET MAUI クラス ライブラリにあります。 そのため、ネイティブ アプリ プロジェクトには、そのプロジェクトへの参照を含める必要があります。
Note
ToPlatformEmbedded
拡張メソッドは、Microsoft.Maui.Controls.Embedding名前空間にあります。 そのため、ネイティブ アプリ プロジェクトには、その名前空間の using
ステートメントを含める必要があります。
その後、View オブジェクトをネイティブ アプリのレイアウトに追加できます:
rootLayout.AddView(nativeView, new LinearLayout.LayoutParams(MatchParent, WrapContent));
iOS および Mac Catalyst では、ToPlatformEmbedded
拡張メソッドは .NET MAUI コントロールを UIView オブジェクトに変換します:
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(context);
nativeView.WidthAnchor.ConstraintEqualTo(View.Frame.Width).Active = true;
nativeView.HeightAnchor.ConstraintEqualTo(500).Active = true;
この例では、ContentView 派生オブジェクトが UIView オブジェクトに変換されてから、やりとりを可能にするためにそのオブジェクトに幅と高さの制約が設定されます。
Note
ToPlatformEmbedded
拡張メソッドは、前に作成した .NET MAUI クラス ライブラリにあります。 そのため、ネイティブ アプリ プロジェクトには、そのプロジェクトへの参照を含める必要があります。
その後、UIView オブジェクトをビュー コントローラーのビューに追加できます:
stackView.AddArrangedSubView(nativeView);
var mauiView = new MyMauiContent();
UIView nativeView = mauiView.ToPlatformEmbedded(context);
この例では、ContentView から派生したオブジェクトが UIView オブジェクトに変換されます。
Note
ToPlatformEmbedded
拡張メソッドは、Microsoft.Maui.Controls.Embedding名前空間にあります。 そのため、ネイティブ アプリ プロジェクトには、その名前空間の using
ステートメントを含める必要があります。
その後、UIView オブジェクトをビュー コントローラーのビューに追加できます:
stackView.AddArrangedSubView(new ContainerView(nativeView));
ContainerView
は、.NET MAUI ビューをラップして、サイズが正しいことを確認するカスタム型です。 これは、 IntrinsicContentSize
を .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();
}
}
さらに、.NET MAUI の ToUIViewController
拡張メソッドを使用して、.NET MAUI ページを UIViewControllerに変換できます。
MyMauiPage myMauiPage = new MyMauiPage();
UIViewController myPageController = myMauiPage.ToUIViewController(context);
この例では、ContentPage から派生したオブジェクトを UIViewController に変換しています。
Windows では、ToPlatformEmbedded
拡張メソッドは .NET MAUI コントロールを FrameworkElement オブジェクトに変換します:
var mauiView = new MyMauiContent();
FrameworkElement nativeView = myMauiPage.ToPlatformEmbedded(context);
この例では、ContentView から派生したオブジェクトが FrameworkElement オブジェクトに変換されます。 その後、FrameworkElement オブジェクトを WinUI ページのコンテンツとして設定できます。
Note
ToPlatformEmbedded
拡張メソッドは、前に作成した .NET MAUI クラス ライブラリにあります。 そのため、ネイティブ アプリ プロジェクトには、そのプロジェクトへの参照を含める必要があります。
Note
ToPlatformEmbedded
拡張メソッドは、Microsoft.Maui.Controls.Embedding名前空間にあります。 そのため、ネイティブ アプリ プロジェクトには、その名前空間の using
ステートメントを含める必要があります。
その後、FrameworkElement オブジェクトをネイティブ アプリのレイアウトに追加できます:
stackPanel.Children.Add(nativeView);
重要
エラーが発生しないようにするには、デバッグ構成でネイティブ埋め込みアプリを実行する前に、XAML ホット リロードを無効にする必要があります。
XAML ホット リロードをサポートする
XAML ホット リロードは、ネイティブ埋め込みアプリではサポートされていません。 しかし、.NET MAUI UI を使用する .NET MAUI アプリを作成することで、XAML ホット リロードを使用して .NET MAUI UI 上の反復処理をすばやく行うことは可能です。
XAML ホット リロードを使用して .NET MAUI UI を表示するには:
.NET MAUI UI を含むプロジェクトで、以下のように、
MauiProgram
クラスを更新してCreateMauiApp
のオーバーロードを追加し、ジェネリック引数を受け入れるように既存のCreateMauiApp
メソッドを変更します。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(); } }
.NET MAUI UI を含むプロジェクトで、各リソース ディクショナリをスタンドアロン XAML ファイルから、分離コード ファイルをベースにしたリソース ディクショナリに変換します。
.NET MAUI UI を含むプロジェクトで、以下のように (通常は App.xaml 内にある) リソース ディクショナリのインスタンス化を更新して、
Source
プロパティがリソース ディクショナリを含むアセンブリも指定するようにします。<ResourceDictionary Source="Resources/Styles/Colors.xaml;assembly=NativeEmbeddingDemo" /> <ResourceDictionary Source="Resources/Styles/Styles.xaml;assembly=NativeEmbeddingDemo" />
新しい .NET MAUI アプリを作成し、それを .NET MAUI UI プロジェクトとネイティブ埋め込みアプリを含むソリューションに追加します。
.NET MAUI アプリ プロジェクトで、.NET MAUI UI を含むプロジェクトへの参照を追加します。
.NET MAUI アプリ プロジェクトで、.NET MAUI UI プロジェクトによってリソースが提供されている Resource の子フォルダーをすべて削除します。 たとえば、.NET MAUI UI プロジェクトに Resources > Fonts、Resources > Images、Resources > Styles フォルダーが含まれている場合、先ほど作成した .NET MAUI アプリからこれらのフォルダーを削除する必要があります。 これにより、.NET MAUI アプリは、.NET MAUI UI を含むプロジェクトのリソースを使用できるようになります。
.NET MAUI アプリで、以下のように
App
クラスを更新し、これが .NET MAUI UI プロジェクト内のApp
クラスから派生するようにします。<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>
次に、以下のように
App
クラスの分離コードを更新し、これが .NET MAUI UI プロジェクト内のApp
クラスから派生し、このプロジェクトからすべての XAML リソースを読み込むようにします。public partial class TestApp : myMauiUIProject.App { public TestApp() { var baseResources = Resources; InitializeComponent(); Resources.MergedDictionaries.Add(baseResources); MainPage = new HostPage(); } }
.NET MAUI アプリで、以下のように .NET MAUI UI を含むプロジェクトの UI を表示するページを追加します。
<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>
.NET MAUI アプリで、以下のように .NET MAUI UI を含むプロジェクト内の
CreateMauiApp
メソッドを呼び出すようにMauiProgram
クラスを更新します。public static class MauiProgram { public static MauiApp CreateMauiApp() => NativeEmbeddingDemo.MauiProgram.CreateMauiApp<TestApp>(builder => { // Add any test harness configuration such as service stubs or mocks. }); }
これで、各プラットフォームで .NET MAUI アプリ プロジェクトを実行し、XAML ホット リロードを使用して .NET MAUI UI 上の反復処理を行えるようになったはずです。
この方法の例については、サンプル アプリを参照してください。
.NET MAUI