Xamarin Forms to Maui Migration

Xamarin Forms was retired on May 1, 2024. As Maui is its successor, migrating our Xamarin Forms apps to Maui is mandatory. In this article, we will focus on the migration of our projects.

Before starting the migration process, we need to check the following points.

  1. Xamarin.Forms should be in the latest version, ideally Xamarin.Forms 5, for compatibility with .NET MAUI.
  2. Review your dependencies (NuGets) and ensure they have compatible versions for .NET MAUI by searching in Google or NuGet Explorer.

Migration Approaches

  • Manual Migration: This involves manually converting your Xamarin.Forms codebase to .NET MAUI. While offering more control, it requires a deeper understanding of both frameworks and can be time-consuming for larger projects.
  • Using the .NET Upgrade Assistant: This tool automates much of the migration process, analyzing your Xamarin. Forms code and suggests necessary changes. It’s a faster option but may require manual adjustments for specific scenarios.

In this article, we will discuss manual migration. While migrating, we will encounter a lot of compile/build errors because.

  • Xamarin.Forms namespaces need to migrate to Maui (as we use ImplicitUsings, just removal of Xamarin. Forms namespace is fine).
  • Xamarin Essentials is now part of .NET Maui itself.
  • Lots of obsolete APIs in Xamarin.Forms are removed in Maui and much more.

Our first priority is fixing all build errors. Later, we will go through all screens one by one to fix UI and functionality issues.

