Compartilhar via


Implantação de AOT nativa no iOS e Mac Catalyst

A implantação nativa do AOT produz um aplicativo .NET MAUI (interface do usuário do aplicativo multiplataforma) do .NET no iOS e no Mac Catalyst que foi compilado antecipadamente (AOT) para código nativo. O AOT nativo executa a análise estática do programa, o corte completo do seu aplicativo, que é agressivo na remoção de código que não é referenciado estaticamente e na geração antecipada de código.

A publicação e a implantação de um aplicativo AOT nativo produzem os seguintes benefícios:

  • Tamanho reduzido do pacote do aplicativo.
  • Tempo de inicialização mais rápido.
  • Tempo de construção mais rápido.

O AOT nativo introduzirá limitações no uso de determinados aspectos do runtime do .NET e só deve ser usado em cenários em que o tamanho e o desempenho do aplicativo são importantes. Isso exigirá que você adapte seus aplicativos aos requisitos nativos do AOT, o que significa garantir que eles sejam totalmente aparados e compatíveis com AOT. Para obter mais informações sobre as limitações do AOT nativo, consulte Limitações do AOT nativo.

Quando a implantação AOT nativa está habilitada, o sistema de build analisa seu código e todas as suas dependências para verificar se ele é adequado para corte completo e compilação AOT. Se forem detectadas incompatibilidades, serão produzidos avisos de corte e AOT. Um único aviso de corte ou AOT significa que o aplicativo não é compatível com a implantação do AOT nativo e que pode não funcionar corretamente. Portanto, ao criar um aplicativo para implantação de AOT nativo, você deve revisar e corrigir todos os avisos de corte e AOT. Não fazer isso pode resultar em exceções em tempo de execução, pois o código necessário pode ter sido removido. Se você suprimir os avisos, o aplicativo implantado AOT deverá ser testado minuciosamente para verificar se a funcionalidade não foi alterada em relação ao aplicativo não cortado. Para obter mais informações, consulte Introdução aos avisos de corte e Introdução aos avisos AOT.

Observação

Pode haver casos em que a correção de avisos de corte e AOT não seja possível, como quando eles ocorrem para bibliotecas de terceiros. Nesses casos, as bibliotecas de terceiros precisarão ser atualizadas para se tornarem totalmente compatíveis.

Benefícios de desempenho AOT nativos

A publicação e a implantação de um aplicativo AOT nativo produzem um aplicativo que normalmente é até 2,5 vezes menor e um aplicativo que é iniciado normalmente até 2 vezes mais rápido. No entanto, os benefícios exatos de desempenho dependem de vários fatores, que incluem a plataforma que está sendo usada, o dispositivo no qual o aplicativo está sendo executado e o próprio aplicativo.

Importante

Os gráficos a seguir mostram os benefícios típicos de desempenho da implantação do AOT nativo para um dotnet new maui aplicativo no iOS e no Mac Catalyst. No entanto, os dados exatos dependem do hardware e podem ser alterados em versões futuras.

O gráfico a seguir mostra o tamanho do pacote do aplicativo para um dotnet new maui aplicativo no iOS e no Mac Catalyst em diferentes modelos de implantação:

Gráfico mostrando o tamanho do pacote do aplicativo em diferentes modelos de implantação.

O gráfico anterior mostra que, normalmente, o AOT nativo produz aplicativos mais de 2 vezes menores para iOS e Mac Catalyst em comparação com o modelo de implantação padrão.

O gráfico a seguir mostra o tempo médio de inicialização, em hardware específico, para um dotnet new maui aplicativo no iOS e Mac Catalyst na implantação Mono e AOT nativa:

Gráfico mostrando o tempo médio de inicialização do aplicativo no Mono e no AOT nativo.

O gráfico anterior mostra que o AOT nativo normalmente tem tempos de inicialização até 2x mais rápidos em dispositivos iOS e tempo de inicialização 1,2x mais rápido no Mac Catalyst, em comparação com a implantação do Mono.

O gráfico a seguir mostra o tempo médio de compilação, em hardware específico, para um dotnet new maui aplicativo no iOS e no Mac Catalyst em diferentes modelos de implantação:

Gráfico mostrando o tempo médio de criação do aplicativo no Mono e no AOT nativo.

