maui-performance について
.NET MAUI アプリ開発者向けのパフォーマンス最適化スキルです。プロファイリング、バインディングやレイアウト、起動処理、トリミング、NativeAOT を扱います。
主な機能
- 01dotnet-trace と PerfView による分析
- 02コンパイル済みバインディングとリフレクション削減
- 03レイアウトとコレクション計測の最適化
- 04画像サイズとキャッシュの調整
- 05起動処理の削減とトリミング・NativeAOT の設定
活用シーン
- 01MAUI アプリの CPU・メモリ負荷の特定
- 02ページレイアウトとコレクション描画の改善
- 03トリミングや NativeAOT 公開前の互換性確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ davidortinau/ maui-skills --skill maui-performanceインストール後、Claude Code で/maui-performanceを入力して読み込まれたか確認します。
詳細
.NET MAUI のパフォーマンス最適化
プロファイリング
- dotnet-trace:すべての MAUI ターゲットに対応するクロスプラットフォームのプロファイラーです。次のコマンドでトレースを収集します。
dotnet-trace collect --process-id <PID> --providers Microsoft-DotNETCore-SampleProfiler - PerfView(Windows のみ):WinUI ターゲットでの詳細なメモリ割り当てと CPU の分析に使用します。
- 最適化の前にプロファイリングを行ってください。推測ではなく、測定しましょう。
コンパイル済みバインディング
- コンパイル済みバインディングを有効にするため、ページやビューには必ず
x:DataTypeを設定します。 - コンパイル済みバインディングは、リフレクションベースのバインディングより8~20 倍高速です。
- NativeAOT と完全なトリミングでは必須です。リフレクションバインディングはトリミング時に機能しなくなります。
x:DataTypeは、合理的に設定できる最も上位のスコープ(ページまたはルート要素)に設定します。
<ContentPage xmlns:vm="clr-namespace:MyApp.ViewModels"
x:DataType="vm:MainViewModel">
<Label Text="{Binding Title}" />
</ContentPage>
CollectionView/ListView内のDataTemplateでは、テンプレートのルートにx:DataTypeを設定します。
<DataTemplate x:DataType="model:Item">
<Label Text="{Binding Name}" />
</DataTemplate>
- 不要なバインディングを最小限にします:変化しない静的なコンテンツに
{Binding}は不要です。代わりにリテラル値またはx:Staticを使用します。
レイアウトの最適化
- 子要素が 1 つだけのレイアウトの入れ子は避けます。子要素が 1 つだけの
StackLayoutは無駄なオーバーヘッドになります。 - 入れ子の
StackLayout/VerticalStackLayoutよりGridを優先します。Grid は 1 回のパスでレイアウトを解決します。 - 実行時に要素をツリーに追加・削除するのではなく、
IsVisible="False"を使って非表示にします。 - 不要なラッパーコンテナーを削除します。レイアウトを追加するたびに、計測と配置のパスが増えます。
Gridの行/列定義で同じ結果を実現できる場合は、AbsoluteLayoutを避けます。- サイズが分かっている場合は
WidthRequest/HeightRequestを明示的に設定し、計測のパスを減らします。
CollectionView と ListView
- 項目の高さが均一な
CollectionViewでは、ItemSizingStrategy="MeasureFirstItem"を使用します。これにより、項目ごとの計測を避けられます。
<CollectionView ItemSizingStrategy="MeasureFirstItem"
ItemsSource="{Binding Items}">
- 新規開発では
ListViewよりCollectionViewを優先します。 DataTemplateのビジュアルツリーは浅く保ちます。項目ごとの入れ子レイアウトを減らします。
画像の最適化
- 表示解像度に合わせて画像のサイズを調整します。200×200 の表示に 4000×3000 の画像を読み込まないでください。
Aspect="AspectFill"またはAspectFitを使用し、サイズを明示的に設定します。- ダウンロードした画像をキャッシュします:
UriImageSourceではCachingEnabled="True"(デフォルト)を使用し、CacheValidityを設定します。 - プラットフォームに適した形式を使用します(Android では WebP、iOS では HEIF/PNG)。
- アイコンやシンプルなグラフィックには、SVG またはベクターベースのフォントアイコンを優先します。
リソースディクショナリ
- アプリレベル(
App.xaml):複数のページで使用する共通のスタイル、色、コンバーター。 - ページレベル:特定のページに固有のスタイル/リソースを定義し、
App.xamlを簡潔に保ちます。 - ディクショナリ間でリソースを重複させないようにします。
- 大規模なリソースセットを整理するには
MergedDictionariesを使用し、単一ファイルの肥大化を防ぎます。
起動時の最適化
AppコンストラクターとMainPageコンストラクターでの処理を最小限にします。- 必須ではないサービスの登録を遅らせ、可能な場合は遅延初期化を使用します。
- 起動時に解析する XAML ページの数を減らします(遅延読み込みには
Shellルーティングを使用します)。 MauiProgram.csから未使用のHandlers/Effectsの登録を削除します。- Android では、起動時に不要な権限チェックが強制されないよう、
AndroidManifest.xmlを確認します。
トリミング
IL トリミングを有効にして、アプリのサイズを縮小し、未使用のコードを削除します。
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>full</TrimMode>
</PropertyGroup>
- 十分にテストしてください。トリミングによって、リフレクション経由でのみアクセスされるコードが削除される場合があります。
- リフレクションの対象を保持するには、
[DynamicDependency]または[UnconditionalSuppressMessage]を使用します。 - コンパイル済みバインディングは不可欠です。リフレクションベースのバインディングはトリミングによって削除されます。
NativeAOT
- NativeAOT は事前にネイティブコードへコンパイルするため、起動が速くなり、フットプリントが小さくなります。
- 要件:コンパイル済みバインディング、制約のないリフレクションを使用しないこと、トリミング互換のコード。
<PropertyGroup>
<PublishAot>true</PublishAot>
<PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
- サードパーティ製 NuGet パッケージのトリミング/AOT 互換性を監査します。
- リフレクションベースの JSON シリアル化の代わりに、
[JsonSerializable]ソースジェネレーターを使用します。 - リリース前に AOT を有効にして
dotnet publishを実行し、警告がないことを確認します。
クイックチェックリスト
- ✅ すべてのページ、テンプレート、データバインドされたビューに
x:DataTypeを指定します - ✅ 単一の子要素を持つレイアウトの入れ子を避けます
- ✅ 入れ子になった StackLayouts より Grid を優先します
- ✅ 画像を表示サイズに合わせ、キャッシュを有効にします
- ✅ 均一な CollectionViews に
ItemSizingStrategy="MeasureFirstItem"を指定します - ✅ 起動時の処理を最小限に抑え、後回しにします
- ✅ トリミングを有効にしてテストします
- ✅ 変更の前後に dotnet-trace でプロファイルを取得します
コメント
Markdown 対応