Skip to main content
While Avalonia provides extensive cross-platform capabilities, you may need to access platform-specific features or APIs that are unique to each platform.

Platform Detection

Runtime Detection

Detect the current platform at runtime:
using System.Runtime.InteropServices;

public static class PlatformHelper
{
    public static bool IsWindows =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
    
    public static bool IsMacOS =>
        RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
    
    public static bool IsLinux =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
    
    public static bool IsIOS =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS"));
    
    public static bool IsAndroid =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID"));
    
    public static bool IsBrowser =>
        RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER"));
}

Compile-Time Detection

Use conditional compilation for platform-specific code:
public class PlatformService
{
    public void DoSomething()
    {
#if WINDOWS
        // Windows-specific implementation
        DoWindowsSpecific();
#elif OSX || MACCATALYST
        // macOS-specific implementation
        DoMacOSSpecific();
#elif LINUX
        // Linux-specific implementation
        DoLinuxSpecific();
#elif IOS || TVOS
        // iOS-specific implementation
        DoIOSSpecific();
#elif ANDROID
        // Android-specific implementation
        DoAndroidSpecific();
#elif BROWSER
        // Browser-specific implementation
        DoBrowserSpecific();
#else
        // Fallback implementation
        DoGenericImplementation();
#endif
    }
}

Accessing Platform Services

Service Locator Pattern

Use Avalonia’s service locator to access platform services:
using Avalonia;
using Avalonia.Platform;

public class PlatformServiceAccessor
{
    public void AccessPlatformServices()
    {
        // Get platform settings
        var settings = AvaloniaLocator.Current
            .GetService<IPlatformSettings>();
        
        // Get runtime platform info
        var runtimePlatform = AvaloniaLocator.Current
            .GetService<IRuntimePlatform>();
        
        // Get clipboard
        var clipboard = AvaloniaLocator.Current
            .GetService<IClipboard>();
        
        // Get screen information
        var screens = AvaloniaLocator.Current
            .GetService<IScreenImpl>();
    }
}

TopLevel Services

Access services through TopLevel:
using Avalonia.Controls;
using Avalonia.Platform.Storage;

public class TopLevelServiceAccessor : UserControl
{
    private void AccessServices()
    {
        var topLevel = TopLevel.GetTopLevel(this);
        if (topLevel == null) return;
        
        // Storage provider (file dialogs)
        var storageProvider = topLevel.StorageProvider;
        
        // Clipboard
        var clipboard = topLevel.Clipboard;
        
        // Launcher (open URLs, files)
        var launcher = topLevel.Launcher;
        
        // Input pane (virtual keyboard)
        var inputPane = topLevel.InputPane;
        
        // Insets manager (safe areas)
        var insetsManager = topLevel.InsetsManager;
        
        // System navigation (back button)
        var systemNav = topLevel.SystemNavigationManager;
    }
}

Windows-Specific Features

Windows Platform Handle

Access the native HWND:
using Avalonia.Controls;
using Avalonia.Platform;

public class WindowsSpecificFeatures : Window
{
    public IntPtr GetWindowHandle()
    {
        if (TryGetPlatformHandle() is PlatformHandle handle)
        {
            // handle.Handle is the HWND
            return handle.Handle;
        }
        return IntPtr.Zero;
    }
    
    public void UseWin32API()
    {
        var hwnd = GetWindowHandle();
        if (hwnd != IntPtr.Zero)
        {
            // Call Win32 APIs with the HWND
            // Example: SetWindowLong, SendMessage, etc.
        }
    }
}

Windows Jump Lists

#if WINDOWS
using Windows.UI.StartScreen;

public async Task SetupJumpListAsync()
{
    var jumpList = await JumpList.LoadCurrentAsync();
    jumpList.Items.Clear();
    
    var item = JumpListItem.CreateWithArguments(
        "--open-recent",
        "Recent Files");
    item.Logo = new Uri("ms-appx:///Assets/recent.png");
    
    jumpList.Items.Add(item);
    await jumpList.SaveAsync();
}
#endif

