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