O gráfico anterior mostra que normalmente o AOT nativo tem tempos de build até 2,8 vezes mais rápidos em dispositivos iOS em comparação com o modelo de implantação padrão. Para o Mac Catalyst, os tempos de compilação são comparáveis para aplicativos RID únicos arm64, mas são um pouco mais lentos para aplicativos universais quando comparados à implantação do Mono.

Importante

Em muitos cenários, o AOT nativo produzirá aplicativos menores e mais rápidos. No entanto, em alguns cenários, o AOT nativo pode não produzir aplicativos menores e mais rápidos. Portanto, é importante testar e criar o perfil do seu aplicativo para determinar o resultado da habilitação da implantação do AOT nativo.

Publicar usando AOT nativo

O modelo de implantação AOT nativo é habilitado com a $(PublishAot) propriedade build e o dotnet publish comando. O exemplo a seguir mostra como modificar um arquivo de projeto para habilitar a implantação AOT nativa no 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>

Definir a $(IsAotCompatible) propriedade build como true, para todas as plataformas, habilita analisadores de corte e AOT. Esses analisadores ajudam a identificar o código que não é compatível com corte ou AOT.

A configuração $(PublishAot) condicional como true, para iOS e Mac Catalyst, permite a análise dinâmica do uso de código durante a compilação e a compilação AOT nativa durante a publicação. A análise AOT nativa inclui todo o código do aplicativo e todas as bibliotecas das quais o aplicativo depende.

Aviso

A $(PublishAot) propriedade build não deve ser condicionada pela configuração de build. Isso ocorre porque as opções de recursos de corte são habilitadas ou desabilitadas com base no valor da propriedade de build, e os $(PublishAot) mesmos recursos devem ser habilitados ou desabilitados em todas as configurações de build para que seu código se comporte de forma idêntica. Para obter mais informações sobre como aparar opções de recursos, consulte Chaves de recursos de corte.

A única maneira de verificar se um aplicativo AOT nativo funciona corretamente é publicá-lo usando dotnet publish e verificar se não há avisos de corte ou AOT produzidos pelo seu código e suas dependências. Em particular, dotnet build -t:Publish não é equivalente a dotnet publish.

Use o seguinte dotnet publish comando para publicar seu aplicativo no iOS e no Mac Catalyst usando a implantação 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

Dica

Publique aplicativos com frequência para descobrir problemas de corte ou AOT no início do ciclo de vida de desenvolvimento.

Limitações nativas do AOT

O AOT nativo introduzirá limitações no uso de determinados aspectos do runtime do .NET e só deve ser usado em cenários em que o tamanho e o desempenho do aplicativo são importantes. Isso exigirá que você adapte seus aplicativos aos requisitos de AOT nativo, o que significa garantir que eles sejam totalmente aparados e compatíveis com AOT, e isso pode exigir muito trabalho. Além das limitações do .NET da implantação do AOT nativo, a implantação do AOT nativo para o .NET MAUI tem limitações adicionais.

As bibliotecas de terceiros das quais seus aplicativos dependem podem não ser compatíveis com AOT. A única maneira de garantir que uma biblioteca seja cortada e compatível com AOT é publicar seu aplicativo usando a implantação do AOT nativo e o dotnet publish comando e ver se o compilador AOT nativo produz avisos para a biblioteca. Para obter informações sobre como tornar suas próprias bibliotecas compatíveis com AOT, consulte Como tornar bibliotecas compatíveis com AOT nativo.

Reflexão e código dinâmico

A implantação do AOT nativo limita o uso de reflexão em seu código e suas dependências, e pode ser necessário usar anotações para ajudar o compilador AOT nativo a entender os padrões de reflexão. Quando o compilador encontra um padrão de reflexão, ele não pode analisar estaticamente e, portanto, não pode criar o aplicativo, ele produz avisos de corte. O AOT nativo também impede que você use código dinâmico em seu aplicativo. Por exemplo, a compilação System.Linq.Expressions não funcionará conforme o esperado e não é possível carregar e executar assemblies em runtime. Quando o compilador encontra um padrão dinâmico que não pode compilar antecipadamente, ele produzirá um aviso AOT.

No aplicativo .NET MAUI, isso significa que:

Importante

