The first project with .NET MAUI

The first project with .NET MAUI

14 March 2021

MAUI/Xamarin

Share:

Hello!

Today we will migrate an existing Xamarin.Forms Application to .NET MAUI! As a victim I chose my KanbanBoard app.

Installation

First of all, we need to verify if we have prepared the development environment. The best tool for that is MAUI Check. Run the next commands in PowerShell:

dotnet tool install -g Redth.Net.Maui.Check
maui-check

It will automatically attempt to fix any issues.

Solution Configuration

  1. Because .NET MAUI is not published to Nuget yet, we need to set up additional package sources.

Create NuGet.config file new the solution file

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
    <add key="dotnet6" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json" />
    <add key="maui" value="https://aka.ms/maui-preview/index.json" />
    <add key="public" value="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public/nuget/v3/index.json" />
  </packageSources>
  <config>
    <add key="globalPackagesFolder" value="packages" />
  </config>
</configuration>
  1. Edit solution file
  • Remove Platform-specific projects;
  • Remove unused Solution Configuration Platforms

The base solution configuration is done.

It's project time

.NET MAUI introduces the Single project concept, SDK-project style, and much more. Let's first migrate our platforms to the “Shared” project.

  1. For each platform create a folder in the “Shared” project:
  • Android
  • iOS
  • MacCatalyst

1.1. Android

  • Copy AndroidManifest.xml, MainActivity.cs, MainApplication.cs, all your services, Resources folder to the Android folder.

1.2. iOS, macOS

  • Copy Main.cs, Info.plist, Entitlements.plist, AppDelegate.cs, LaunchScreen.storyboard, and all your services to the iOS/MacCatalyst folder
  1. Delete Old platforms projects folders.

  2. Now we need to modify and change these files

  • From AndroidManifest.xml remove package name, version code, version name. We will set these settings later in csproj file.
  • Replace MainActivity.cs content with:
namespace YourNamespace
{
	using Android.App;
	using Microsoft.Maui;

	[Activity(Theme = "@style/MainTheme", MainLauncher = true)]
	public class MainActivity : MauiAppCompatActivity
	{
	}
}
  • Replace MainApplication.cs content with:
namespace YourNamespace
{
	using System;
	using Android.App;
	using Android.Runtime;
	using Microsoft.Maui;

	[Application]
	public class MainApplication : MauiApplication<Startup>
	{
		public MainApplication(IntPtr handle, JniHandleOwnership ownership)
			: base(handle, ownership)
		{
		}
	}
}
  • Replace AppDelegate.cs content with:
using Foundation;
using Microsoft.Maui;

namespace YourNamespace
{
	[Register(nameof(AppDelegate))]
	public class AppDelegate : MauiUIApplicationDelegate<Application>
	{
	}
}
  1. Replace all Xamarin.Forms with Microsoft.Maui
  2. Replace App.xaml.cs file content with the next code:
namespace KanbanBoard
{
    public partial class App : Application
    {
        public App(IServiceProvider serviceProvider) // You can inject and resolve any service
        {
            InitializeComponent();
        }

        protected override IWindow CreateWindow(IActivationState activationState)
        {
        	Microsoft.Maui.Controls.Compatibility.Forms.Init(activationState);
        	return new Microsoft.Maui.Controls.Window(new MainPage());
        }
    }
}

Here we enabled back compatibility with the Xamarin.Forms and created a new Window with the ContentPage. 6. Create Startup.cs with content:

namespace YourNamespace
{
	using System.Linq;
	using Microsoft.Extensions.DependencyInjection;
	using Microsoft.Maui;
	using Microsoft.Maui.Hosting;

	public class Startup : IStartup
	{
		public void Configure(IAppHostBuilder appBuilder)
		{
			appBuilder
				.UseMauiServiceProviderFactory(constructorInjection: true)
                                .UseFormsCompatibility()
                                .UseMauiApp<App>()
                                .ConfigureServices(services =>
                                {
                                    services.AddTransient<IPath, DbPath>();
                                })
				.ConfigureFonts(fonts =>
				{
					fonts.AddFont("fasolid.otf", "FASolid");
				});
		}
	}
}
  1. Inherit all content pages from IPage:
