Condividi tramite


Distribuzione AOT nativa in iOS e Mac Catalyst

La distribuzione AOT nativa produce un'app .NET Multipiattaforma (.NET MAUI) in iOS e Mac Catalyst che è stata compilata in anticipo nel codice nativo. AOT nativo esegue l'analisi statica del programma, il taglio completo dell'app, che è aggressivo nella rimozione del codice a cui non viene fatto riferimento staticamente e nella generazione di codice in anticipo.

La pubblicazione e la distribuzione di un'app AOT nativa offre i vantaggi seguenti:

  • Riduzione delle dimensioni del pacchetto dell'app.
  • Tempo di avvio più veloce.
  • Tempo di compilazione più rapido.

AOT nativo introduce limitazioni sull'utilizzo di determinati aspetti del runtime .NET e deve essere usato solo negli scenari in cui le dimensioni e le prestazioni dell'app sono importanti. Sarà necessario adattare le app ai requisiti di AOT nativi, assicurandosi che siano completamente tagliabili e compatibili con AOT. Per altre informazioni sulle limitazioni di AOT nativo, vedere Limitazioni di AOT nativo.

Quando la distribuzione AOT nativa è abilitata, il sistema di compilazione analizza il codice e tutte le relative dipendenze per verificare se è adatto per il taglio completo e la compilazione AOT. Se vengono rilevate incompatibilità, vengono generati avvisi di taglio e AOT. Un singolo avviso di taglio o AOT indica che l'app non è compatibile con la distribuzione AOT nativa e che potrebbe non funzionare correttamente. Pertanto, quando si compila un'app per la distribuzione AOT nativa, è necessario esaminare e correggere tutti gli avvisi di taglio e AOT. In caso contrario, potrebbero verificarsi eccezioni in fase di esecuzione perché il codice necessario potrebbe essere stato rimosso. Se si eliminano gli avvisi, l'app distribuita AOT deve essere testata accuratamente per verificare che la funzionalità non sia stata modificata dall'app non completata. Per altre informazioni, vedere Introduzione al taglio degli avvisi e Introduzione agli avvisi AOT.

Nota

In alcuni casi la correzione del taglio e gli avvisi AOT non sono possibili, ad esempio quando si verificano per librerie di terze parti. In questi casi, le librerie di terze parti dovranno essere aggiornate per diventare completamente compatibili.

Vantaggi delle prestazioni AOT nativi

La pubblicazione e la distribuzione di un'app AOT nativa genera in genere un'app di dimensioni inferiori fino a 2,5 volte e un'app che viene avviata in genere fino a 2 volte più veloce. Tuttavia, i vantaggi esatti delle prestazioni dipendono da più fattori che includono la piattaforma usata, il dispositivo in cui è in esecuzione l'app e l'app stessa.

Importante

I grafici seguenti mostrano i vantaggi tipici delle prestazioni della distribuzione nativa di AOT per un'app dotnet new maui in iOS e Mac Catalyst. Tuttavia, i dati esatti dipendono dall'hardware e possono cambiare nelle versioni future.

Il grafico seguente mostra le dimensioni del pacchetto dell'app per un'app dotnet new maui in iOS e Mac Catalyst in diversi modelli di distribuzione:

Grafico che mostra le dimensioni del pacchetto dell'app in diversi modelli di distribuzione.

Il grafico precedente mostra che, in genere, Native AOT produce più di 2x app più piccole per iOS e Mac Catalyst rispetto al modello di distribuzione predefinito.

Il grafico seguente mostra il tempo medio di avvio, su hardware specifico, per un'app dotnet new maui in iOS e Mac Catalyst in mono e distribuzione AOT nativa:

Grafico che mostra il tempo medio di avvio dell'app in Mono e native AOT.

Il grafico precedente mostra che Native AOT ha in genere fino a 2 volte più veloci tempi di avvio nei dispositivi iOS e 1.2x più veloce tempo di avvio in Mac Catalyst, rispetto alla distribuzione mono.

Il grafico seguente mostra il tempo medio di compilazione, su hardware specifico, per un'app dotnet new maui in iOS e Mac Catalyst in diversi modelli di distribuzione:

Grafico che mostra il tempo medio di compilazione delle app in Mono e AOT nativo.

Il grafico precedente mostra che in genere native AOT ha fino a 2,8 volte più veloci tempi di compilazione nei dispositivi iOS rispetto al modello di distribuzione predefinito. Per Mac Catalyst, i tempi di compilazione sono confrontabili per le app RID singole arm64, ma sono leggermente più lente per le app universali rispetto alla distribuzione mono.

Importante

In molti scenari L'AOT nativo produrrà app più piccole e veloci. In alcuni scenari, tuttavia, L'AOT nativo potrebbe non produrre app più piccole e veloci. È quindi importante testare e profilare l'app per determinare il risultato dell'abilitazione della distribuzione AOT nativa.

