Skip to main content

Building Cross-Platform Apps with CoreCLR and Mono in .NET MAUI: Hands-On Guide

July 25, 2026 5 min read AI Assisted

Building Cross-Platform Apps with CoreCLR and Mono in .NET MAUI: Hands-On Guide (Part 3)

Cross-platform app development has become a necessity in today’s software landscape, and .NET MAUI (Multi-platform App UI) provides a unified framework for building apps that run on Android, iOS, Windows, and macOS. In Part 3 of this series, we’ll focus on implementing a working cross-platform app that leverages both CoreCLR and Mono runtimes in .NET MAUI. By the end, you’ll have a functional app with error handling and basic test coverage.

Let’s dive in.


Section 1: Setting Up Your Development Environment

To build a cross-platform app with .NET MAUI, we must first ensure our development environment is configured correctly. Here's what you'll need:

Prerequisites

  1. Install .NET SDK: Download and install the latest .NET SDK.
  2. Install Visual Studio: Use Visual Studio 2022 with the Mobile Development workload enabled.
  3. Enable platform-specific tools:
    • For Android: Install the Android Emulator and SDK tools via Visual Studio's installer.
    • For iOS: Set up a Mac machine for remote builds (if using Windows) with Xcode installed.

Verify Installation

Run the following commands to verify your setup:

dotnet --version
dotnet workload list

Ensure you see workloads like maui, android, and ios in the output.


Section 2: Creating a New .NET MAUI Project

Let’s create and configure a new .NET MAUI project.

Step 1: Create the Project

Run the following command to create a new .NET MAUI app:

dotnet new maui -n CrossPlatformApp

Navigate into the project directory:

cd CrossPlatformApp

Step 2: Configure Target Platforms

Update your Platforms folder to include the necessary platform-specific configurations. For example, ensure AndroidManifest.xml and Info.plist are properly set up for Android and iOS, respectively.


Section 3: Implementing Core Functionality with CoreCLR and Mono

Adding Shared Code

.NET MAUI allows us to write shared code that runs across all platforms. Let’s implement a simple service for fetching data from an API.

Create a Data Service

Add a new file WeatherService.cs to the Services folder:

using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;

public class WeatherService
{
    private readonly HttpClient _httpClient;

    public WeatherService()
    {
        _httpClient = new HttpClient();
    }

    public async Task<WeatherData> GetWeatherAsync(string city)
    {
        var response = await _httpClient.GetAsync($"https://api.weatherapi.com/v1/current.json?key=YOUR_API_KEY&q={city}");

        if (!response.IsSuccessStatusCode)
        {
            throw new HttpRequestException("Failed to fetch weather data.");
        }

        var json = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<WeatherData>(json);
    }
}

public class WeatherData
{
    public string Location { get; set; }
    public string Temperature { get; set; }
    public string Condition { get; set; }
}

Replace YOUR_API_KEY with your actual API key from WeatherAPI.


Adding Platform-Specific Code

For iOS and Android, we can use platform-specific implementations to access device features.

Example: Accessing Battery Info (Platform-specific)

Add a BatteryService interface to the shared project:

public interface IBatteryService
{
    double GetBatteryLevel();
}

For Android, implement it in Platforms/Android/BatteryService.cs:

using Android.OS;

public class BatteryService : IBatteryService
{
    public double GetBatteryLevel()
    {
        var batteryManager = (BatteryManager)Android.App.Application.Context.GetSystemService(Android.Content.Context.BatteryService);
        return batteryManager.GetIntProperty((int)BatteryProperty.Capacity);
    }
}

For iOS, implement it in Platforms/iOS/BatteryService.cs:

using UIKit;

public class BatteryService : IBatteryService
{
    public double GetBatteryLevel()
    {
        return UIDevice.CurrentDevice.BatteryLevel * 100;
    }
}

Register these services in MauiProgram.cs:

builder.Services.AddSingleton<IBatteryService, BatteryService>();