public partial class MainPage : ContentPage, IPage

7.1. Replace xmlns="http://xamarin.com/schemas/2014/forms" with xmlns="http://schemas.microsoft.com/dotnet/2021/maui" 8. Finally update csproj file with:

<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<!-- iOS, Android, MacCatalyst -->
		<TargetFrameworks>net6.0-ios;net6.0-android;net6.0-maccatalyst</TargetFrameworks>
		<OutputType>Exe</OutputType>
		<SingleProject>true</SingleProject>
		<RootNamespace>KanbanBoard</RootNamespace>

		<!-- Display name -->
		<ApplicationTitle>KanbanBoard</ApplicationTitle>

		<!-- App Identifier -->
		<ApplicationId>com.vladislavantonyuk.kanbanboard</ApplicationId>

		<!-- Versions -->
		<ApplicationVersion>1.0</ApplicationVersion>
		<AndroidVersionCode>1</AndroidVersionCode>

		<UseInterpreter Condition="'$(TargetFramework)' == 'net6.0-android'">True</UseInterpreter>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="Microsoft.Maui" Version="6.0.100-preview.4.*" />
	</ItemGroup>

	<PropertyGroup>
		<InvariantGlobalization Condition="'$(TargetFramework)' == 'net6.0-maccatalyst'">true</InvariantGlobalization>
		<RuntimeIdentifier Condition="'$(TargetFramework)' == 'net6.0-ios'">iossimulator-x64</RuntimeIdentifier>
		<RuntimeIdentifier Condition="'$(TargetFramework)' == 'net6.0-maccatalyst'">maccatalyst-x64</RuntimeIdentifier>
	</PropertyGroup>
	<ItemGroup Condition="'$(TargetFramework)' == 'net6.0-android'">
		<AndroidEnvironment Include="Android\AndroidEnvironment.txt" />
	</ItemGroup>
	<ItemGroup>
		<!-- App Icon -->
		<MauiImage
			Include="Resources\appicon.svg"
			ForegroundFile="Resources\appiconfg.svg"
			IsAppIcon="true" />

		<!-- Splash Screen -->
		<MauiSplashScreen Include="Resources\appiconfg.svg" Color="#512BD4" />

		<!-- Images -->
		<MauiImage Include="Resources\Images\*" />

		<!-- Custom Fonts -->
		<MauiFont Include="Resources\Fonts\*" />
	</ItemGroup>

</Project>

Pay attention to the last ItemGroup. .NET MAUI is integrated with Resizetizer NT, so MauiImage and MauiFont will automatically prepare resources for all your applications.

Build and Run

# For Android
dotnet build KanbanBoard -t:Run -f net6.0-android
# For iOS
dotnet build KanbanBoard -t:Run -f net6.0-ios
# For macOS
dotnet build KanbanBoard -t:Run -f net6.0-maccatalyst

Issues

1. Android deployment (Solved)

I was not able to deploy the application to the device until specified the RuntimeIdentifiers for Android. Add this line to your csproj file:

<RuntimeIdentifiers Condition="'$(TargetFramework)' == 'net6.0-android'">android-arm;android-arm64;android-x86;android-x64</RuntimeIdentifiers>

After some unsuccessful attempts I made it running: Kanban MAUI

You can find the code changes here: https://github.com/VladislavAntonyuk/KanbanBoard/tree/maui4

Related:

Creating Kanban Board using Xamarin Forms 5

Creating Kanban Board using Xamarin Forms 5

This article describes how to create Kanban Board using Xamarin Forms 5 only. Drag & Drop Cards, Set Column WIP, Store data in Local Db.

How to show SnackBar and Toast using Xamarin Community Toolkit

How to show SnackBar and Toast using Xamarin Community Toolkit

Demonstrate how to configure SnackBar and Toast using Xamarin Community Toolkit

An error has occurred. This application may no longer respond until reloaded. Reload 🗙