maui-platform-invoke
Platform Invoke in .NET MAUI
Two approaches exist for invoking platform-specific APIs from shared code.
1. Conditional Compilation
Use preprocessor directives for small, inline platform code:
public string GetDeviceName()
{
#if ANDROID
return Android.OS.Build.Model;
#elif IOS || MACCATALYST
return UIKit.UIDevice.CurrentDevice.Name;
#elif WINDOWS
return Windows.Security.ExchangeActiveSyncProvisioning
.EasClientDeviceInformation().FriendlyName;
#else
return "Unknown";
#endif
}
Best for: one-off calls, quick checks, small blocks. Avoid for complex logic—use partial classes instead.
2. Partial Classes (Preferred)
Split a service into a cross-platform definition and per-platform implementations.
Cross-platform definition
Services/DeviceOrientationService.cs:
namespace MyApp.Services;
public partial class DeviceOrientationService
{
public partial DeviceOrientation GetOrientation();
}
public enum DeviceOrientation
{
Undefined, Portrait, Landscape
}
Platform implementations
Platforms/Android/Services/DeviceOrientationService.cs:
namespace MyApp.Services;
public partial class DeviceOrientationService
{
public partial DeviceOrientation GetOrientation()
{
var activity = Platform.CurrentActivity
?? throw new InvalidOperationException("No current activity.");
var rotation = activity.WindowManager?.DefaultDisplay?.Rotation;
return rotation is SurfaceOrientation.Rotation90
or SurfaceOrientation.Rotation270
? DeviceOrientation.Landscape
: DeviceOrientation.Portrait;
}
}
Platforms/iOS/Services/DeviceOrientationService.cs:
namespace MyApp.Services;
public partial class DeviceOrientationService
{
public partial DeviceOrientation GetOrientation()
{
var orientation = UIKit.UIDevice.CurrentDevice.Orientation;
return orientation is UIKit.UIDeviceOrientation.LandscapeLeft
or UIKit.UIDeviceOrientation.LandscapeRight
? DeviceOrientation.Landscape
: DeviceOrientation.Portrait;
}
}
Key rules
- Same namespace across all partial files.
- The build system auto-includes only the file matching the target platform from
Platforms/{Platform}/. - No
#ifneeded—MSBuild handles it.
Multi-Targeting Configuration
The default .csproj already multi-targets. To add custom file-based patterns:
<!-- Include files matching *.android.cs only for Android -->
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">
<Compile Include="**\*.android.cs" />
</ItemGroup>
You can also use folder-based conventions beyond Platforms/:
<ItemGroup Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">
<Compile Include="iOS\**\*.cs" />
</ItemGroup>
Dependency Injection Registration
Register platform-specific implementations in MauiProgram.cs:
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.UseMauiApp<App>();
// Interface-based (recommended for testability)
builder.Services.AddSingleton<IDeviceOrientationService, DeviceOrientationService>();
// Platform-specific registrations when implementations differ by type
#if ANDROID
builder.Services.AddSingleton<IPlatformNotifier, AndroidNotifier>();
#elif IOS || MACCATALYST
builder.Services.AddSingleton<IPlatformNotifier, AppleNotifier>();
#elif WINDOWS
builder.Services.AddSingleton<IPlatformNotifier, WindowsNotifier>();
#endif
return builder.Build();
}
Prefer interfaces (IDeviceOrientationService) so shared code depends on abstractions, enabling unit testing with mocks.
Android Java Interop Basics
Access Android APIs directly via C# bindings in the Android.* namespaces:
// Get a system service
var connectivityManager = (Android.Net.ConnectivityManager)
Platform.CurrentActivity!
.GetSystemService(Android.Content.Context.ConnectivityService)!;
// Check network
var network = connectivityManager.ActiveNetwork;
var capabilities = connectivityManager.GetNetworkCapabilities(network);
bool hasWifi = capabilities?.HasTransport(
Android.Net.TransportType.Wifi) ?? false;
For APIs without existing bindings, use Java Native Interface via Java.Interop or create an Android Binding Library.
Quick Reference
| Approach | When to use |
|---|---|
#if ANDROID |
Small inline checks, 1–5 lines |
| Partial classes | Services, complex logic, testable code |
| Interface + DI | Swappable implementations, unit testing |
| Custom file patterns | Teams preferring *.android.cs naming |