Partilhar via


Interpretador Mono no iOS e no Mac Catalyst

Quando você compila um aplicativo .NET Multi-Platform App UI (.NET MAUI) para iOS ou Mac Catalyst, o compilador transforma o código do aplicativo em Microsoft Intermediate Language (MSIL). Quando você executa o aplicativo iOS no simulador ou o aplicativo Mac Catalyst, o .NET Common Language Runtime (CLR) compila o MSIL usando um compilador Just in Time (JIT). No runtime, o MSIL é compilado em código nativo, que pode ser executado na arquitetura correta para seu aplicativo.

No entanto, há uma restrição de segurança no iOS, definida pela Apple, que não permite a execução do código gerado dinamicamente em um dispositivo. Da mesma forma, a execução de código gerado dinamicamente não é permitida em aplicativos iOS executados na arquitetura ARM64 no simulador e em aplicativos Mac Catalyst executados na arquitetura ARM64. Para atender a essa restrição, os aplicativos iOS e Mac Catalyst utilizam um compilador AOT (Ahead of Time) para compilar o código gerenciado. Isso produz um binário nativo do iOS que pode ser implantado em dispositivos Apple ou um binário nativo do Mac Catalyst.

O AOT oferece benefícios por meio de uma redução no tempo de inicialização e várias outras otimizações de desempenho. No entanto, ele também restringe o uso de determinados recursos em seu aplicativo:

  • O suporte a genéricos é limitado. Nem todas as instanciações genéricas possíveis podem ser determinadas no momento da compilação. Muitos dos problemas específicos do iOS encontrados nas compilações de versão do .NET MAUI se devem a essa limitação.
  • A geração de código dinâmico não é permitida. Isso significa que System.Relection.Emit não está disponível, não há suporte para System.Runtime.Remoting e alguns usos do tipo C# dinâmico não são permitidos.

Quando ocorre uma restrição de AOT, um System.ExecutionEngineException será gerado com a mensagem "Tentativa de compilar o método JIT durante a execução no modo somente AOT".

O interpretador Mono supera essas restrições e, ao mesmo tempo, obedece às restrições da plataforma. Ele permite que você interprete algumas partes do seu aplicativo em runtime, enquanto o AOT compila o restante. No entanto, há algumas possíveis desvantagens em usar o interpretador em um aplicativo de produção:

  • Embora o tamanho do aplicativo geralmente diminua significativamente quando o interpretador está habilitado, em certos casos, o tamanho do aplicativo pode aumentar.
  • A velocidade de execução do aplicativo será mais lenta porque o código interpretado é executado mais lentamente do que o código compilado pelo AOT. Essa redução da velocidade de execução pode variar de não mensurável a inaceitável, portanto, devem ser realizados testes de desempenho.
  • Os rastreamentos de pilha nativos nos relatórios de falhas tornam-se menos úteis, pois conterão quadros genéricos do interpretador que não mencionam o código que está sendo executado. Entretanto, os rastreamentos de pilha gerenciados não serão alterados.

O interpretador é habilitado por padrão para compilações de depuração do .NET MAUI e pode ser habilitado para compilações de versão.

Dica

Se o seu aplicativo iOS .NET MAUI ou o aplicativo Mac Catalyst ARM64-based funcionar corretamente como uma compilação de depuração, mas depois falhar como uma compilação de versão, tente habilitar o interpretador para a compilação de versão do aplicativo. Pode ser que seu aplicativo, ou uma de suas bibliotecas, use um recurso que exija o interpretador.

Habilitar o interpretador

O interpretador Mono pode ser habilitado nas compilações de versão do iOS definindo a propriedade $(UseInterpreter) MSBuild para true no arquivo de projeto do seu aplicativo .NET MAUI:

<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
    <UseInterpreter>true</UseInterpreter>
</PropertyGroup>

O interpretador também pode ser habilitado para compilações de versão do Mac Catalyst no ARM64:

<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
    <UseInterpreter>true</UseInterpreter>
</PropertyGroup>

Aviso

Não habilite o interpretador para compilações de versão no Android porque ele desabilita a compilação JIT.

No iOS e no Mac Catalyst, o interpretador também pode ser habilitado com a propriedade $(MtouchInterpreter) MSBuild. Opcionalmente, essa propriedade recebe uma lista separada por vírgulas de assemblies a serem interpretados. Além disso, all pode ser usada para especificar todos os assemblies e, quando prefixada com um sinal de menos, um assembly será compilado pelo AOT. Isso permite:

  • Interprete todos os assemblies especificando all ou compile tudo com AOT especificando -all.
  • Interprete os assemblies individuais especificando MyAssembly ou compile os assemblies individuais com o AOT especificando -MyAssembly.
  • Misture e corresponda para interpretar alguns assemblies e compilar outros assemblies com o AOT.

Aviso

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

O exemplo a seguir mostra como interpretar todos os assemblies, exceto System.Xml.dll:

<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
    <!-- Interpret everything, except System.Xml.dll -->
    <MtouchInterpreter>all,-System.Xml</MtouchInterpreter>
</PropertyGroup>

O exemplo a seguir mostra como compilar por AOT todos os assemblies, exceto System.Numerics.dll:

<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
    <!-- AOT everything, except System.Numerics.dll, which will be interpreted -->
    <MtouchInterpreter>-all,System.Numerics</MtouchInterpreter>
</PropertyGroup>

Importante

Um registro de ativação executado pelo interpretador não fornecerá informações úteis. No entanto, como o interpretador pode ser desabilitado por montagem, é possível ter quadros de pilha de algumas montagens descritos com precisão nos relatórios de falhas.

Como alternativa, use o exemplo a seguir para compilar todos os assemblies com AOT e, ao mesmo tempo, permitir que o interpretador execute a geração de código dinâmico:

<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
    <MtouchInterpreter>-all</MtouchInterpreter>
</PropertyGroup>

Outro cenário comum em que o interpretador às vezes é necessário é um aplicativo .NET MAUI Mac Catalyst em execução na arquitetura ARM64, que pode gerar uma exceção na inicialização. Essa exceção de inicialização geralmente pode ser corrigida habilitando o interpretador:

<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
    <MtouchInterpreter>-all,MyAssembly</MtouchInterpreter>
</PropertyGroup>