Section 4: Adding a Simple UI

Let’s build a basic UI to display weather data and battery information.

Update MainPage.xaml

Replace the contents of MainPage.xaml:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CrossPlatformApp.MainPage">
    <StackLayout Padding="20">
        <Entry x:Name="CityEntry" Placeholder="Enter city" />
        <Button Text="Get Weather" Clicked="OnGetWeatherClicked" />
        <Label x:Name="WeatherLabel" Text="Weather info will appear here." />
        <Label x:Name="BatteryLabel" Text="Battery info will appear here." />
    </StackLayout>
</ContentPage>

Update MainPage.xaml.cs

Add event handlers:

using System;

public partial class MainPage : ContentPage
{
    private readonly WeatherService _weatherService;
    private readonly IBatteryService _batteryService;

    public MainPage(WeatherService weatherService, IBatteryService batteryService)
    {
        InitializeComponent();
        _weatherService = weatherService;
        _batteryService = batteryService;

        BatteryLabel.Text = $"Battery Level: {_batteryService.GetBatteryLevel()}%";
    }

    private async void OnGetWeatherClicked(object sender, EventArgs e)
    {
        try
        {
            var weather = await _weatherService.GetWeatherAsync(CityEntry.Text);
            WeatherLabel.Text = $"{weather.Location}: {weather.Temperature}°C, {weather.Condition}";
        }
        catch (Exception ex)
        {
            WeatherLabel.Text = $"Error: {ex.Message}";
        }
    }
}

Section 5: Error Handling

Robust error handling is critical in cross-platform apps. Here’s how we handle potential issues:

Network Errors

Wrap API calls in a try-catch block, as shown in the OnGetWeatherClicked method above. Log errors or show user-friendly messages.

Platform-Specific Exceptions

For services like BatteryService, use platform-specific logging or analytics tools to capture issues. For example:

try
{
    var batteryLevel = _batteryService.GetBatteryLevel();
}
catch (PlatformNotSupportedException ex)
{
    Console.WriteLine($"Platform error: {ex.Message}");
}

Section 6: Testing the App

Unit Testing

Write unit tests for shared logic using xUnit or NUnit. Here’s an example for WeatherService:

using System.Net.Http;
using Xunit;

public class WeatherServiceTests
{
    [Fact]
    public async Task GetWeatherAsync_ValidCity_ReturnsData()
    {
        var service = new WeatherService();
        var result = await service.GetWeatherAsync("Seattle");

        Assert.NotNull(result);
        Assert.Equal("Seattle", result.Location);
    }
}

Manual Testing

Run the app on an Android emulator and an iOS simulator to verify platform-specific functionality, such as the battery service.


Section 7: Running the App

Compile and run your app using the following commands:

dotnet build
dotnet run -t:run -f net6.0-android
dotnet run -t:run -f net6.0-ios

Test the app by:

  • Entering a city name to fetch weather data.
  • Verifying the battery level is displayed correctly on both platforms.

Conclusion

In this hands-on guide, we built a functional cross-platform app using .NET MAUI, leveraging CoreCLR for shared logic and Mono for platform-specific features. We implemented error handling and unit testing to ensure the app is robust and reliable.

In Part 4, we’ll explore advanced patterns, including custom renderers, dependency injection, and performance optimization techniques for .NET MAUI applications.


References

  1. Getting Started with .NET MAUI
  2. WeatherAPI Documentation
  3. .NET MAUI Architecture
  4. xUnit Documentation
  5. BatteryManager Android API

Comments

Ajit Gangurde

Software Engineer II at Microsoft | 15+ years in .NET & Azure

Series: series-coreclr-progress-and-the-mono-timeline-for-net-maui-20260718

Part 3 of 4

Part 2
"CoreCLR and Mono in .NET MAUI: Exploring the Architecture Behind the Framework"
Part 3
Building Cross-Platform Apps with CoreCLR and Mono in .NET MAUI: Hands-On Guide