Расскажите про ваш опыт миграции Xamarin-приложений на .NET MAUI.

Миграция Xamarin-приложения на .NET MAUI (Multi-platform App UI) представляет собой стратегический и технический процесс, который требует глубокой подготовки, понимания архитектуры приложения и особенностей новых технологий. MAUI — это эволюция Xamarin.Forms, построенная на .NET 6/7/8, с целью унификации и упрощения кроссплатформенной разработки для Android, iOS, Windows и macOS.

Ниже подробно описан реальный опыт миграции большого корпоративного Xamarin.Forms-приложения на .NET MAUI, включая этапы, трудности и решения.

1. Предварительный аудит Xamarin-проекта

Перед началом миграции была проведена полная инвентаризация проекта:

  • Проверка версии Xamarin.Forms и зависимостей NuGet.

  • Анализ используемых платформенных API через DependencyService.

  • Поиск кастомных рендереров, эффектов, behavior'ов.

  • Выделение UI-слоя, бизнес-логики, сервисов, моделей.

  • Проверка unit-тестов и UI-тестов (на NUnit + Xamarin.UITest).

Также были оценены критические точки, не поддерживаемые напрямую в MAUI, например:

  • Custom Renderers → Handlers

  • MessagingCenter → EventAggregator или CommunityToolkit.MVVM

  • ResourceDictionary → пересмотр структуры

  • Shell-архитектура → изменения в навигации

2. Обновление к .NET 6/.NET 7 и MAUI workload

На этом этапе была подготовлена среда:

  • Установлены:

    • .NET SDK 6, 7 и 8

    • dotnet workload install maui

    • Visual Studio 2022/2023 с MAUI workload

  • Проект переведён на однофайловую .csproj-структуру

  • Создана новая MAUI-заготовка с типом dotnet new maui

3. Миграция общих библиотек

Бизнес-логика, модели и сервисы уже были размещены в .NET Standard 2.0 библиотеке. Для совместимости с MAUI она была:

  • Переведена в net6.0 или netstandard2.1

  • Пересобрана без изменений — основная логика не требует переписывания

  • Тесты также были переведены на xUnit с net6.0

Этап прошёл практически безболезненно благодаря слабой связности с UI.

4. Перенос UI-слоя

А. Разметка XAML

  • Поддержка XAML в MAUI сохраняется, однако:

    • Устаревшие свойства были удалены (Device.RuntimePlatform)

    • Были заменены OnPlatform, OnIdiom на DeviceInfo и AppThemeBinding

    • Импорты XMLNS переопределены под Microsoft.Maui.Controls

Б. Code-behind

  • Подключение событий, команд и BindingContext осталось аналогичным.

  • Требовалось заменить платформенные вызовы, особенно Android/Java API.

В. Shell

  • Структура навигации Shell практически полностью переносима.

  • Однако Routing.RegisterRoute() и URI-навигация требовали пересмотра.

  • Добавлены новые возможности FlyoutItem, TabBar, ShellContent.

5. Custom Renderers → Handlers

Одной из самых сложных частей стало переписывание Custom Renderer'ов.

  • В MAUI вместо Renderer используется Handler + Mapper API.

  • Пример перехода:

// В Xamarin
\[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))\]
// В MAUI
public class MyEntryHandler : EntryHandler
{
public MyEntryHandler() : base(Mapper)
{
}
public static IPropertyMapper<Entry, MyEntryHandler> Mapper =
new PropertyMapper<Entry, MyEntryHandler>(EntryHandler.Mapper)
{
\[nameof(MyEntry.BorderColor)\] = MapBorderColor
};
static void MapBorderColor(IEntryHandler handler, Entry entry)
{
// Платформенно-специфичная логика
}
}
  • Требовалась миграция платформозависимых директорий (Platforms/Android, Platforms/iOS и т.д.)

6. DependencyService → Dependency Injection

MAUI использует встроенный DI через Microsoft.Extensions.DependencyInjection.

  • В Program.cs регистрировались сервисы:
builder.Services.AddSingleton<IMyService, MyService>();
  • Устаревшие вызовы DependencyService.Get<IMyService>() были заменены на DI-инъекции через конструктор:
public class MainViewModel
{
private readonly IMyService \_service;
public MainViewModel(IMyService service)
{
\_service = service;
}
}

7. Платформенный код

Многие платформенные зависимости, ранее реализованные через DependencyService и MainActivity.cs/AppDelegate.cs, были перенесены в соответствующие каталоги:

  • Platforms/Android/MainActivity.cs

  • Platforms/iOS/AppDelegate.cs

Для MAUI предусмотрены partial-классы, которые объединяются во время компиляции.

8. Использование MAUI Community Toolkit

Для компенсации недостающих функций Xamarin.Forms были добавлены:

  • CommunityToolkit.Maui:

    • Behaviors

    • Converters

    • SnackBar, Toast

    • ObservableObject / RelayCommand

Установка:

dotnet add package CommunityToolkit.Maui

И регистрация в Program.cs:

builder.UseMauiCommunityToolkit();

9. Тестирование и отладка

  • Основной фокус сделан на юнит-тестах: они работали без изменений.

  • UI-тесты были адаптированы к новым деревьям элементов.

  • Использовались:

    • Visual Studio MAUI Hot Reload

    • MAUI Previewer

    • Debug Proxies for ViewModels

10. Интеграция CI/CD

CI/CD пайплайны для GitHub Actions и Azure DevOps были обновлены:

  • Добавлены команды:

    • dotnet workload install maui

    • dotnet build -f net7.0-ios

    • dotnet build -f net7.0-android

  • Подключены новые ключи для .keystore и .p12

  • Переписаны публикационные шаги через fastlane

11. Итоговая архитектура после миграции

  • Переход на MVVM Toolkit вместо стороннего MVVM-фреймворка

  • Использование Shell + DI + Handlers

  • Single Project модель с платформенными папками

  • Unified ресурсные файлы (Resources/Images, Resources/Styles, Resources/Raw)

Миграция показала, что проект с чистой архитектурой, модульной логикой и слабой зависимостью от UI легко адаптируется под .NET MAUI. Однако наличие большого количества кастомных решений (рендереров, эффектов, платформенных вызовов) требует дополнительного времени и проектирования. Эффективный переход требует пошагового подхода, разбивки миграции на фазы и тщательного тестирования.