O interpretador Mono não é compatível com a implantação do AOT nativo e, portanto, as propriedades e $(UseInterpreter) do MSBuild não têm efeito ao usar o $(MtouchInterpreter) AOT nativo. Para obter mais informações sobre o interpretador Mono, consulte Interpretador Mono no iOS e Mac Catalyst.

Para obter mais informações sobre avisos de corte, consulte Introdução aos avisos de corte. Para obter mais informações sobre avisos AOT, consulte Introdução aos avisos AOT.

Adaptar um aplicativo à implantação de AOT nativa

Use a lista de verificação a seguir para ajudá-lo a adaptar seu aplicativo aos requisitos de implantação do AOT nativo:

  • Verifique se todo o XAML está compilado:
    • Remova todo o [XamlCompilation(XamlCompilationOptions.Skip)] uso.
    • Remova todo o <?xaml-comp compile="false" ?> uso.
  • Remova todas as chamadas para o LoadFromXaml método.
  • Verifique se todas as associações de dados são compiladas. Para obter mais informações, confira Associações compiladas.
    • Verifique se todas as associações de dados XAML são anotadas com x:DataType.
    • Certifique-se de que todas as associações de dados de código substituam todas as associações baseadas em cadeia de caracteres por associações baseadas em lambda.
  • Substitua o uso da extensão de marcação XAML OnPlatform por uma implementação que usa a classe OnPlatform<T>. Para obter mais informações, consulte Personalizar a aparência da interface do usuário com base noda plataforma.
  • Substitua todo o uso da extensão de marcação OnIdiom XAML por uma implementação que usa a classe OnIdiom<T>. Para obter mais informações, consulte Personalizar a aparência da interface do usuário com base node idioma do dispositivo.
  • Substitua todo [QueryProperty(...)] o uso por uma implementação da IQueryAttributable interface. Para obter mais informações, confira Processar os dados de navegação usando um só método.
  • Substitua todo o SearchHandler.DisplayMemberName uso por um ItemTemplate. Para obter mais informações, consulte Definir a aparência do item de resultados da pesquisa.
  • Substitua todos os operadores de conversão implícitos para tipos usados em XAML por um TypeConverter, e anexe-o ao seu tipo usando o TypeConverterAttribute. Para obter mais informações, consulte Definir um TypeConverter para substituir um operador de conversão implícito.
    • Ao converter de tipo A para tipo B, o ConvertTo método em um conversor de tipo associado a A será usado ou o ConvertFrom método em um conversor de tipo associado a B será usado.
    • Quando os tipos de origem e de destino têm um conversor de tipo associado, qualquer um deles pode ser usado.
  • Compile todas as expressões regulares usando geradores de código-fonte. Para obter mais informações, confira Geradores de origem de expressão regular do .NET.
  • Verifique se a serialização e a desserialização JSON usam um contexto gerado pela origem. Para obter mais informações, consulte APIs mínimas e cargas JSON.
  • Revise e corrija quaisquer avisos de corte ou AOT. Para obter mais informações, consulte Introdução aos avisos de corte e Introdução aos avisos AOT.
  • Teste completamente seu aplicativo.

Suporte nativo ao diagnóstico AOT no iOS e Mac Catalyst

AOT e Mono nativos compartilham um subconjunto de recursos de diagnóstico e instrumentação. Devido à variedade de ferramentas de diagnóstico do Mono, pode ser benéfico diagnosticar e depurar problemas no Mono em vez do AOT nativo. Os aplicativos que são aparados e compatíveis com AOT não devem ter diferenças comportamentais, portanto, as investigações geralmente se aplicam a ambos os tempos de execução.

A tabela a seguir mostra o suporte de diagnóstico com AOT nativo no iOS e Mac Catalyst:

Recurso Suporte total Suporte parcial Sem suporte
Observabilidade e telemetria Parcialmente compatível
Diagnóstico em tempo de desenvolvimento Totalmente compatível
Depuração nativa Parcialmente compatível
Criação de perfil da CPU Parcialmente compatível
Análise de heap Sem suporte

As seções a seguir fornecem informações adicionais sobre esse suporte de diagnóstico.

Observabilidade e telemetria

O rastreamento de aplicativos .NET MAUI em plataformas móveis é habilitado por meio de dotnet-dsrouter , que conecta ferramentas de diagnóstico a aplicativos .NET em execução no iOS e Mac Catalyst, por TCP/IP. No entanto, o AOT nativo atualmente não é compatível com esse cenário, pois não dá suporte a componentes EventPipe/DiagnosticServer criados com a pilha TCP/IP. A observabilidade ainda pode ser alcançada explicitamente no código.

