
Maui Platform Invoke
- 31 installs
- 163 repo stars
- Updated July 6, 2026
- davidortinau/maui-skills
Calls platform-specific native APIs from .NET MAUI apps using partial classes, conditional compilation, multi-targeting, and DI patterns.
About
Guides calling platform-specific native APIs from .NET MAUI apps via partial classes, conditional compilation, multi-targeting configuration and dependency injection. A developer uses it when invoking native platform code from cross-platform MAUI code.
- Partial classes and conditional compilation for multi-targeting
- DI patterns for cross-platform code needing native APIs
Maui Platform Invoke by the numbers
- 31 all-time installs (skills.sh)
- Ranked #656 of 1,039 Mobile Development skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/davidortinau/maui-skills --skill maui-platform-invokeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 31 |
|---|---|
| repo stars | ★ 163 |
| Last updated | July 6, 2026 |
| Repository | davidortinau/maui-skills ↗ |
What it does
Calls platform-specific native APIs from .NET MAUI apps using partial classes, conditional compilation, multi-targeting, and DI patterns.
Files
Platform Invoke — Gotchas & Best Practices
Decision Framework
| Scenario | Approach |
|---|---|
| 1–5 lines, one-off check | #if ANDROID conditional compilation |
| Service with logic, testable | Partial classes in Platforms/ folders |
| Swappable implementations, mocking | Interface + DI registration |
Team prefers *.android.cs naming | Custom file patterns in .csproj |
Default choice: partial classes + interface + DI. Only use #if for trivial inline checks.
Common Mistakes
1. Overusing #if directives
// ❌ Complex logic buried in #if blocks — untestable, hard to read
public async Task<bool> CheckConnectivity()
{
#if ANDROID
// 30 lines of Android networking code...
#elif IOS
// 25 lines of iOS networking code...
#endif
}
// ✅ Use partial classes — each platform file is clean and testable
// Services/ConnectivityService.cs (shared)
public partial class ConnectivityService
{
public partial Task<bool> CheckConnectivityAsync();
}
// Platforms/Android/Services/ConnectivityService.cs
public partial class ConnectivityService
{
public partial Task<bool> CheckConnectivityAsync() { /* Android impl */ }
}2. Mismatched namespaces in partial classes
All partial class files must use the same namespace, or they become separate classes.
// ❌ Different namespaces — creates TWO unrelated classes
// Services/MyService.cs
namespace MyApp.Services;
public partial class MyService { }
// Platforms/Android/MyService.cs
namespace MyApp.Platforms.Android; // WRONG!
public partial class MyService { }
// ✅ Same namespace everywhere
namespace MyApp.Services;
public partial class MyService { }3. Depending on concrete classes in shared code
// ❌ Shared code depends on concrete platform type — can't mock in tests
public class MyViewModel
{
readonly DeviceOrientationService _service = new();
}
// ✅ Depend on interface — enables unit testing and swapping
public class MyViewModel
{
readonly IDeviceOrientationService _service;
public MyViewModel(IDeviceOrientationService service) => _service = service;
}4. Forgetting the #else fallback
// ❌ Fails compilation on unsupported platforms
public string GetDeviceName()
{
#if ANDROID
return Android.OS.Build.Model;
#elif IOS
return UIKit.UIDevice.CurrentDevice.Name;
#endif // No return for Windows or other platforms!
}
// ✅ Always include a fallback
#else
return "Unknown";
#endifPlatform Pitfalls
⚠️ Android: Platform.CurrentActivity can be null
Platform.CurrentActivity is null before OnCreate completes or when the app is in the background. Always null-check or throw a clear exception.
⚠️ MSBuild auto-includes Platforms/{Platform}/ files
Files under Platforms/Android/ are only compiled for Android — no #if needed. But if you put platform code in a shared folder (e.g., Services/), you must use #if or conditional <Compile> items.
⚠️ Custom file patterns need explicit MSBuild conditions
If using *.android.cs naming, files won't auto-include. Add <Compile> items with platform conditions in your .csproj.
Checklist
- [ ] Partial classes share the same namespace across all files
- [ ] Complex platform code uses partial classes, not
#ifblocks - [ ] Shared code depends on interfaces, not concrete implementations
- [ ] Interfaces registered in DI in
MauiProgram.cs - [ ]
#ifblocks include#elsefallback for unsupported platforms - [ ]
Platform.CurrentActivitynull-checked before use (Android) - [ ] Custom file patterns (if used) have MSBuild
<Compile>conditions
Platform Invoke API Reference
Conditional Compilation Example
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
}Partial Classes Example
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;
}
}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>DI 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();
}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.