Windows Composition

Source: src/Windows/Avalonia.Win32/Win32Platform.cs:82

macOS-Specific Features

macOS Menu Bar

Access the native macOS menu bar:
using Avalonia.Controls;

public class MacOSMenuSetup
{
    public void CreateMacOSMenu()
    {
        var menu = new NativeMenu();
        
        // Application menu (automatically named after app)
        var appMenu = new NativeMenuItem("Application");
        var appSubMenu = new NativeMenu
        {
            new NativeMenuItem("About MyApp") { Command = AboutCommand },
            new NativeMenuItemSeparator(),
            new NativeMenuItem("Preferences...") 
            { 
                Command = PreferencesCommand,
                Gesture = new KeyGesture(Key.OemComma, KeyModifiers.Meta)
            },
            new NativeMenuItemSeparator(),
            new NativeMenuItem("Hide MyApp") 
            { 
                Gesture = new KeyGesture(Key.H, KeyModifiers.Meta)
            },
            new NativeMenuItem("Quit MyApp") 
            { 
                Gesture = new KeyGesture(Key.Q, KeyModifiers.Meta)
            }
        };
        appMenu.Menu = appSubMenu;
        menu.Add(appMenu);
        
        // Set the menu
        NativeMenu.SetMenu(Application.Current, menu);
    }
}

macOS Dark Mode

using Avalonia.Platform;

public class MacOSThemeDetector
{
    public void DetectTheme()
    {
        var settings = AvaloniaLocator.Current
            .GetService<IPlatformSettings>();
        
        if (settings != null)
        {
            var colorValues = settings.GetColorValues();
            var isDark = colorValues.ThemeVariant == PlatformThemeVariant.Dark;
            
            // Listen for theme changes
            settings.ColorValuesChanged += (s, e) =>
            {
                var newIsDark = e.ThemeVariant == PlatformThemeVariant.Dark;
                // Update UI for theme change
            };
        }
    }
}
Source: src/Avalonia.Native/NativePlatformSettings.cs:31

Linux-Specific Features

DBus Integration

#if LINUX
using Avalonia.FreeDesktop;
using Tmds.DBus;

public class LinuxDBusIntegration
{
    public async Task SendNotificationAsync(string title, string body)
    {
        try
        {
            var connection = Connection.Session;
            var service = connection.CreateProxy<INotifications>(
                "org.freedesktop.Notifications",
                "/org/freedesktop/Notifications");
            
            await service.NotifyAsync(
                "MyApp",           // app_name
                0,                 // replaces_id
                "dialog-information", // app_icon
                title,             // summary
                body,              // body
                new string[0],     // actions
                new Dictionary<string, object>(), // hints
                5000               // timeout (ms)
            );
        }
        catch (Exception ex)
        {
            // Handle error
        }
    }
}

[DBusInterface("org.freedesktop.Notifications")]
interface INotifications : IDBusObject
{
    Task<uint> NotifyAsync(
        string appName,
        uint replacesId,
        string appIcon,
        string summary,
        string body,
        string[] actions,
        IDictionary<string, object> hints,
        int expireTimeout);
}
#endif

X11 Window Properties

#if LINUX
using Avalonia.X11;

public class X11WindowProperties : Window
{
    public void SetX11Properties()
    {
        if (TryGetPlatformHandle() is PlatformHandle handle)
        {
            // Access X11 display and window
            // handle.Handle is the X11 Window ID
        }
    }
}
#endif
Source: src/Avalonia.X11/X11Window.cs:12

iOS-Specific Features

iOS View Controller Integration

#if IOS
using Avalonia.iOS;
using UIKit;

