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:

  • Todo o XAML precisa ser compilado antecipadamente. Portanto, verifique se você não desabilitou a compilação XAML e se todas as associações foram compiladas. Para obter mais informações, consulte Compilação XAML e Associações compiladas.
  • Todas as expressões de associação devem usar associações compiladas, em vez de um caminho de associação definido como uma cadeia de caracteres. Para obter mais informações, confira Associações compiladas.
  • Os operadores de conversão implícitos podem não ser chamados ao atribuir um valor de um tipo incompatível a uma propriedade em XAML ou quando duas propriedades de tipos diferentes usam uma associação de dados. Em vez disso, você deve definir a TypeConverter para o seu tipo e anexá-lo ao tipo usando o TypeConverterAttribute. Para obter mais informações, consulte Definir um TypeConverter para substituir um operador de conversão implícito.
  • Não é possível analisar XAML em runtime com o LoadFromXaml método. Embora isso possa ser feito com segurança de corte anotando todos os tipos que podem ser carregados em runtime com o DynamicallyAccessedMembers atributo ou o DynamicDependency atributo, isso é muito propenso a erros e não é recomendado.
  • Receber dados de navegação usando o QueryPropertyAttribute não funcionará. Em vez disso, você deve implementar a IQueryAttributable interface em tipos que precisam aceitar parâmetros de consulta. Para obter mais informações, confira Processar os dados de navegação usando um só método.
  • A SearchHandler.DisplayMemberName propriedade pode não funcionar. Em vez disso, você deve fornecer um ItemTemplate para definir a aparência dos resultados SearchHandler. Para obter mais informações, consulte Definir a aparência do item de resultados da pesquisa.

Importante

O interpretador Mono não é compatível com a implantação do AOT nativo e, portanto, as propriedades e $(MtouchInterpreter) do MSBuild não têm efeito ao usar o $(UseInterpreter) 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 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.

Confira também