Adiós a Mono en .NET MAUI: qué cambia con CoreCLR en .NET 11

Durante años, desarrollar aplicaciones móviles con C# ha significado convivir con dos mundos dentro de .NET. El backend, las aplicaciones de escritorio y los servicios en la nube utilizaban CoreCLR, mientras que Android, iOS y Mac Catalyst seguían ejecutándose sobre Mono. En .NET 11 esa separación empieza a desaparecer: CoreCLR pasa a ser el runtime predeterminado de .NET MAUI también en las plataformas móviles.

El cambio es importante, pero conviene interpretarlo bien. No significa que tengamos que reescribir la interfaz ni abandonar XAML, los handlers o nuestras bibliotecas habituales. Lo que cambia está más abajo: es el motor que ejecuta el código administrado, gestiona la memoria, compila métodos y proporciona herramientas de diagnóstico.

Mono fue la pieza que hizo posible .NET en móviles

Hablar de esta transición como si Mono hubiera sido un error sería injusto. Mono llevó C# a entornos donde originalmente .NET no podía ejecutarse. De MonoTouch y MonoDroid nacieron Xamarin.iOS y Xamarin.Android; más tarde, esa experiencia se convirtió en una parte esencial de .NET MAUI.

Mientras tanto, CoreCLR evolucionó como runtime principal para servidores, escritorio y nube. Mantener dos runtimes permitía atender las restricciones particulares de cada plataforma, pero también creaba diferencias en el recolector de basura, el comportamiento del JIT, las herramientas de diagnóstico y algunos errores difíciles de reproducir fuera del dispositivo.

Con .NET 11, Android, iOS, Mac Catalyst y tvOS son las últimas plataformas de MAUI que pasan a CoreCLR. Windows ya utilizaba este runtime. Blazor WebAssembly queda fuera del cambio y continúa sobre Mono.

Qué cambia en un proyecto .NET MAUI

A partir de .NET 11 Preview 4, una aplicación MAUI dirigida a Android, iOS o Mac Catalyst utiliza CoreCLR por defecto tanto en Debug como en Release. El cambio básico en el proyecto consiste en apuntar a los nuevos target frameworks:

<TargetFrameworks>
  net11.0-android;
  net11.0-ios;
  net11.0-maccatalyst
</TargetFrameworks>

No aparece una nueva API visual ni un control espectacular. La promesa está en unificar la base técnica: una aplicación móvil y su backend pueden compartir no solo lenguaje y bibliotecas, sino también el mismo runtime, comportamientos más consistentes y una familia común de herramientas.

Por qué Microsoft hace el cambio

Un único runtime para casi todo .NET

La primera ventaja es reducir la distancia entre plataformas. Si un equipo mantiene una API en ASP.NET Core y una aplicación MAUI, ambos lados pasan a ejecutarse sobre CoreCLR. Esto no elimina las diferencias propias de Android o iOS, pero sí reduce otra fuente de variación interna.

Una base mejor para el rendimiento

CoreCLR aporta tecnologías como la compilación JIT por niveles, ReadyToRun y la optimización guiada por perfiles, conocida como PGO. En móvil, estas piezas se combinan para intentar mejorar especialmente el tiempo de arranque sin obligarnos a modificar el código de la aplicación.

Microsoft afirma que una aplicación creada con dotnet new maui inicia de forma mediblemente más rápida. Sin embargo, no ofrece una cifra universal, y esa cautela importa: el resultado depende del tamaño de la aplicación, sus dependencias, las arquitecturas incluidas y el trabajo que realiza durante el arranque.

El camino hacia NativeAOT

CoreCLR también sirve como base para ampliar NativeAOT. En Android abre el camino hacia binarios completamente compilados de antemano. En las plataformas de Apple, donde las restricciones ya obligaban a utilizar compilación AOT, permite avanzar hacia una cadena de herramientas más unificada.

Diagnóstico de .NET en el dispositivo

Una de las mejoras más concretas es poder utilizar herramientas como dotnet-trace y dotnet-counters en escenarios móviles. Analizar actividad del runtime, contadores o trazas se acerca así al flujo que ya conocemos en servidores y escritorio.

