Leveraging Platform-Specific APIs in .NET MAUI

πŸš€ Leveraging Platform-Specific APIs in .NET MAUI

A Deep Dive into Partials and Conditional Compilation

When building cross-platform applications with .NET MAUI, you quickly realize that β€œwrite once, run anywhere” is more of a guiding principle than an absolute rule. Real-world apps often require:

  • Native integrations (biometrics, sensors, secure storage πŸ”)
  • Platform-specific UI tweaks 🎨
  • OS-level optimizations ⚑ The question is not if you will need platform-specific codeβ€”but how to implement it cleanly without turning your codebase into a mess. This is where two powerful techniques come into play:
  • 🧩 Partial Classes & Partial Methods
  • βš™οΈ Conditional Compilation (#if) Let’s break them down deeply, compare them, and establish best practices you can confidently apply in production-grade MAUI apps.

🧠 Why Platform-Specific Code Matters

Even though .NET MAUI abstracts most functionality, some APIs are inherently platform-bound:

Feature Android iOS Windows
Biometric Auth βœ… βœ… ⚠️ Different APIs
File System Access Scoped Storage Sandbox Full FS
Notifications Firebase APNs Windows Push
Hardware Sensors Rich APIs Limited Varies

πŸ‘‰ Trying to force everything into shared code often leads to:

  • ❌ Hacks
  • ❌ Poor performance
  • ❌ Unmaintainable abstractions

🧩 Approach #1: Partial Classes & Partial Methods

πŸ” Concept

Partial classes allow you to split a class across multiple filesβ€”typically:

  • One shared file (cross-platform logic)
  • Multiple platform-specific implementations

πŸ—οΈ Example Structure

Services/  
 β”œβ”€β”€ DeviceService.shared.cs  
 β”œβ”€β”€ DeviceService.android.cs  
 β”œβ”€β”€ DeviceService.ios.cs  
 └── DeviceService.windows.cs

πŸ§ͺ Shared Code

public partial class DeviceService  
{  
    public partial string GetDeviceName();  
}

πŸ€– Android Implementation

public partial class DeviceService  
{  
    public partial string GetDeviceName()  
    {  
        return Android.OS.Build.Model;  
    }  
}

🍏 iOS Implementation

public partial class DeviceService  
{  
    public partial string GetDeviceName()  
    {  
        return UIKit.UIDevice.CurrentDevice.Name;  
    }  
}

πŸͺŸ Windows Implementation

public partial class DeviceService  
{  
    public partial string GetDeviceName()  
    {  
        return Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily;  
    }  
}

βœ… Advantages

  • Clean separation of concerns 🧼
  • Strongly typed and compile-safe πŸ’ͺ
  • Easy to scale for large apps πŸ“ˆ
  • Ideal for dependency injection scenarios

❌ Drawbacks

  • Requires multiple files πŸ“‚
  • Slightly more setup overhead
  • Can be harder to trace implementations

βš™οΈ Approach #2: Conditional Compilation (#if)

πŸ” Concept

Conditional compilation allows you to include/exclude code at compile time depending on the platform.


πŸ§ͺ Example

public string GetDeviceName()  
{  
#if ANDROID  
    return Android.OS.Build.Model;  
#elif IOS  
    return UIKit.UIDevice.CurrentDevice.Name;  
#elif WINDOWS  
    return Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily;  
#else  
    return "Unknown";  
#endif  
}

βœ… Advantages

  • Simple and quick to implement ⚑
  • Everything in one place πŸ“
  • Great for small differences

❌ Drawbacks

  • Can become messy fast 🧨
  • Harder to maintain in large codebases
  • Violates separation of concerns

βš–οΈ Partials vs Conditional Compilation

πŸ“Š Comparative Table

Criteria Partial Classes 🧩 #if Compilation βš™οΈ
Maintainability ⭐⭐⭐⭐⭐ ⭐⭐
Scalability ⭐⭐⭐⭐⭐ ⭐⭐
Readability ⭐⭐⭐⭐ ⭐⭐
Setup Complexity ⭐⭐⭐ ⭐
Best for Large Projects βœ… ❌
Best for Quick Fixes ❌ βœ…

🧠 When Should You Use Each?

🧩 Use Partials When:

  • You’re building production-grade apps
  • Logic differs significantly per platform
  • You want clean architecture (MVVM, Clean Architecture)
  • You plan to scale the project πŸ‘‰ Example use cases:
  • Biometric authentication
  • Native SDK integrations
  • Secure storage implementations

βš™οΈ Use #if When:

  • You need a small tweak
  • Logic differences are minimal
  • You want a quick solution πŸ‘‰ Example use cases:
  • Minor UI adjustments
  • Debug logging
  • Small platform checks

πŸ—οΈ Hybrid Approach (Best Practice)

In real-world apps, the best solution is often a combination of both:

βœ… Pattern

  • Use partials for services and core logic
  • Use #if for minor inline differences

πŸ§ͺ Example Hybrid

public partial class BatteryService  
{  
    public partial int GetBatteryLevel();  
  
    public bool IsLowBattery()  
    {  
        var level = GetBatteryLevel();  
  
#if DEBUG  
        Console.WriteLine($"Battery Level: {level}");  
#endif  
  
        return level < 20;  
    }  
}

🧱 Architecture Tip (PRO Level) 🧠

Combine partials with dependency injection:

builder.Services.AddSingleton<IDeviceService, DeviceService>();

This gives you:

  • Testability πŸ§ͺ
  • Flexibility πŸ”„
  • Clean boundaries 🧱

πŸ”— Official References

For deeper understanding, check:


πŸš€ Key Takeaways

  • Platform-specific code is inevitable in MAUI
  • Partials = clean, scalable, maintainable 🧩
  • #if = quick, simple, but risky at scale βš™οΈ
  • The hybrid approach is often the best solution

🧩 Final Thoughts

Mastering platform-specific APIs in .NET MAUI is what separates a functional app from a production-ready app. If you rely too much on conditional compilation, your codebase will eventually become fragile. On the other hand, leveraging partial classes strategically allows you to build clean, extensible, and enterprise-grade applications. πŸ‘‰ Think of it this way:

  • #if is a tool
  • Partials are an architecture Use them accordingly, and your MAUI apps will scale without pain. ⚑
An unhandled error has occurred. Reload πŸ—™