skills/davidortinau/maui-skills/maui-platform-invoke

maui-platform-invoke

SKILL.md

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 #if needed—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
Weekly Installs
7
GitHub Stars
71
First Seen
Feb 18, 2026
Installed on
opencode7
gemini-cli7
github-copilot7
codex7
kimi-cli7
amp7