Diagnóstico em tempo de desenvolvimento

As ferramentas da CLI do .NET fornecem comandos separados para build e publish. dotnet build (ou Start Debugging (F5) no Visual Studio Code), usa o Mono por padrão ao criar ou iniciar aplicativos .NET MAUI iOS ou Mac Catalyst. Só dotnet publish criará um aplicativo AOT nativo, se esse modelo de implantação estiver habilitado no arquivo de projeto.

Nem todas as ferramentas de diagnóstico funcionarão perfeitamente com aplicativos AOT nativos publicados. No entanto, todos os aplicativos compatíveis com corte e AOT (ou seja, aqueles que não produzem nenhum aviso de corte e AOT no momento da compilação) não devem ter diferenças comportamentais entre o Mono e o AOT nativo. Portanto, todas as ferramentas de diagnóstico de tempo de desenvolvimento do .NET, como Recarga Dinâmica, ainda estão disponíveis para desenvolvedores durante o ciclo de desenvolvimento de aplicativos móveis.

Dica

Você deve desenvolver, depurar e testar seu aplicativo como de costume e publicar seu aplicativo final com AOT nativo como uma das últimas etapas.

Depuração nativa

Quando você executa seu aplicativo .NET MAUI iOS ou Mac Catalyst durante o desenvolvimento, ele é executado no Mono por padrão. No entanto, se a implantação do AOT nativo estiver habilitada no arquivo de projeto, espera-se que o comportamento seja o mesmo entre o Mono e o AOT nativo quando o aplicativo não estiver produzindo nenhum aviso de corte e AOT no momento do build. Desde que seu aplicativo atenda a esse requisito, você pode usar o mecanismo de depuração gerenciado padrão do Visual Studio Code para desenvolvimento e teste,

Após a publicação, os aplicativos AOT nativos são binários nativos verdadeiros e, portanto, o depurador gerenciado não funcionará neles. No entanto, o compilador AOT nativo gera arquivos executáveis totalmente nativos que você pode depurar com lldbo . A depuração de um aplicativo Mac Catalyst é lldb direta, pois é executada no mesmo sistema. No entanto, a depuração de aplicativos iOS NativeAOT requer esforço adicional.

Depurar aplicativos iOS .NET MAUI com AOT nativo

Os aplicativos iOS do .NET MAUI compatíveis com AOT nativo e configurados e publicados corretamente com esse modelo de implantação podem ser depurados da seguinte maneira:

  1. Publique seu aplicativo com segmentação ios-arm64 AOT nativa e observe as seguintes informações:

    • Nome do aplicativo (referenciado abaixo como <app-name>).
    • Identificador de pacote (referenciado abaixo como <bundle-identifier>).
    • Caminho para o arquivo .ipa do aplicativo publicado (referenciado abaixo como <path-to-ipa>).
  2. Obtenha a ID do seu dispositivo físico (referenciada abaixo como <device-identifier>):

    xcrun devicectl list devices
    
  3. Instale o aplicativo em seu dispositivo físico:

    xcrun devicectl device install app --device <device-identifier> <path-to-ipa>
    
  4. Inicie o aplicativo em seu dispositivo físico:

    xcrun devicectl device process launch --device <device-identifier> --start-stopped <bundle-identifier>
    
  5. Abra lldb e conecte-se ao seu dispositivo físico:

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

Depois de concluir essas etapas com êxito, você poderá começar a depurar seu aplicativo iOS Native AOT .NET MAUI com lldbo .

Importância do arquivo de símbolo

Por padrão, os símbolos de depuração são removidos do arquivo binário do aplicativo para um arquivo .dSYM . Esse arquivo é usado por depuradores e ferramentas de análise post mortem para mostrar informações sobre variáveis locais, números de linha de origem e para recriar rastreamentos de pilha de despejos de memória. Portanto, é essencial preservar o arquivo de símbolo antes de enviar sua inscrição para a App Store.

Criação de perfil da CPU

O Xcode Instruments pode ser usado para coletar amostras de CPU de um aplicativo AOT nativo.

Análise de heap

No momento, não há suporte para a análise de heap com o AOT nativo.

Confira também