.NET 6の現状を把握し、具体的な移行方法を学ぶ連載。今回は、.NET MAUIの概要とXamarn.Formsからの改良ポイントについてまとめる。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
2022年5月23日(米国時間)、.NET MAUIがGA(一般提供)されました。Microsoftは「.NET MAUIは、.NET Multi-platform App UIの略称で、モバイル、タブレット、デスクトップにまたがるネイティブデバイスのアプリケーションを構築するフレームワークです」と紹介しています。
.NET MAUI自体はGAされましたが、2022年6月26日の原稿執筆では開発環境「Visual Studio」は、Windows版も、Mac版も最新のプレビュー版での対応です。こちらは程なく安定版のVisual Studioでも対応されるでしょう。
.NET MAUIはXamarin.Formsから全く違う製品名に変わりましたが、何が違うのでしょうか? 分かりやすくいえば、.NET MAUIはXamarin.Formsの改良版です。本稿では、.NET MAUIはXamarin.Formsと比べて、どこが改良されたのか、具体的に解説します。
Xamarin.Formsと.NET MAUIの主な違いを表でまとめました。
| Xamarin.Forms | .NET MAUI | |
|---|---|---|
| プロジェクトの構造 | 非SDKスタイル(Franken-proj) プラットフォームごとに個別のプロジェクトを使用 |
SDKスタイル 単一のプロジェクトで、複数プラットフォームをターゲットにできる |
| ツールチェーン | .NET Framework | .NET CLI |
| リソース管理 | プラットフォームごとに個別管理 プラットフォーム固有のデバイスの解像度に応じたイメージを準備する必要がある |
単一のプロジェクト内で一元管理 SVGを準備すれば各プラットフォームの解像度のPNGに変換でされる |
| スタートアップ | 独自(Appクラス) | Generic Host対応 |
| ホットリロード | 完全なXAMLホットリロード (SDK 5.xおよびVisual Studio 2019 16.9以降) |
完全な.NETホットリロード 完全なXAMLホットリロード |
| UIコントロールアーキテクチャ | レンダラー | ハンドラー |
以降、.NET MAUIの改良点の中で、特に注目のポイントを紹介します。
.NET MAUIのプロジェクトは下図のようになっています。
Xamarin.Formsのような「単一の共有プロジェクト+複数のプラットフォーム固有プロジェクト」の構成ではなく、単一のプロジェクトで、複数プラットフォームをターゲットにできるようになりました。
Xamarin.Formsは登場当時、画期的なフレームワークでした。ですが、利用が進むにつれてアーキテクチャに起因する問題点も顕在化しました。
下図のようにレンダラーは共有プロジェクトのUIコントロール実装に依存しています。
Xamarin.Formsからの最大の変更点は、レンダラーアーキテクチャからハンドラーアーキテクチャへの変更です。ハンドラーアーキテクチャの採用によってプラットフォーム固有のレンダリングの責務を、抽象化UIフレームワークの実装から分離しました。
下図のようにハンドラーはインタフェースにのみ依存し、抽象化UIコントロールの実装には依存しません。
また、共有コード内で複数のプラットフォームのネイティブUIコントロールを直接操作できます。
これによって、以下に述べるようなアドバンテージが生まれました。
Generic Hostは、アプリの起動やシャットダウンのようなライフタイム管理や、アプリの構成やロギング、DI(Dependency Injection:依存性の注入)といった、アプリのビジネスロジック自体とは関係ない、基盤となる機能をカプセル化するオブジェクトです。ビジネスロジックとアプリの基盤に関わる機能を分離できるので、クリーンな構造にすることができます。
Generic Hostの詳細はこちらをご覧ください。
.NET MAUIではGeneric Hostに対応したので、スタートアップの処理がXamarin.Formsと大きく異なります。ここからは、.NET MAUIのスタートアップコードのサンプルを見ていきます。なお以下のコードは、説明するために調整されたものです。ベストプラクティスではないのでご注意ください。
まずは、コード全体です。Generic Host内では、次の4つを行っています。
スタートアップコードはMauiProgram.csに記述します。
using MauiUICustomizeSample.Controls;
using Microsoft.Maui.Handlers;
using Microsoft.Maui.Platform;
namespace MauiUICustomizeSample;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder .UseMauiApp<App>() // 起動するアプリクラスの指定
.ConfigureFonts(fonts => // リソースフォルダ内のフォントの登録
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
// Dependency injection : AppSlell クラスをDIコンテナに登録
builder.Services.AddTransient<AppShell>();
// 全てのLabelのカスタマイズ
LabelHandler.Mapper.AppendToMapping(nameof(IView.Background), (handler, view) =>
{
if (view is Label)
{
#if IOS
handler.PlatformView.BackgroundColor = Colors.MediumSpringGreen.ToPlatform();
#elif ANDROID
handler.PlatformView.SetBackgroundColor(Colors.MediumSpringGreen.ToPlatform());
#endif
}
});
// 特定のインスタンスのButtonのカスタマイズ
ButtonHandler.Mapper.AppendToMapping(nameof(IView.Background), (handler, view) =>
{
if (view is MyButton)
{
#if IOS
handler.PlatformView.BackgroundColor = Colors.LightCoral.ToPlatform();
handler.PlatformView.SetTitleColor(Colors.White.ToPlatform(), UIKit.UIControlState.Normal);
handler.PlatformView.Layer.CornerRadius = 7;
#elif ANDROID
handler.PlatformView.SetBackgroundColor(Colors.LightCoral.ToPlatform());
#endif
}
});
return builder.Build();
}
}
個別の処理について詳説します。
・MAUI用のGeneric Hostのビルダーを作成
MauiAppのCreateBuilderメソッドでMauiAppBuilderのインスタンスが作成されます。
var builder = MauiApp.CreateBuilder();
・起動するアプリクラス(このサンプルではAppクラス)を指定
MauiAppBuilderのUseMauiAppメソッドの型パラメーターに起動するアプリクラスの型(App)を指定します。
builder.UseMauiApp<App>()
AppクラスはApp.xaml.csで定義されています。
namespace MauiUICustomizeSample;
public partial class App : Application
{
public App(AppShell appShell)
{
InitializeComponent();
MainPage = appShell;
}
}
・フォントの登録
プロジェクト内の「/Resources/Fonts」内に配置されたフォントを登録します。
MauiAppBuilderのConfigureFontsメソッド内のデリゲートで登録します。
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
・AppSlellクラスをDIコンテナに登録
AppSlellクラスをDIコンテナに登録し、インスタンスが注入されるようにします。
builder.Services.AddTransient<AppShell>();
これによって、App.xaml.csのコンストラクタのappShellパラメーターにインスタンスが注入されます。
namespace MauiUICustomizeSample;
public partial class App : Application
{
public App(AppShell appShell)
{
InitializeComponent();
MainPage = appShell;
}
}
・ハンドラーを利用したUIのカスタマイズ
サンプルでは、「特定の種類のUIコントロール全てをカスタマイズする場合」「あるUIコントロールの特定のインスタンスのみをカスタマイズする場合」の2つのパターンでUIをカスタマイズしています。両者とも、Xamarin.Formsと比較して簡単にカスタマイズできます。
・特定の種類のUIコントロール全てをカスタマイズする場合
Labelコントロール全ての背景色をMediumSpringGreenに変更します。
// 全てのLabelのカスタマイズ
LabelHandler.Mapper.AppendToMapping(nameof(IView.Background), (handler, view) =>
{
if (view is Label)
{
#if IOS
handler.PlatformView.BackgroundColor = Colors.MediumSpringGreen.ToPlatform();
#elif ANDROID
handler.PlatformView.SetBackgroundColor(Colors.MediumSpringGreen.ToPlatform());
#endif
}
});
AppendToMappingのActionデリゲート内でUIコントロールの型がLabelの場合、カスタマイズしたい色を設定します。handler.PlatformViewには、iOSの場合はUILabelが、Androidの場合はAppCompatTextViewが割り当てられています。そのため、それぞれのネイティブUIコントロールのプロパティを変更することで、色も変更できます。設定する色はToPlatformメソッドによって、それぞれのプラットフォームのネイティブカラーに変換されます。
ここで注目なのは、たった数行のコードで共有コード内のUILabel.BackgroundColorや、AppCompatTextView.SetBackgroundColorといったプロパティやメソッドが使用できることです。これをXamarin.Formsでするには、各プラットフォームプロジェクト内でクラスを定義し定型的なコードを書く必要があったので、簡単になっているのが分かります。
・あるUIコントロールの特定のインスタンスのみをカスタマイズする場合
こちらでは、Buttonコントロール特定のインスタンスの背景色をLightCoralに変更します。
ButtonのサブクラスMyButtonを作成します。
namespace MauiUICustomizeSample.Controls
{
public class MyButton : Button
{
public MyButton()
{
}
}
}
MauiProgram.csでMyButtonに対してカスタマイズを適用します。
// 特定のインスタンスの Button のカスタマイズ
ButtonHandler.Mapper.AppendToMapping(nameof(IView.Background), (handler, view) =>
{
if (view is MyButton)
{
#if IOS
handler.PlatformView.BackgroundColor = Colors.LightCoral.ToPlatform();
handler.PlatformView.SetTitleColor(Colors.White.ToPlatform(), UIKit.UIControlState.Normal);
handler.PlatformView.Layer.CornerRadius = 7;
#elif ANDROID
handler.PlatformView.SetBackgroundColor(Colors.LightCoral.ToPlatform());
#endif
}
});
AppendToMappingのActionデリゲート内で、UIコントロールの型がMyButtonの場合、カスタマイズしたい色を設定します。
handler.PlatformViewには、iOSの場合はUIButtonが、Androidの場合はMaterialButtonが割り当てられるので、それぞれのネイティブUIコントロールのプロパティを変更することで、色を変更できます。設定する色はToPlatformメソッドによって、それぞれのプラットフォームのネイティブカラーに変換されます。
カスタマイズしたコントロールをXAML内で使用するには、「xmlns:button="clr-namespace:MauiUICustomizeSample.Controls"」のように名前空間を指定します。
MyButtonのみ背景色がカスタマイズされます。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:button="clr-namespace:MauiUICustomizeSample.Controls"
x:Class="MauiUICustomizeSample.MainPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="Hello, MAUI!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Welcome to.NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App UI"
FontSize="16"
HorizontalOptions="Center" />
<HorizontalStackLayout
Spacing="10"
HorizontalOptions="Center">
<Button
x:Name="CounterBtn"
WidthRequest="120"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Start" />
<button:MyButton
x:Name="CustomizedBtn"
WidthRequest="120"
Text="Customized"
HorizontalOptions="End" />
</HorizontalStackLayout>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
iOSでの実行結果は、下図のようになります。ラベルの全体の背景色と、右側のボタンの背景色がカスタマイズされています。
ハンドラーを使用したコントロールのカスタマイズの詳細は、こちらをご覧ください。
本稿で説明したように、.NET MAUIでは、Xamarin.Formsの面倒だった部分が扱いやすくなり、直感的でシンプルなコードで記述できるように改善されました。また、アセンブリスキャンやリフレクションなど、コストの高い処理を回避することで起動速度が向上しました。つまり「.NET MAUI=よりシンプルで使いやすくなったXamarin.Forms」といえます。
.NET MAUIは今後も強化され続けるとアナウンスされています。まずは強力に生まれ変わった.NET MAUIを体験してみてはいかがでしょうか。
Arm64デバイスでネイティブ開発が可能に、「Visual Studio 2022 17.3 Preview 2」がリリース
デベロッパーが注目したいMSの開発関連技術「.NET MAUI」「Microsoft Dev Box」の威力とは
Microsoft、「Xamarin」の全APIドキュメントをオープンソース化Copyright © ITmedia, Inc. All Rights Reserved.