Estás desarrollando con .NET MAUI y todo va bien… hasta que necesitas acceder a algo específico de Android o iOS. Dónde va ese código? Cómo lo haces sin romper la portabilidad? Y, sobre todo, por qué no hay una guía clara que lo explique?
MAUI tiene una base de código única, pero hay momentos en los que sí o sí necesitas tocar el sistema operativo.
En este artículo vas a aprender cómo agregar código específico de cada plataforma de una forma ordenada, usando las herramientas que MAUI te da, por ejemplo: directivas de compilación, clases parciales o inyección de dependencias. Todo explicado de forma directa y con ejemplos.
¿Qué significa “código específico de cada plataforma” en MAUI?
Cuando hablamos de “código específico de cada plataforma” en .NET MAUI, nos referimos a cualquier funcionalidad que no está disponible de forma compartida entre plataformas. Es decir, cosas que solo existen o funcionan diferente en Android, iOS, Windows o macOS.
Ejemplos comunes:
- Obtener el identificador del dispositivo (Android/iOS).
- Acceder a sensores o al GPS.
- Usar APIs exclusivas como el llavero de iOS o el sistema de archivos de Windows.
MAUI, por diseño, te da una única base de código. Pero también sabe que vas a necesitar romper esa uniformidad en ciertos casos. Por eso, permite introducir código específico sin tener que duplicar tu aplicación por cada plataforma.
El objetivo no es evitar el código nativo, sino encapsularlo bien. Así puedes seguir escribiendo tu app como si todo fuera multiplataforma… y solo abrir esa “puerta” nativa cuando lo necesites.
Estructura del proyecto .NET MAUI y dónde va el código nativo
En un proyecto .NET MAUI, todo empieza en una carpeta única y compartida. Pero si miras un poco más de cerca, vas a ver subcarpetas para cada plataforma: Platforms/Android
, Platforms/iOS
, Platforms/Windows
, y Platforms/MacCatalyst
. Ahí es donde va el código específico.
Por ejemplo, si necesitas usar una API nativa de Android, ese código va dentro de Platforms/Android
. Lo mismo con iOS o cualquier otra plataforma.