public class iOSIntegration
{
    public void IntegrateWithUIKit()
    {
        var avaloniaView = new AvaloniaView();
        avaloniaView.Content = new MyAvaloniaControl();
        
        // Add to UIViewController
        var viewController = new UIViewController();
        viewController.View.AddSubview(avaloniaView);
        
        // Layout
        avaloniaView.Frame = viewController.View.Bounds;
        avaloniaView.AutoresizingMask = 
            UIViewAutoresizing.FlexibleWidth | 
            UIViewAutoresizing.FlexibleHeight;
    }
}
#endif

iOS Safe Areas

Handle notches and safe areas:
#if IOS
using Avalonia.Platform;
using UIKit;

public class iOSSafeAreaHandler : UserControl
{
    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
    {
        base.OnAttachedToVisualTree(e);
        
        var insetsManager = TopLevel.GetTopLevel(this)?.InsetsManager;
        if (insetsManager != null)
        {
            insetsManager.SafeAreaChanged += (s, args) =>
            {
                // Apply safe area insets
                Padding = new Thickness(
                    args.SafeAreaPadding.Left,
                    args.SafeAreaPadding.Top,
                    args.SafeAreaPadding.Right,
                    args.SafeAreaPadding.Bottom
                );
            };
        }
    }
}
#endif
Source: src/iOS/Avalonia.iOS/InsetsManager.cs:19

Android-Specific Features

Android Activity Access

#if ANDROID
using Android.App;
using Android.Content;
using Avalonia.Android;

public class AndroidIntegration
{
    public void AccessAndroidAPIs()
    {
        var activity = AvaloniaMainActivity.Current as Activity;
        if (activity != null)
        {
            // Use Android APIs
            var context = activity.ApplicationContext;
            
            // Example: Get package name
            var packageName = context.PackageName;
            
            // Example: Start an Android activity
            var intent = new Intent(Intent.ActionView);
            intent.SetData(Android.Net.Uri.Parse("https://example.com"));
            activity.StartActivity(intent);
        }
    }
}
#endif

Android Permissions

#if ANDROID
using Android;
using Android.App;
using Android.Content.PM;
using AndroidX.Core.App;
using AndroidX.Core.Content;

public class AndroidPermissions
{
    private Activity _activity;
    
    public async Task<bool> RequestStoragePermissionAsync()
    {
        if (ContextCompat.CheckSelfPermission(_activity,
            Manifest.Permission.ReadExternalStorage) 
            == Permission.Granted)
        {
            return true;
        }
        
        var tcs = new TaskCompletionSource<bool>();
        
        ActivityCompat.RequestPermissions(_activity,
            new[] { Manifest.Permission.ReadExternalStorage },
            requestCode: 1);
        
        // Handle result in OnRequestPermissionsResult
        return await tcs.Task;
    }
}
#endif

Android Back Button

#if ANDROID
using Avalonia.Platform;

public class AndroidBackHandler : UserControl
{
    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
    {
        base.OnAttachedToVisualTree(e);
        
        var systemNav = TopLevel.GetTopLevel(this)?.SystemNavigationManager;
        if (systemNav != null)
        {
            systemNav.BackRequested += OnBackRequested;
        }
    }
    
    private void OnBackRequested(object? sender, BackRequestedEventArgs e)
    {
        // Handle back button
        if (CanNavigateBack())
        {
            NavigateBack();
            e.Handled = true;
        }
    }
}
#endif
Source: src/Android/Avalonia.Android/Platform/AndroidSystemNavigationManager.cs:13

Browser-Specific Features

JavaScript Interop

#if BROWSER
using System.Runtime.InteropServices.JavaScript;

public partial class BrowserInterop
{
    [JSImport("globalThis.alert")]
    public static partial void Alert(string message);
    
    [JSImport("globalThis.localStorage.setItem")]
    public static partial void SetLocalStorage(string key, string value);
    
    [JSImport("globalThis.localStorage.getItem")]
    public static partial string? GetLocalStorage(string key);
    