Considering the latest .NET installed in the system with Maui.

  1. New Project: Create a new blank MAUI Project with the same name as the Xamarin Forms project. Open .csproj only keeps supported platforms removed not supported ones in TargetFrameworks and SupportedOSPlatformVersion. And Remove in Project/Platforms as well.
    Project
  2. Adding Nugets: In the .csproj PackageReference section, Maui Nuget reference has already been added, Here you need to add your project references that are Maui Compatible for Old and not Maui-supported nuggets need to find alternatives. Here are a few alternatives of mostly used packages.
  3. Adding Platform-Specific Nugets: We can add platform-specific nuggets and resources in .csproj files like below. For any unsupported Xamarin nuggets, we can add code to the project and make the necessary changes to support Maui.
    <ItemGroup Condition="( '$(TargetFramework)' == 'net8.0-android' )">
       <PackageReference Include="Xamarin.Firebase.Messaging" Version="123.1.1" />
       <PackageReference Include="Xamarin.Firebase.Analytics" Version="121.2.0" />
       <PackageReference Include="Xamarin.Android.Tooltips" Version="1.0.7" />
       <GoogleServicesJson Include="Platforms\Android\google-services.json" />
    </ItemGroup>
    <ItemGroup Condition="( '$(TargetFramework)' == 'net8.0-ios' )">
       <PackageReference Include="Xamarin.Google.iOS.SignIn" Version="5.0.2.4" />
       <PackageReference Include="Xamarin.Facebook.iOS" Version="12.2.0.1" />
       <PackageReference Include="Xamarin.Facebook.LoginKit.iOS" Version="12.2.0.1" />
       <PackageReference Include="Xamarin.Firebase.iOS.CloudMessaging" Version="8.10.0.3" />
       <PackageReference Include="Xamarin.Firebase.iOS.Analytics" Version="8.10.0.3" />
       <PackageReference Include="Xamarin.Firebase.iOS.Core" Version="8.10.0.3" />
       <BundleResource Include="Platforms\iOS\GoogleService-Info.plist" Link="GoogleService-Info.plist" />
       <BundleResource Include="Assets.xcassets\**\*" />
    </ItemGroup>
  4. Copy Code files: Copy all folders in the Xamarin shared project(.Net Standard) to the new Maui Project. And Android project files to the Platforms/Android folder respectively other platforms as well. No need to add all files and folder information in the .csproj file. Maui is smart enough to take care compile and MauiXaml information.
  5. Images: Maui supports SVG images/icons. Instead, we add platform-specific images to support all resolutions Maui does all the hard work to convert SVG to platform-specific PNG images. For more information here. As of now, you can use Android resources icons and iOS Assets. cassettes for iOS you may need to add the below line in .csproj.
    <!--For adding all files as images under Resources/Images-->
    <MauiImage Include="Resources\Images\*" />
    
    <!--For adding iOS assets images as icons instead of svgs-->
    <ItemGroup Condition="( '$(TargetFramework)' == 'net8.0-ios' )">
            <BundleResource Include="Assets.xcassets\**\*" />
    </ItemGroup>
  6. Namespace changes
  7. In.Cs Files: NET MAUI projects make use of implicit using. This feature enables you to remove using directives for the Xamarin.Forms, Xamarin.Essentialsnamespace, without having to replace them with the equivalent .NET MAUI namespaces. You can safely replace the below with empty.
    using Xamarin.Forms;
    using Xamarin.Forms.Xaml;
    using Xamarin.Essentials;
    using Xamarin.Forms.Internals;
  8. In Xaml Files.
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
  9. Change the above namespace to below.
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls"
  10. Similarly, you can replace other third-party XML namespaces. For this, you can use Visual Studio Code Replace all features (Shift-Command-F)
    XML namespaces
  11. Reuse Custom Renderers: Maui suggests using handlers over renderers because handlers offer many performance improvements. We can still use Renderes in Maui by removing it.
    [assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
    
  12. Registering in MauiProgram.cs File.
             .ConfigureMauiHandlers((handlers) =>
                {
    #if ANDROID
                    handlers.AddCompatibilityRenderer(typeof(CustomEntry), typeof(Android.Renderers.CustomEntryRenderer));
    #elif IOS
                    handlers.AddCompatibilityRenderer(typeof(CustomEntry), typeof(iOS.Renderers.CustomEntryRenderer));
    #endif
                });
  13. Reuse of effects: Maui encourages us to use handlers for UI customizations, but we can still use effects in Maui. By removing the below code and Resolve namespaces.
    using Xamarin.Forms;
    using Xamarin.Forms.Platform.*;
    
    [assembly: ResolutionGroupName("Flex.Effects")]
    [assembly: ExportEffect(typeof(CustomffectiOs), nameof(Customffect))]
    
  14. And add the effects to the program.
     .ConfigureEffects(effects =>
        {
    #if ANDROID
           effects.Add<FocusRoutingEffect, Android.Effects.FocusPlatformEffect>();
    #elif IOS
           effects.Add<FocusRoutingEffect, iOS.Effects.FocusPlatformEffect>();
    #endif
        });
  15. Dependency Service Migration: Maui Provides an Inbuilt dependency injection framework that will utilize that for Dependency service. Remove the below lines.
    [assembly: Xamarin.Forms.Dependency(typeof(ClearCookiesService))]
    
  16. And Register Dependency Service in MauiProgram.cs.
    #if ANDROID
           mauiAppBuilder.Services.AddSingleton<IClearCookies, Android.Services.ClearCookies>();
    #elif IOS
           mauiAppBuilder.Services.AddSingleton<IClearCookies, iOS.Services.ClearCookies>();
    #endif
        });
  17. Xamarin.Forms.Internals: As this mostly used list extension functions Foreach, FindIndex we can write our own extension function for this.
      public static void ForEach<T>(this IEnumerable<T> enumeration, Action<T> action)
      {
         foreach (T item in enumeration)
         {
            action(item);
         }
      }
    
      public static int FindIndex<T>(this IEnumerable<T> source, Func<T, bool> predicate)
      {
         int i = 0;
         foreach (var item in source)
         {
            if (predicate(item))
                return i;
            i++;
         }
         return -1;
      }
  18. Default spacings in stack and grid layout in Maui are zero. To Make it work the same as Xamarin, we modify styles in the app. Xaml.
    <Style TargetType="Grid">
        <Setter Property="RowSpacing" Value="6"/>
        <Setter Property="ColumnSpacing" Value="6"/>
    </Style> 
    <Style TargetType="StackLayout">
        <Setter Property="Spacing" Value="6"/>
    </Style>

Other Points

  • Application.Properties API is obsolete. Use Microsoft.Maui.Storage.Preferences instead.
  • Use Border instead of Frame
  • Change Color.Default to new Color(), Change Xamarin.Forms.Color.* to Microsoft.Maui.Graphics.Colors.*,
  • Change Color.*.ToAndroid() or.ToUIColor() to Colors.*.ToPlatform()

In this article, we’ve explained the basic process of migrating a Xamarin.Forms app to .NET MAUI. For more information, we can always look into Microsoft’s articles on migration. If you find some useful information in this article, please press like.


Similar Articles