iOS および Mac Catalyst でのネイティブ AOT デプロイ
ネイティブ AOT デプロイでは、ネイティブ コードにコンパイルされた事前 (AOT) である iOS および Mac Catalyst 上の .NET マルチプラットフォーム アプリ UI (.NET MAUI) アプリが生成されます。 ネイティブ AOT は、静的なプログラム分析、アプリの完全なトリミングを実行します。これは、静的に参照されていないコードを削除する際に積極的であり、事前にコードを生成します。
ネイティブ AOT アプリの発行とデプロイには、次の利点があります。
- アプリ パッケージのサイズが縮小されました。
- 起動時間が短縮されました。
- ビルド時間が短縮されます。
ネイティブ AOT では、.NET ランタイムの特定の側面の使用に制限が導入され、アプリのサイズとパフォーマンスが重要なシナリオでのみ使用する必要があります。 ネイティブ AOT 要件に合わせてアプリを調整する必要があります。つまり、アプリが完全にトリミングされ、AOT と互換性があることを確認します。 ネイティブ AOT の制限の詳細については、「 Native AOT の制限事項を参照してください。
ネイティブ AOT デプロイが有効になっている場合、ビルド システムはコードとそのすべての依存関係を分析して、完全なトリミングと AOT コンパイルに適しているかどうかを確認します。 非互換性が検出されると、トリミングと AOT 警告が生成されます。 1 つのトリミングまたは AOT 警告は、アプリがネイティブ AOT デプロイと互換性がない、および正しく動作しない可能性があることを意味します。 そのため、ネイティブ AOT デプロイ用のアプリをビルドするときは、すべてのトリミングと AOT の警告を確認して修正する必要があります。 これを行わないと、必要なコードが削除された可能性があるため、実行時に例外が発生する可能性があります。 警告を抑制する場合は、AOT でデプロイされたアプリを十分にテストして、機能が未インストールのアプリから変更されていないことを確認する必要があります。 詳細については、「警告をトリミングする方法AOT 警告の概要を参照してください。
Note
トリミングと AOT の警告を修正できない場合があります (サード パーティ製ライブラリで発生した場合など)。 このような場合は、完全に互換性を得るためにサードパーティ製ライブラリを更新する必要があります。
ネイティブ AOT パフォーマンスの利点
ネイティブ AOT アプリを発行してデプロイすると、通常は最大 2.5 倍小さいアプリと、通常は最大 2 倍速く起動するアプリが生成されます。 ただし、正確なパフォーマンス上の利点は、使用されているプラットフォーム、アプリが実行されているデバイス、アプリ自体など、複数の要因によって異なります。
重要
次のグラフは、iOS および Mac Catalyst 上の dotnet new maui
アプリのネイティブ AOT 展開の一般的なパフォーマンス上の利点を示しています。 ただし、正確なデータはハードウェアに依存しており、将来のリリースで変更される可能性があります。
次のグラフは、iOS および Mac Catalyst 上の dotnet new maui
アプリのアプリ パッケージ サイズを、さまざまなデプロイ モデルで示しています。
上記のグラフは、通常、ネイティブ AOT では、既定のデプロイ モデルと比較して、iOS と Mac Catalyst の両方で 2 倍以上の小さなアプリが生成されることを示しています。
次のグラフは、iOS および Mac Catalyst on Mono およびネイティブ AOT 展開の dotnet new maui
アプリの、特定のハードウェアでの平均起動時間を示しています。
上の図は、ネイティブ AOT の iOS デバイスでの起動時間が最大 2 倍、Mac Catalyst での起動時間が Mono の場合と比較して 1.2 倍高速であることを示しています。
次のグラフは、iOS および Mac Catalyst 上の dotnet new maui
アプリの特定のハードウェアでのさまざまなデプロイ モデルの平均ビルド時間を示しています。
上記のグラフは、通常、既定のデプロイ モデルと比較して、iOS デバイスでのネイティブ AOT のビルド時間が最大 2.8 倍高速であることを示しています。 Mac Catalyst の場合、arm64 単一 RID アプリのビルド時間は同等ですが、Mono デプロイと比較するとユニバーサル アプリの場合は若干遅くなります。
重要
多くのシナリオでは、ネイティブ AOT は、より小さく、より高速なアプリを生成します。 ただし、一部のシナリオでは、ネイティブ AOT では、より小さく高速なアプリが生成されない場合があります。 そのため、ネイティブ AOT デプロイを有効にした結果を判断するには、アプリをテストしてプロファイリングすることが重要です。
ネイティブ AOT を使用して発行する
ネイティブ AOT デプロイ モデルは、 $(PublishAot)
ビルド プロパティと dotnet publish
コマンドを使用して有効になります。 次の例では、プロジェクト ファイルを変更して、iOS および Mac Catalyst でネイティブ AOT 展開を有効にする方法を示します。
<PropertyGroup>
<!-- enable trimming and AOT analyzers on all platforms -->
<IsAotCompatible>true</IsAotCompatible>
<!-- select platforms to use with NativeAOT -->
<PublishAot Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">true</PublishAot>
<PublishAot Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">true</PublishAot>
</PropertyGroup>
$(IsAotCompatible)
ビルド プロパティをすべてのプラットフォームでtrue
に設定すると、トリミングと AOT アナライザーが有効になります。 これらのアナライザーは、トリミングまたは AOT と互換性のないコードを識別するのに役立ちます。
iOS および Mac Catalyst の場合、 $(PublishAot)
を true
に条件付きで設定すると、ビルド時の動的コード使用状況分析と、発行中のネイティブ AOT コンパイルが可能になります。 ネイティブ AOT 分析には、アプリのすべてのコードと、アプリが依存するすべてのライブラリが含まれます。
警告
$(PublishAot)
ビルド プロパティは、ビルド構成によって条件付けしないでください。 これは、トリミング機能スイッチは、 $(PublishAot)
ビルド プロパティの値に基づいて有効または無効になり、コードが同じように動作するように、すべてのビルド構成で同じ機能を有効または無効にする必要があるためです。 フィーチャー スイッチのトリミングの詳細については、「 機能スイッチのトリミングを参照してください。
ネイティブ AOT アプリが正しく動作することを確認する唯一の方法は、 dotnet publish
を使用して発行し、コードとその依存関係によって生成されたトリミングまたは AOT 警告がないことを確認することです。 特に、 dotnet build -t:Publish
は dotnet publish
と同等ではありません。
ネイティブ AOT デプロイを使用して iOS および Mac Catalyst にアプリを発行するには、次の dotnet publish
コマンドを使用します。
# iOS
dotnet publish -f net9.0-ios -r ios-arm64
# Mac Catalyst
dotnet publish -f net9.0-maccatalyst -r maccatalyst-arm64
dotnet publish -f net9.0-maccatalyst -r maccatalyst-x64
# Universal Mac Catalyst apps
# (when <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> is set in the project file)
dotnet publish -f net9.0-maccatalyst
ヒント
アプリを頻繁に発行して、開発ライフサイクルの早い段階でトリミングまたは AOT の問題を検出します。
ネイティブ AOT の制限事項
ネイティブ AOT では、.NET ランタイムの特定の側面の使用に制限が導入され、アプリのサイズとパフォーマンスが重要なシナリオでのみ使用する必要があります。 ネイティブ AOT 要件に合わせてアプリを調整する必要があります。つまり、アプリが完全にトリミングされ、AOT と互換性があることを確認し、これには多くの作業が必要になる可能性があります。 ネイティブ AOT デプロイの .NET の制限に加えて.NET MAUI のネイティブ AOT デプロイには、追加の制限があります。
アプリが依存しているサード パーティ製ライブラリは、AOT と互換性がない可能性があります。 ライブラリがトリミングされ、AOT と互換性があることを確認する唯一の方法は、ネイティブ AOT デプロイと dotnet publish
コマンドを使用してアプリを発行し、ネイティブ AOT コンパイラがライブラリの警告を生成するかどうかを確認することです。 独自のライブラリを AOT 互換にする方法については、「 ライブラリをネイティブ AOT と互換性のあるものにする方法を参照してください。
リフレクションと動的コード
ネイティブ AOT デプロイでは、コードとその依存関係でのリフレクションの使用が制限され、ネイティブ AOT コンパイラがリフレクション パターンを理解するのに役立つ注釈を使用することが必要になる場合があります。 コンパイラがリフレクション パターンを検出すると、静的に分析できないため、アプリをビルドできないため、トリミング警告が生成されます。 ネイティブ AOT では、アプリで動的コードを使用することもできなくなります。 たとえば、 System.Linq.Expressions のコンパイルは期待どおりに機能せず、実行時にアセンブリを読み込んで実行することはできません。 コンパイラが動的パターンを検出すると、事前コンパイルができないと、AOT 警告が生成されます。
.NET MAUI アプリでは、これは次のことを意味します。
- すべての XAML は、事前にコンパイルする必要があります。 そのため、XAML コンパイルを無効にしていないことと、すべてのバインドがコンパイルされていることを確認してください。 詳細については、
XAML のコンパイル とコンパイルバインドを参照してください。 - すべてのバインド式では、文字列に設定されたバインド パスではなく、コンパイル済みのバインドを使用する必要があります。 詳しくは、「コンパイル済みのバインド」を参照してください。
- XAML のプロパティに互換性のない型の値を割り当てたり、異なる型の 2 つのプロパティでデータ バインディングを使用したりする場合、暗黙的な変換演算子が呼び出されない場合があります。 代わりに、型の TypeConverter を定義し、 TypeConverterAttributeを使用して型にアタッチする必要があります。 詳細については、「 暗黙的な変換演算子を置き換える TypeConverter を定義するを参照してください。
- LoadFromXaml メソッドを使用して実行時に XAML を解析することはできません。 これは、実行時に読み込むことができるすべての型に
DynamicallyAccessedMembers
属性またはDynamicDependency
属性を使用して注釈を付けることでトリミングを安全にすることができますが、これは非常にエラーが発生しやすく、推奨されません。 - QueryPropertyAttributeを使用してナビゲーション データを受信することはできません。 代わりに、クエリ パラメーターを受け入れる必要がある型に IQueryAttributable インターフェイスを実装する必要があります。 詳細については、「単一のメソッドを使用してナビゲーションデータを処理する」を参照してください。
SearchHandler.DisplayMemberName
プロパティが機能しない可能性があります。 代わりに、SearchHandler の結果の外観を定義する ItemTemplate を指定する必要があります。 詳細については、「 検索結果アイテムの外観を定義する」を参照してください。
重要
Mono インタープリターはネイティブ AOT デプロイと互換性がないため、ネイティブ AOT を使用する場合、MSBuild プロパティ $(UseInterpreter)
と $(MtouchInterpreter)
は無効です。 Mono インタープリターの詳細については、「iOS および Mac Catalyst の Mono インタープリターを参照してください。
トリミング警告の詳細については、「 警告をトリミングする方法を参照してください。 AOT 警告の詳細については、「 AOT 警告への導入」を参照してください。
ネイティブ AOT デプロイにアプリを適応させる
次のチェックリストを使用して、アプリをネイティブ AOT デプロイ要件に適応させます。
- すべての XAML がコンパイルされていることを確認します。
[XamlCompilation(XamlCompilationOptions.Skip)]
の使用状況をすべて削除します。<?xaml-comp compile="false" ?>
の使用状況をすべて削除します。
- LoadFromXaml メソッドのすべての呼び出しを削除します。
- すべてのデータ バインディングがコンパイルされていることを確認します。 詳しくは、「コンパイル済みのバインド」を参照してください。
- すべての XAML データ バインディングに
x:DataType
で注釈が付けられるようにします。 - すべてのコード データ バインディングが、すべての文字列ベースのバインドをラムダ ベースのバインドに置き換えることを確認します。
- すべての XAML データ バインディングに
- すべての
[QueryProperty(...)]
使用を、IQueryAttributable
インターフェイスの実装に置き換えます。 詳細については、「単一のメソッドを使用してナビゲーションデータを処理する」を参照してください。 - すべての
SearchHandler.DisplayMemberName
使用法を ItemTemplateに置き換えます。 詳細については、「 検索結果アイテムの外観を定義する」を参照してください。 - XAML で使用される型のすべての暗黙的な変換演算子を TypeConverterに置き換え、 TypeConverterAttributeを使用して型にアタッチします。 詳細については、「 暗黙的な変換演算子を置き換える TypeConverter を定義するを参照してください。
- 型
A
から型B
に変換する場合は、A
に関連付けられている型コンバーターのConvertTo
メソッドが使用されるか、B
に関連付けられている型コンバーターのConvertFrom
メソッドが使用されます。 - ソース型とターゲット型の両方に関連付けられた型コンバーターがある場合は、いずれかを使用できます。
- 型
- ソース ジェネレーターを使用して、すべての正規表現をコンパイルします。 詳細については、「.NET 正規表現ソース ジェネレーター」を参照してください。
- JSON のシリアル化と逆シリアル化で、ソースによって生成されたコンテキストが使用されていることを確認します。 詳細については、「 Minimal API と JSON ペイロードを参照してください。
- トリミングまたは AOT の警告を確認して修正します。 詳細については、「警告をトリミングする方法AOT 警告の概要を参照してください。
- アプリを徹底的にテストします。
iOS および Mac Catalyst でのネイティブ AOT 診断サポート
ネイティブ AOT と Mono は、診断機能とインストルメンテーション機能のサブセットを共有します。 Mono の診断ツールの範囲により、ネイティブ AOT ではなく Mono 内の問題を診断してデバッグすると便利です。 トリミングと AOT 互換のアプリには動作の違いはありません。そのため、多くの場合、両方のランタイムに調査が適用されます。
次の表は、iOS および Mac Catalyst でのネイティブ AOT での診断のサポートを示しています。
機能 | 完全にサポートされています | 一部サポートされています | サポートされていません |
---|---|---|---|
監視とテレメトリ | 部分的にサポート | ||
開発時の診断 | 完全にサポート | ||
ネイティブ デバッグ | 部分的にサポート | ||
CPU プロファイリング | 部分的にサポート | ||
ヒープ分析 | サポートされていません |
次のセクションでは、この診断サポートに関する追加情報を提供します。
監視とテレメトリ
モバイル プラットフォーム上の .NET MAUI アプリケーションのトレースは、 dotnet-dsrouter を使用して有効になります これは、診断ツールを、iOS および Mac Catalyst で実行されている .NET アプリケーションと TCP/IP 経由で接続します。 ただし、現在、ネイティブ AOT は TCP/IP スタックで構築された EventPipe/DiagnosticServer コンポーネントをサポートしていないため、このシナリオと互換性がありません。 コードでは、可観測性は引き続き明示的に実現できます。
開発時の診断
.NET CLI ツールでは、 build
と publish
に個別のコマンドが提供されます。 dotnet build
(または Visual Studio Code の Start Debugging (F5)
) では、.NET MAUI iOS または Mac Catalyst アプリケーションをビルドまたは起動するときに、Mono が既定で使用されます。 このデプロイ モデルがプロジェクト ファイルで可能な場合は、dotnet publish
のみがネイティブ AOT アプリケーションを作成します。
すべての診断ツールが、公開されたネイティブ AOT アプリケーションとシームレスに連携するわけではありません。 ただし、trim と AOT 互換のすべてのアプリケーション (つまり、ビルド時にトリムと AOT の警告を生成しないアプリケーション) には、Mono とネイティブ AOT の動作の違いはありません。 そのため、ホット リロードなどのすべての .NET 開発時診断ツールは、モバイル アプリケーション開発サイクル中に開発者が引き続き使用できます。
ヒント
通常どおりにアプリケーションを開発、デバッグ、テストし、最後の手順の 1 つとしてネイティブ AOT を使用して最終的なアプリを発行する必要があります。
ネイティブ デバッグ
開発中に .NET MAUI iOS または Mac Catalyst アプリケーションを実行すると、Mono で既定で実行されます。 ただし、プロジェクト ファイルでネイティブ AOT デプロイが有効になっている場合、ビルド時にアプリケーションでトリミングと AOT の警告が生成されない場合、Mono と Native AOT の間で動作は同じであることが期待されます。 アプリケーションがこの要件を満たしている場合は、開発とテストに標準の Visual Studio Code マネージド デバッグ エンジンを使用できます。
発行後、ネイティブ AOT アプリケーションは真のネイティブ バイナリであるため、マネージド デバッガーは動作しません。 ただし、ネイティブ AOT コンパイラは、 lldb
でデバッグできる完全ネイティブ実行可能ファイルを生成します。 lldb
を使用した Mac Catalyst アプリのデバッグは、同じシステム上で実行されるため、簡単です。 ただし、NativeAOT iOS アプリケーションのデバッグには追加の作業が必要です。
ネイティブ AOT を使用して .NET MAUI iOS アプリケーションをデバッグする
ネイティブ AOT と互換性があり、このデプロイ モデルで適切に構成および公開されている .NET MAUI iOS アプリケーションは、次のようにデバッグできます。
ネイティブ AOT ターゲット
ios-arm64
を使用してアプリを発行し、次の情報に注意してください。- アプリケーション名 (以下
<app-name>
参照)。 - バンドル識別子 (以下に
<bundle-identifier>
として参照)。 - 発行されたアプリケーションのアーカイブ .ipa ファイルへのパス (以下
<path-to-ipa>
参照)。
- アプリケーション名 (以下
物理デバイス ID を取得します (以下
<device-identifier>
参照)。xcrun devicectl list devices
物理デバイスにアプリをインストールします。
xcrun devicectl device install app --device <device-identifier> <path-to-ipa>
物理デバイスでアプリを起動します。
xcrun devicectl device process launch --device <device-identifier> --start-stopped <bundle-identifier>
lldb
を開き、物理デバイスに接続します。(lldb) device select <device-identifier> (lldb) device process attach -n <app-name>
これらの手順が正常に完了すると、 lldb
を使用してネイティブ AOT .NET MAUI iOS アプリケーションのデバッグを開始できるようになります。
シンボル ファイルの重要度
既定では、デバッグ シンボルはアプリケーションのバイナリ ファイルから .dSYM ファイルに削除されます。 このファイルは、ローカル変数、ソース行番号に関する情報を表示したり、クラッシュ ダンプのスタック トレースを再作成したりするために、デバッガーと事後分析ツールによって使用されます。 そのため、アプリケーションを App Store に送信する前にシンボル ファイルを保持することが不可欠です。
CPU プロファイリング
Xcode Instruments を使用して、ネイティブ AOT アプリケーションの CPU サンプルを収集できます。
ヒープ分析
ヒープ分析は現在、ネイティブ AOT ではサポートされていません。
関連項目
.NET MAUI