    [JSExport]
    public static string GetDataFromCSharp()
    {
        return "Data from C#";
    }
}
#endif

Browser APIs

#if BROWSER
using Avalonia.Browser.Interop;

public class BrowserFeatures
{
    public void UseBrowserAPIs()
    {
        // Detect dark mode
        var darkMode = DomHelper.GetDarkMode(
            BrowserWindowingPlatform.GlobalThis);
        
        // Get user agent
        var userAgent = BrowserWindowingPlatform.GlobalThis
            .GetProperty("navigator")
            .GetProperty("userAgent")
            .GetString();
    }
}
#endif
Source: src/Browser/Avalonia.Browser/BrowserPlatformSettings.cs:41

Platform-Specific Resources

Conditional Resource Loading

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
        <!-- Common resources -->
        <SolidColorBrush x:Key="AccentBrush" Color="Blue"/>
    </Application.Resources>
    
    <Application.Styles>
        <!-- Platform-specific styles -->
        <OnFormFactor Desktop="DesktopStyles.axaml"
                      Mobile="MobileStyles.axaml"/>
        
        <!-- Or using platform detection -->
        <StyleInclude Source="avaloniaui://avalonia/ui/fluent"
                      Condition="{OnPlatform Default=True, Android=False}"/>
    </Application.Styles>
</Application>

OnFormFactor Extension

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <!-- Different layouts for different form factors -->
        <TextBlock Text="{OnFormFactor Desktop='Desktop Mode', 
                                        Mobile='Mobile Mode'}"/>
        
        <Image Source="{OnFormFactor Desktop='/Assets/desktop.png',
                                      Mobile='/Assets/mobile.png'}"/>
    </Grid>
</UserControl>

Platform-Specific Services Pattern

Interface Definition

public interface IPlatformService
{
    Task<bool> DoSomethingAsync();
    string GetPlatformInfo();
}

Platform Implementations

#if WINDOWS
public class WindowsPlatformService : IPlatformService
{
    public async Task<bool> DoSomethingAsync()
    {
        // Windows-specific implementation
        return true;
    }
    
    public string GetPlatformInfo()
    {
        return "Windows Implementation";
    }
}
#endif

Usage

public class MyViewModel
{
    private readonly IPlatformService _platformService;
    
    public MyViewModel()
    {
        _platformService = PlatformServiceFactory.Create();
    }
    
    public async Task DoWorkAsync()
    {
        var result = await _platformService.DoSomethingAsync();
        var info = _platformService.GetPlatformInfo();
    }
}

Best Practices

1. Abstract Platform-Specific Code

Keep platform-specific code isolated behind interfaces:
// Good: Platform-agnostic interface
public interface IFileService
{
    Task<string> ReadFileAsync(string path);
}

// Platform-specific implementations
#if WINDOWS
public class WindowsFileService : IFileService { }
#elif ANDROID
public class AndroidFileService : IFileService { }
#endif

2. Use Dependency Injection

Register platform-specific services:
public static class ServiceRegistration
{
    public static void RegisterPlatformServices(IServiceCollection services)
    {
        #if WINDOWS
            services.AddSingleton<IPlatformService, WindowsPlatformService>();
        #elif ANDROID
            services.AddSingleton<IPlatformService, AndroidPlatformService>();
        #endif
    }
}

3. Graceful Degradation

Provide fallbacks for unsupported platforms:
public async Task<bool> TryUseNativeFeatureAsync()
{
    #if WINDOWS
        return await UseWindowsNativeFeatureAsync();
    #else
        // Fallback implementation
        return await UseCrossplatformAlternativeAsync();
    #endif
}

4. Test on All Platforms

Always test platform-specific code on actual devices or emulators.

Next Steps

Desktop Platforms

Learn about desktop-specific features

Mobile Platforms

Explore mobile platform capabilities

Build docs developers (and LLMs) love