No hay que asumir que todo será más rápido

Aquí está la parte más importante de la migración. Microsoft reconoce casos reales de aplicaciones Android grandes en las que CoreCLR ha provocado regresiones en el tiempo de arranque o en el tamaño del paquete. En iOS ya se han validado envíos correctos a la App Store, pero eso tampoco sustituye las pruebas sobre nuestra propia aplicación.

Por tanto, el mensaje no debería ser “actualiza y ganarás rendimiento”, sino “actualiza una rama de prueba y mide”. El cambio de runtime puede mejorar una aplicación sencilla y comportarse de otra manera en un proyecto con muchas bibliotecas, reflexión, generación dinámica de código o integraciones nativas.

Qué medir antes de migrar

Yo prepararía primero una versión base de la aplicación con .NET 10 y después repetiría las mismas pruebas con .NET 11. Como mínimo, compararía:

  • Arranque en frío: abrir la aplicación después de cerrarla por completo.
  • Arranque en caliente: repetir la apertura cuando el sistema ya tiene parte de los recursos preparados.
  • Tamaño del paquete: comparar APK o AAB en Android e IPA en iOS.
  • Memoria: observar el consumo después del arranque y durante los flujos más pesados.
  • Navegación y carga de datos: recorrer las pantallas principales y las listas grandes.
  • Integraciones nativas: cámara, notificaciones, ubicación, almacenamiento y código específico de plataforma.
  • Bibliotecas de terceros: prestar atención a las que utilizan reflexión, generación dinámica o APIs específicas de Mono.
  • Flujo de desarrollo: comprobar depurador, Hot Reload y tiempos de compilación.

Las pruebas deben hacerse en Release y sobre dispositivos físicos representativos. Medir únicamente en un emulador o con el depurador conectado puede distorsionar justo los datos que intentamos comparar.

Cómo probar la transición

.NET 11 todavía está en preview y su lanzamiento estable está previsto para noviembre de 2026. Eso hace que el momento actual sea adecuado para evaluar compatibilidad, no para actualizar a ciegas una aplicación crítica en producción.

El primer paso es instalar el SDK de .NET 11 y su workload de MAUI:

dotnet workload install maui

Después podemos crear una rama, actualizar los target frameworks a net11.0-android, net11.0-ios y net11.0-maccatalyst, generar una compilación Release y ejecutar el checklist anterior.

Si algo falla, todavía se puede volver a Mono

Durante la transición existe una salida temporal. Si aparece una incompatibilidad bloqueante o una regresión que impide publicar, se puede recuperar Mono añadiendo esta propiedad al archivo del proyecto:

<PropertyGroup>
  <UseMonoRuntime>true</UseMonoRuntime>
</PropertyGroup>

La opción está disponible para Android, iOS y Mac Catalyst durante el mantenimiento de .NET 11. No debería convertirse en una excusa para ignorar el problema: lo útil es acompañarla de una incidencia reproducible con el tipo de aplicación, dispositivo, arquitectura, tamaño de paquete y tiempos de arranque.

Qué significa realmente para MAUI

Esta transición no resuelve por sí sola todos los problemas de calidad de .NET MAUI. Los controles continúan dependiendo de implementaciones nativas, cada plataforma conserva sus particularidades y seguirán existiendo errores específicos de Android o iOS.

Lo que sí elimina es una frontera histórica. Desde Xamarin, el desarrollo móvil en C# estaba ligado a Mono. Con .NET 11, MAUI se integra más profundamente en el runtime principal de .NET y obtiene una base común para rendimiento, diagnóstico y futuras opciones de compilación.

Mono hizo posible llegar hasta aquí. CoreCLR intenta que el siguiente tramo sea menos diferente del resto de .NET. Para quienes mantenemos aplicaciones reales, la mejor forma de recibirlo no es con fe ni con miedo: es con una rama de prueba, dispositivos físicos y métricas.

Fuentes consultadas

Comentarios

Entradas populares de este blog

Distribución de aplicaciones iOS en App Store mediante Visual Studio 2019

Visual Studio 2026 y Codex: una integración natural para programar con inteligencia artificial

Qué necesito para ser desarrollador de aplicaciones móviles (2ª parte)