Pubblicare con AOT nativo

Il modello di distribuzione AOT nativo è abilitato con la proprietà di $(PublishAot) compilazione e il dotnet publish comando . L'esempio seguente illustra come modificare un file di progetto per abilitare la distribuzione AOT nativa in iOS e Mac Catalyst:

<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>

L'impostazione della proprietà di compilazione su true, per tutte le piattaforme, abilita l'eliminazione $(IsAotCompatible) e gli analizzatori AOT. Questi analizzatori consentono di identificare il codice non compatibile con il taglio o AOT.

Impostando $(PublishAot) in modo condizionale su true, per iOS e Mac Catalyst, consente l'analisi dinamica dell'utilizzo del codice durante la compilazione e la compilazione AOT nativa durante la pubblicazione. L'analisi AOT nativa include tutto il codice dell'app e tutte le librerie da cui dipende l'app.

Avviso

La $(PublishAot) proprietà di compilazione non deve essere condizionata dalla configurazione di compilazione. Ciò è dovuto al fatto che le opzioni delle funzionalità di taglio sono abilitate o disabilitate in base al valore della proprietà di $(PublishAot) compilazione e le stesse funzionalità devono essere abilitate o disabilitate in tutte le configurazioni di compilazione in modo che il codice si comporti in modo identico. Per altre informazioni sui commutatori di funzionalità di taglio, vedere Interruttori delle funzionalità di taglio.

L'unico modo per verificare che un'app AOT nativa funzioni correttamente consiste nel pubblicarla usando dotnet publish e verificare che non siano presenti avvisi di taglio o AOT generati dal codice e dalle relative dipendenze. In particolare, dotnet build -t:Publish non equivale a dotnet publish.

Usare il comando seguente dotnet publish per pubblicare l'app in iOS e Mac Catalyst usando la distribuzione AOT nativa:

# 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

Suggerimento

Pubblicare le app frequentemente per individuare problemi di taglio o AOT all'inizio del ciclo di vita dello sviluppo.

Limitazioni AOT native

AOT nativo introduce limitazioni sull'utilizzo di determinati aspetti del runtime .NET e deve essere usato solo negli scenari in cui le dimensioni e le prestazioni dell'app sono importanti. Sarà necessario adattare le app ai requisiti di AOT nativi, assicurandosi che siano completamente tagliabili e compatibili con AOT e questo può richiedere molto lavoro. Oltre alle limitazioni di .NET della distribuzione AOT nativa, la distribuzione AOT nativa per .NET MAUI presenta limitazioni aggiuntive.

Le librerie di terze parti da cui dipendono le app potrebbero non essere compatibili con AOT. L'unico modo per assicurarsi che una libreria stia tagliando e compatibile con AOT consiste nel pubblicare l'app usando la distribuzione AOT nativa e il dotnet publish comando e verificare se il compilatore AOT nativo genera avvisi per la libreria. Per informazioni sulla compatibilità con AOT delle librerie personalizzate, vedere How to make libraries compatible with native AOT (Come rendere compatibili le librerie con AOT nativo).

Reflection e codice dinamico

La distribuzione AOT nativa limita l'uso della reflection nel codice e delle relative dipendenze e può diventare necessario usare annotazioni per consentire al compilatore AOT nativo di comprendere i modelli di reflection. Quando il compilatore rileva un modello di reflection che non può analizzare in modo statico e quindi non può compilare l'app, genera avvisi di taglio. AOT nativo impedisce anche di usare codice dinamico nell'app. Ad esempio, la compilazione System.Linq.Expressions non funzionerà come previsto e non è possibile caricare ed eseguire assembly in fase di esecuzione. Quando il compilatore rileva un modello dinamico che non può essere compilato in anticipo, genererà un avviso AOT.

Nell'app .NET MAUI questo significa che:

  • Tutto il codice XAML deve essere compilato in anticipo. Assicurarsi quindi di non aver disabilitato la compilazione XAML e che tutte le associazioni siano compilate. Per altre informazioni, vedi Compilazione XAML e associazioni compilate.
  • Tutte le espressioni di associazione devono usare associazioni compilate, anziché un percorso di associazione impostato su una stringa. Per altre informazioni, vedere Binding compilati.
  • Gli operatori di conversione impliciti potrebbero non essere chiamati quando si assegna un valore di un tipo incompatibile a una proprietà in XAML o quando due proprietà di tipi diversi usano un data binding. È invece necessario definire un TypeConverter per il tipo e collegarlo al tipo usando .TypeConverterAttribute Per altre informazioni, vedere Definire un TypeConverter per sostituire un operatore di conversione implicita.
  • Non è possibile analizzare XAML in fase di esecuzione con il LoadFromXaml metodo . Anche se questa operazione può essere resa sicura annotando tutti i tipi che potrebbero essere caricati in fase di esecuzione con l'attributo o l'attributo DynamicallyAccessedMembers DynamicDependency questo è molto soggetto a errori e non è consigliato.
  • La ricezione dei dati di navigazione tramite QueryPropertyAttribute non funzionerà. È invece necessario implementare l'interfaccia IQueryAttributable sui tipi che devono accettare parametri di query. Per altre informazioni, vedere Elaborare i dati di navigazione usando un singolo metodo.
  • La SearchHandler.DisplayMemberName proprietà potrebbe non funzionare. È invece necessario fornire un oggetto ItemTemplate per definire l'aspetto dei SearchHandler risultati. Per altre informazioni, vedere Definire l'aspetto degli elementi dei risultati della ricerca.

