Intérprete mono en iOS y Mac Catalyst
Al compilar una aplicación .NET Multi-Platform App UI (.NET MAUI) para iOS o Mac Catalyst, el compilador convierte el código de la aplicación en Lenguaje Intermedio de Microsoft (MSIL). Al ejecutar la aplicación iOS en el simulador, o la aplicación Mac Catalyst, Common Language Runtime (CLR) de .NET compila el MSIL mediante un compilador Just-In-Time (JIT). En tiempo de ejecución, MSIL se compila en código nativo, que se puede ejecutar en la arquitectura correcta para la aplicación.
Sin embargo, hay una restricción de seguridad en iOS, establecida por Apple, que no permite la ejecución de código generado dinámicamente en un dispositivo. Del mismo modo, la ejecución de código generado dinámicamente no se permite en las aplicaciones iOS que se ejecutan en la arquitectura ARM64 en el simulador ni en las aplicaciones Mac Catalyst que se ejecutan en la arquitectura ARM64. Para cumplir esta restricción, las aplicaciones iOS y Mac Catalyst usan un compilador Ahead of Time (AOT) para compilar el código administrado. Esto genera un binario nativo de iOS que se puede implementar en dispositivos Apple o un binario nativo de Mac Catalyst.
AOT proporciona ventajas a través de una reducción del tiempo de inicio y otras optimizaciones del rendimiento. Pero también restringe ciertas características en la aplicación:
- La compatibilidad con genéricos es limitada. No todas las instancias posibles de genéricos se pueden determinar en tiempo de compilación. Muchos de los problemas específicos de iOS detectados en las compilaciones de versión de .NET MAUI se deben a esta limitación.
- No se permite la generación dinámica de código. Esto significa que
System.Relection.Emit
no está disponible, no hay compatibilidad conSystem.Runtime.Remoting
y algunos usos del tipo dinámico de C# no están permitidos.
Cuando se produzca una restricción AOT, se lanzará una System.ExecutionEngineException
con un mensaje que indica que se está intentando el método de compilación JIT mientras se ejecuta en modo de solo AOT.
El intérprete mono supera estas restricciones al tiempo que cumple las restricciones de la plataforma. Permite interpretar algunas partes de la aplicación en tiempo de ejecución, mientras se realiza una compilación AOT en el resto. Sin embargo, el uso del intérprete en una aplicación de producción puede tener algunas desventajas:
- Aunque el tamaño de la aplicación se suele reducir significativamente cuando el intérprete está habilitado, el tamaño de la aplicación puede aumentar en determinados casos.
- La velocidad de ejecución de la aplicación será más lenta porque el código interpretado se ejecuta más lentamente que el código compilado de AOT. Esta reducción de la velocidad de ejecución puede variar de un nivel incalculable a uno inaceptable, por lo que se deben realizar pruebas de rendimiento.
- Los seguimientos de pila nativa en informes de bloqueo resultan menos útiles, ya que contendrán marcos genéricos del intérprete que no mencionan el código que se está ejecutando. Sin embargo, los seguimientos de pila administrada no cambiarán.
El intérprete está habilitado de forma predeterminada para las compilaciones de depuración de .NET MAUI y se puede habilitar para las compilaciones de versión.
Sugerencia
Si la aplicación iOS de .NET MAUI o la aplicación Mac Catalyst basada en ARM64 funciona correctamente como una compilación de depuración, pero luego se bloquea como compilación de versión, intenta habilitar el intérprete para la compilación de versión de la aplicación. Puede ser que la aplicación, o una de sus bibliotecas, use una característica que requiera el intérprete.
Habilitación del intérprete
El intérprete mono se puede habilitar en compilaciones de versión iOS estableciendo la propiedad de MSBuild $(UseInterpreter)
en true
en el archivo del proyecto de la aplicación .NET MAUI:
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<UseInterpreter>true</UseInterpreter>
</PropertyGroup>
El intérprete también se puede habilitar para las compilaciones de versión de Mac Catalyst en ARM64:
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
<UseInterpreter>true</UseInterpreter>
</PropertyGroup>
Advertencia
No habilite el intérprete para las compilaciones de versión en Android porque deshabilita la compilación JIT.
En iOS y Mac Catalyst, el intérprete también se puede habilitar con la propiedad de MSBuild $(MtouchInterpreter)
. Esta propiedad toma opcionalmente una lista separada por comas de ensamblados que se van a interpretar. Además, all
se puede usar para especificar todos los ensamblados y, cuando lleva como prefijo un signo menos, un ensamblado experimentará una compilación AOT. Esto le permite:
- Interpretar todos los ensamblados especificando
all
o realizar una compilación AOT de todo especificando-all
. - Interpreta los ensamblados individuales especificando MyAssembly o ensamblados individuales de compilación AOT especificando -MyAssembly.
- Mezclar y combinar para interpretar algunos ensamblados y realizar una compilación AOT de otros ensamblados.
Advertencia
El intérprete no es compatible con la implementación de AOT nativa y, por tanto, las $(UseInterpreter)
propiedades y $(MtouchInterpreter)
de MSBuild no tienen ningún efecto al usar AOT nativo. Para más información, consulte Implementación con AOT nativa.
En el ejemplo siguiente se muestra cómo interpretar todos los ensamblados excepto System.Xml.dll:
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<!-- Interpret everything, except System.Xml.dll -->
<MtouchInterpreter>all,-System.Xml</MtouchInterpreter>
</PropertyGroup>
En el ejemplo siguiente se muestra cómo realizar una compilación AOT en todos los ensamblados excepto 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
Un marco de pila ejecutado por el intérprete no proporcionará información útil. Sin embargo, dado que el intérprete se puede deshabilitar por ensamblado, es posible tener marcos de pilas de algunos ensamblados que se muestran con precisión en los informes de bloqueos.
Como alternativa, usa el ejemplo siguiente para realizar una compilación AOT de todos los ensamblados, mientras permites al intérprete realizar la generación dinámica de código:
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<MtouchInterpreter>-all</MtouchInterpreter>
</PropertyGroup>
Otro escenario común en el que a veces se requiere el intérprete es una aplicación Mac Catalyst de .NET MAUI que se ejecuta en la arquitectura ARM64, que puede producir una excepción al iniciarse. Esta excepción de inicio se puede corregir a menudo habilitando el intérprete:
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
<MtouchInterpreter>-all,MyAssembly</MtouchInterpreter>
</PropertyGroup>