Interpréteur Mono sur iOS et Mac Catalyst
Lorsque vous compilez une application .NET Multi-Platform App UI (.NET MAUI) pour iOS ou Mac Catalyst, le compilateur transforme le code de votre application en Microsoft Intermediate Language (MSIL). Lorsque vous exécutez l’application iOS dans le simulateur ou l’application Mac Catalyst, le common language runtime (CLR) .NET compile le MSIL en utilisant un compilateur juste-à-temps (JIT). Au moment du runtime, le MSIL est compilé en code natif qui peut s’exécuter sur l’architecture appropriée pour votre application.
Toutefois, il existe une restriction de sécurité sur iOS, définie par Apple, qui interdit l’exécution de code généré dynamiquement sur des appareils. De la même façon, l’exécution du code généré dynamiquement est interdite dans les applications iOS s’exécutant sur l’architecture ARM64 dans le simulateur et sur les applications Mac Catalyst s’exécutant sur l’architecture ARM64. Pour respecter cette restriction, les applications iOS et Mac Catalyst utilisent un compilateur Ahead Of Time (AOT) pour compiler le code managé. Cette opération produit un binaire iOS natif pouvant être déployé sur des appareils Apple ou un binaire Mac Catalyst natif.
AOT offre des avantages via une réduction du temps de démarrage et diverses autres optimisations des performances. Toutefois, il limite également l’utilisation de certaines fonctionnalités dans votre application :
- Il existe une prise en charge limitée des génériques. Les instanciations génériques possible ne peuvent pas toutes être déterminées lors de la compilation. Plusieurs des problèmes spécifiques à iOS rencontrés dans les builds de version .NET MAUI sont attribuables à cette limitation.
- La génération de code dynamique n’est pas autorisée. Cela signifie que
System.Relection.Emit
n’est pas disponible, qu’il n’existe aucune prise en charge pourSystem.Runtime.Remoting
et que certaines utilisations du type dynamique de C# ne sont pas permises.
Lorsqu’une limitation d’AOT se produit, une System.ExecutionEngineException
est levée avec un message « Tentative de méthode de compilation JIT pendant l’exécution en mode AOT uniquement ».
L’interpréteur Mono surmonte ces limitations tout en se conformant aux limitations de la plateforme. Il vous permet d’interpréter certains éléments de votre application au moment du runtime pendant la compilation du reste par AOT. Cependant, il existe des inconvénients éventuels de l’utilisation de l’interpréteur dans une application de production :
- Bien que la taille de l’application se réduise considérablement quand l’interpréteur est activé, elle peut augmenter dans certains cas.
- La vitesse d’exécution de l’application sera plus lente, car le code interprété s’exécute plus lentement que le code AOT compilé. Cette réduction de vitesse d’exécution peut varier de non mesurable à inacceptable et vous devez donc effectuer un test de performances.
- Les traces de pile natives des rapport d’incident deviennent moins utiles, car elles contiennent des images génériques de l’interpréteur qui ne mentionnent pas le code en cours d’exécution. Toutefois, les traces de pile managées ne changent pas.
L’interpréteur est activé par défaut pour les builds de débogage .NET MAUI et vous pouvez l’activer pour les builds de mise en production.
Conseil
Si votre application .NET MAUI iOS ou votre application Mac Catalyst basé sur ARM64 fonctionne correctement comme build de débogage, puis se bloque comme build de mise en production, essayez d’activer l’interpréteur pour la build de mise en production de votre application. Il se peut que votre application, ou l’une de ses bibliothèques, utilise une fonctionnalité qui nécessite l’interpréteur.
Activer l’interpréteur
Vous pouvez activer l’interpréteur Mono dans des builds de mise en production iOS en définissant la $(UseInterpreter)
propriété MSBuild sur la valeur true
dans le fichier projet de votre application .NET MAUI :
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<UseInterpreter>true</UseInterpreter>
</PropertyGroup>
Vous pouvez également activer l’interpréteur pour des builds de mise en production Mac Catalyst sur ARM64 :
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
<UseInterpreter>true</UseInterpreter>
</PropertyGroup>
Avertissement
N’activez pas l’interpréteur pour des builds de mise en production sur Android, car il désactive la compilation JIT.
Sur iOS et Mac Catalyst, vous pouvez également activer l’interpréteur avec la propriété MSBuild $(MtouchInterpreter)
. Cette propriété prend en option une liste séparée par des virgules d’assemblys à interpréter. En outre, vous pouvez utiliser all
pour spécifier tous les assemblys et, s’ils sont précédés du préfixe de signe moins, ils sont compilés AOT. Vous pouvez ainsi effectuer les opérations suivantes :
- Interprétez tous les assemblys en spécifiant
all
ou compilez AOT la totalité en spécifiant-all
. - Interprétez des assemblys individuels en spécifiant MyAssembly ou effectuez une compilation AOA des assemblys individuels en spécifiant -MyAssembly.
- Combinez pour interpréter certains assemblys et compiler AOT d’autres assemblys.
Avertissement
L’interpréteur n’est pas compatible avec le déploiement AOT natif. Par conséquent, les propriétés MSBuild et $(MtouchInterpreter)
MSBuild n’ont aucun effet lors de l’utilisation $(UseInterpreter)
d’AOT natif. Pour plus d’informations, consultez Déploiement AOT natif.
L’exemple suivant montre comment interpréter tous les assemblys à l’exception de System.Xml.dll :
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<!-- Interpret everything, except System.Xml.dll -->
<MtouchInterpreter>all,-System.Xml</MtouchInterpreter>
</PropertyGroup>
L’exemple suivant montre comment compiler AOT tous les assemblys à l’exception de 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>
Important
Une image de pile exécutée par l’interpréteur ne peut pas offrir d’informations utiles. Cependant, du fait que vous pouvez désactiver l’interpréteur par assembly, il est possible d’obtenir des images de pile de quelques assemblys correctement illustrées dans des rapports d’incident.
Vous pouvez également utiliser l’exemple suivant pour compiler AOT tous les assemblys tout en autorisant l’interpréteur à effectuer une génération de code dynamique :
<PropertyGroup Condition="$(TargetFramework.Contains('-ios')) and '$(Configuration)' == 'Release'">
<MtouchInterpreter>-all</MtouchInterpreter>
</PropertyGroup>
L’autre scénario courant dans lequel l’interpréteur est parfois nécessaire correspond à une application .NET MAUI Mac Catalyst s’exécutant sur l’architecture ARM64 qui peut lever une exception au lancement. Vous pouvez souvent corriger cette exception de lancement en activant l’interpréteur :
<PropertyGroup Condition="'$(RuntimeIdentifier)' == 'maccatalyst-arm64' and '$(Configuration)' == 'Release'">
<MtouchInterpreter>-all,MyAssembly</MtouchInterpreter>
</PropertyGroup>