Importante

L'interprete Mono non è compatibile con la distribuzione AOT nativa e pertanto le $(UseInterpreter) proprietà e $(MtouchInterpreter) MSBuild non hanno alcun effetto quando si usa Native AOT. Per altre informazioni sull'interprete Mono, vedere Interprete Mono in iOS e Mac Catalyst.

Per altre informazioni sugli avvisi di taglio, vedere Introduzione agli avvisi di taglio. Per altre informazioni sugli avvisi AOT, vedere Introduzione agli avvisi AOT.

Adattare un'app alla distribuzione AOT nativa

Usare l'elenco di controllo seguente per adattare l'app ai requisiti di distribuzione AOT nativi:

  • Assicurarsi che tutto XAML sia compilato:
    • Rimuovere tutti i [XamlCompilation(XamlCompilationOptions.Skip)] dati di utilizzo.
    • Rimuovere tutti i <?xaml-comp compile="false" ?> dati di utilizzo.
  • Rimuovere tutte le chiamate al LoadFromXaml metodo .
  • Assicurarsi che tutte le associazioni dati siano compilate. Per altre informazioni, vedere Binding compilati.
    • Assicurarsi che tutti i data binding XAML siano annotati con x:DataType.
    • Assicurarsi che tutti i data binding di codice sostituisci tutte le associazioni basate su stringa con associazioni basate su lambda.
  • Sostituire tutti gli [QueryProperty(...)] utilizzi con un'implementazione dell'interfaccia IQueryAttributable . Per altre informazioni, vedere Elaborare i dati di navigazione usando un singolo metodo.
  • Sostituire tutti gli SearchHandler.DisplayMemberName utilizzi con un oggetto ItemTemplate. Per altre informazioni, vedere Definire l'aspetto degli elementi dei risultati della ricerca.
  • Sostituire tutti gli operatori di conversione impliciti per i tipi usati in XAML con un TypeConverteroggetto e collegarlo al tipo usando .TypeConverterAttribute Per altre informazioni, vedere Definire un TypeConverter per sostituire un operatore di conversione implicita.
    • Quando si esegue la conversione dal tipo al tipo A B, verrà utilizzato il ConvertTo metodo in un convertitore di tipi associato A a oppure verrà utilizzato il ConvertFrom metodo in un convertitore di tipi associato a B .
    • Quando entrambi i tipi di origine e di destinazione hanno un convertitore di tipi associato, è possibile usarli entrambi.
  • Compilare tutte le espressioni regolari usando generatori di origine. Per altre informazioni, vedere Generatori di origini di espressioni regolari .NET.
  • Assicurarsi che la serializzazione e la deserializzazione JSON usino un contesto generato dall'origine. Per altre informazioni, vedere API minime e payload JSON.
  • Esaminare e correggere eventuali avvisi di taglio o AOT. Per altre informazioni, vedere Introduzione al taglio degli avvisi e Introduzione agli avvisi AOT.
  • Testare accuratamente l'app.

Supporto di diagnostica AOT nativo in iOS e Mac Catalyst

AOT nativo e Mono condividono un subset di funzionalità di diagnostica e strumentazione. A causa della gamma di strumenti di diagnostica di Mono, può essere utile diagnosticare ed eseguire il debug dei problemi all'interno di Mono anziché in AOT nativo. Le app tagliate e compatibili con AOT non devono presentare differenze comportamentali, quindi le indagini spesso si applicano a entrambi i runtime.

La tabella seguente illustra il supporto di diagnostica con Native AOT in iOS e Mac Catalyst:

Funzionalità supporto completo Parzialmente supportato Non supportato
Osservabilità e telemetria Parzialmente supportato
Diagnostica in fase di sviluppo Completamente supportato
Debug nativo Parzialmente supportato
Profilatura CPU Parzialmente supportato
Analisi dell'heap Non supportato

Le sezioni seguenti forniscono informazioni aggiuntive su questo supporto di diagnostica.

Osservabilità e telemetria