Lo importante es que este código no se ejecuta automáticamente. MAUI no mezcla todo; solo compila el código de la plataforma que estás ejecutando. Por eso es seguro tener código específico ahí: no afecta a las otras plataformas.
Esto mantiene el código compartido limpio, y solo compila lo que corresponde según la plataforma.
Uso de directivas de compilación (#if ANDROID, #if IOS, etc.)
Las directivas de compilación son la forma más directa de escribir código que solo se ejecute en una plataforma específica. Básicamente, le dices al compilador: “esto solo compílalo si estoy en Android” (o iOS, o Windows).
public class IdentifierInfoService
{
public string GetIndentifier()
{
#if ANDROID
return Android.Provider.Settings.Secure.GetString(
Android.App.Application.Context.ContentResolver,
Android.Provider.Settings.Secure.AndroidId);
#elif IOS
return UIKit.UIDevice.CurrentDevice.IdentifierForVendor.AsString();
#else
return "No soportado en esta plataforma";
#endif
}
}
Uso en tu app:
Puedes utilizar esta clase directamente en cualquier parte del código compartido. Por ejemplo, en tu MainPage.xaml.cs
:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
var service = new IdentifierInfoService();
string id = service.GetIndentifier();
result.Text = $"ID del dispositivo: {id}";
}
}
Esto funciona bien si el código específico es simple y no lo usas en muchos lugares. Pero si empieza a crecer, puede volverse difícil de mantener. En ese caso, es mejor encapsularlo usando interfaces y separar las implementaciones por plataforma (lo veremos más adelante).
✅ Cuándo usarlo:
- Cuando solo necesitas una pequeña diferencia entre plataformas.
- Para pruebas rápidas o funcionalidades mínimas.
❌ Cuándo evitarlo:
- Cuando el código nativo empieza a repetirse o a crecer.
- Si quieres mantener el proyecto limpio y escalable.
Uso de partial clases y métodos parciales
Otra forma elegante de manejar código específico de plataforma en .NET MAUI es con partial class
y partial methods
.
Esto te permite definir la estructura de tu clase o método en el código compartido, pero escribir su implementación específica en los archivos de cada plataforma.
Por ejemplo, en tu código compartido:
namespace Sample.Services;
public partial class DeviceInfoService
{
public string GetIdentifier() => GetIdentifierInternal();
protected static partial string GetIdentifierInternal();
}
Te presente el nombre de espacio que le pongas a esta clase, ya que en las siguientes clases que vas a crear tiene que ser el mismo.
Ahora, en la carpeta Platforms/Android
crea la clase que accederá al código nativo de Android:
namespace Sample.Services;
public partial class IdentifierInfoService
{
protected static partial string GetIdentifierInternal()
{
return Android.Provider.Settings.Secure.GetString(
Android.App.Application.Context.ContentResolver,
Android.Provider.Settings.Secure.AndroidId);
}
}
Y finalmente lo mismo en la carpeta Platforms/iOS
para acceder al código nativo de iOS:
namespace Sample.Services;
public partial class IdentifierInfoService
{
protected static partial string GetIdentifierInternal()
{
return UIKit.UIDevice.CurrentDevice.IdentifierForVendor.AsString();
}
}
Uso en tu app:
Puedes utilizar esta clase directamente en cualquier parte del código compartido. Por ejemplo, en tu MainPage.xaml.cs
:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
var service = new IdentifierInfoService();
string id = service.GetIndentifier();
result.Text = $"ID del dispositivo: {id}";
}
}
Con esto, todo tu código compartido sigue limpio y no necesitas preocuparse por las plataformas. Solo hace una llamada, y MAUI se encarga del resto en tiempo de compilación.
Ventajas:
- Código más limpio y organizado.
- Fácil de mantener y escalar.
- Separación clara entre lógica compartida y lógica nativa.
Inyección de dependencias con interfaces específicas por plataforma
Cuando tu lógica específica de cada plataforma crece o necesitas una solución más escalable, usar interfaces con inyección de dependencias es la forma más limpia y flexible de manejarlo en MAUI.
1: Crear una interfaz en tu proyecto compartido
public interface IIdentifierInfoService
{
public string GetIdentifier();
}
2: Implementación en Android
En la carpeta Platforms/Android
crea una clase llamada IdentifierInfoService.cs
que implemente a la interface creada anteriormente:
public class IdentifierInfoService : IIdentifierInfoService
{
public string GetIdentifier()
{
return Android.Provider.Settings.Secure.GetString(
Android.App.Application.Context.ContentResolver,
Android.Provider.Settings.Secure.AndroidId);
}
}
2: Implementación en iOS
En la carpeta Platforms/iOS
crea una clase llamada IdentifierInfoService.cs
que implemente a la interface creada anteriormente:
public class IdentifierInfoService : IIdentifierInfoService
{
public string GetIdentifier()
{
return UIKit.UIDevice.CurrentDevice.IdentifierForVendor.AsString();
}
}
3. Registro en MauiProgram.cs
En la clase MauiProgram.cs
agrega el registro de cada implementación:
#if ANDROID
builder.Services.AddSingleton<IDeviceInfoService, DeviceInfoService>();
#elif IOS
builder.Services.AddSingleton<IDeviceInfoService, DeviceInfoService>();
#endif
4: Usarlo en cualquier parte de tu app
En una página o ViewModel, inyectas la dependencia:
public partial class MainPage : ContentPage
{
private readonly IIdentifierInfoService _deviceInfoService;
public MainPage(IIdentifierInfoService deviceInfoService)
{
InitializeComponent();
_deviceInfoService = deviceInfoService;
string id = _deviceInfoService.GetIdentifier();
result.Text = $"ID del dispositivo: {id}";
}
}
Y listo. Con esto estás obteniendo un identificador nativo, específico de cada plataforma, pero sin ensuciar tu código compartido.
Buenas prácticas para mantener tu proyecto limpio y escalable
Cuando trabajas con código específico de cada plataforma en MAUI, es fácil caer en un caos de archivos y lógica duplicada. Estas prácticas te van a ayudar a evitarlo:
1. Usa interfaces siempre que puedas
Separar la definición (interface) de la implementación te da flexibilidad, testabilidad y un código más limpio.
2. Evita abusar de las directivas de compilación
Si bien #if ANDROID
, #if IOS
son útiles, pueden volver el código difícil de leer si se usan en exceso. Si necesitas lógica más compleja, encapsula todo en clases separadas.
3. Organiza tus archivos por plataforma
No pongas código específico en archivos genéricos. Aprovecha la estructura de carpetas (Platforms/Android
, etc.) para mantener todo ordenado.
4. Centraliza el registro de dependencias
Mantén el registro de servicios (en MauiProgram.cs
) lo más claro posible. Agrupa los AddSingleton
por plataforma y comenta lo necesario.
6. Piensa en el futuro
Si estás empezando con una implementación simple, no te preocupes. Pero si sabes que vas a expandir esa lógica (por ejemplo, más APIs nativas), es mejor arrancar con interfaces desde el principio.
Conclusión
Agregar código específico de cada plataforma en .NET MAUI no es una trampa al sistema ni un retroceso: es una necesidad real en muchas apps, y MAUI está diseñado para manejarlo bien… siempre que tú lo manejes bien también.
Ya viste:
- Dónde va el código específico en el proyecto.
- Cómo usar directivas de compilación para diferencias simples.
- Cómo usar
partial class
einterface
para mantener todo limpio. - Buenas prácticas y errores que podés evitar desde el primer día.
¿Qué sigue ahora?
- Revisa qué partes de tu app podrían beneficiarse de lógica específica por plataforma.
- Usa el patrón que más sentido tenga: directo, parcial o con interfaces.
- Prueba en cada plataforma donde tu app vaya a vivir.
Y recuerda: escribir código nativo no es romper el concepto de MAUI. Es entenderlo bien. Nos leemos pronto :)