La traccia delle applicazioni MAUI .NET sulle piattaforme mobili è abilitata tramite dotnet-dsrouter che connette gli strumenti di diagnostica alle applicazioni .NET in esecuzione in iOS e Mac Catalyst su TCP/IP. Tuttavia, Native AOT non è attualmente compatibile con questo scenario perché non supporta i componenti EventPipe/DiagnosticServer compilati con lo stack TCP/IP. L'osservabilità è ancora raggiungibile in modo esplicito nel codice.

Diagnostica in fase di sviluppo

Gli strumenti dell'interfaccia della riga di comando di .NET forniscono comandi separati per build e publish. dotnet build (o Start Debugging (F5) in Visual Studio Code), usa Mono per impostazione predefinita durante la compilazione o l'avvio di applicazioni .NET MAUI iOS o Mac Catalyst. Verrà creata un'applicazione AOT nativa solo dotnet publish se questo modello di distribuzione è abilitato nel file di progetto.

Non tutti gli strumenti di diagnostica funzioneranno senza problemi con le applicazioni native AOT pubblicate. Tuttavia, tutte le applicazioni tagliate e compatibili con AOT (ovvero quelle che non generano avvisi trim e AOT in fase di compilazione) non devono avere differenze comportamentali tra Mono e AOT nativo. Pertanto, tutti gli strumenti di diagnostica in fase di sviluppo .NET, ad esempio Ricaricamento rapido, sono ancora disponibili per gli sviluppatori durante il ciclo di sviluppo di applicazioni per dispositivi mobili.

Suggerimento

È consigliabile sviluppare, eseguire il debug e testare l'applicazione come di consueto e pubblicare l'app finale con AOT nativo come uno degli ultimi passaggi.

Debug nativo

Quando si esegue l'applicazione .NET MAUI iOS o Mac Catalyst durante lo sviluppo, viene eseguita in Mono per impostazione predefinita. Tuttavia, se la distribuzione AOT nativa è abilitata nel file di progetto, è previsto che il comportamento sia lo stesso tra Mono e AOT nativo quando l'applicazione non genera alcun taglio e avvisi AOT in fase di compilazione. A condizione che l'applicazione soddisfi questo requisito, è possibile usare il motore di debug gestito standard di Visual Studio Code per lo sviluppo e il test,

Dopo la pubblicazione, le applicazioni native AOT sono veri file binari nativi e quindi il debugger gestito non funzionerà su di essi. Tuttavia, il compilatore AOT nativo genera file eseguibili completamente nativi che è possibile eseguire il debug con lldb. Il debug di un'app Mac Catalyst con lldb è semplice, perché viene eseguito nello stesso sistema. Tuttavia, il debug di applicazioni iOS NativeAOT richiede ulteriore impegno.

Eseguire il debug di applicazioni IOS MAUI .NET con AOT nativo

È possibile eseguire il debug delle applicazioni IOS .NET MAUI compatibili con Native AOT e che sono configurate e pubblicate correttamente con questo modello di distribuzione, come indicato di seguito:

  1. Pubblicare l'app con destinazione ios-arm64 AOT nativa e prendere nota delle informazioni seguenti:

    • Nome applicazione (a cui si fa riferimento di seguito come <app-name>).
    • Identificatore bundle (a cui si fa riferimento sotto come <bundle-identifier>).
    • Percorso del file con estensione ipa dell'archivio dell'applicazione pubblicata (a cui si fa riferimento sotto come <path-to-ipa>).
  2. Ottenere l'ID dispositivo fisico (indicato di seguito come <device-identifier>):

    xcrun devicectl list devices
    
  3. Installare l'app nel dispositivo fisico:

    xcrun devicectl device install app --device <device-identifier> <path-to-ipa>
    
  4. Avviare l'app nel dispositivo fisico:

    xcrun devicectl device process launch --device <device-identifier> --start-stopped <bundle-identifier>
    
  5. Aprire lldb e connettersi al dispositivo fisico:

    (lldb) device select <device-identifier>
    (lldb) device process attach -n <app-name>
    

Dopo aver completato correttamente questi passaggi, sarà possibile avviare il debug dell'applicazione IOS .NET AOT nativa con lldb.

Importanza del file di simboli

Per impostazione predefinita, i simboli di debug vengono rimossi dal file binario dell'applicazione in un file con estensione dSYM . Questo file viene usato dai debugger e dagli strumenti di analisi post mortem per visualizzare informazioni sulle variabili locali, i numeri di riga di origine e per ricreare le tracce dello stack dei dump di arresto anomalo del sistema. Pertanto, è essenziale conservare il file di simboli prima di inviare l'applicazione all'App Store.

Profilatura della CPU

Xcode Instruments può essere usato per raccogliere esempi di CPU di un'applicazione AOT nativa.

Analisi dell'heap

L'analisi dell'heap non è attualmente supportata con AOT nativo.

Vedi anche