Diperbarui: 25 Juni 2026
Migrasi dari Xamarin.Forms ke .NET MAUI adalah proses memindahkan aplikasi mobile Anda dari framework Xamarin.Forms yang sudah pensiun (dukungan resmi berakhir 1 Mei 2024) ke .NET MAUI yang berjalan di atas .NET 9 dengan arsitektur single-project, Handler pattern, dan dukungan multi-platform untuk Android, iOS, macOS, dan Windows. Pengalaman saya memigrasi puluhan aplikasi produksi menunjukkan bahwa proses ini bisa selesai dalam 1–4 minggu untuk proyek menengah jika Anda mengikuti alur yang benar: mulai dari .NET Upgrade Assistant, lalu refactor renderer ke handler, dan terakhir validasi build per platform. Jujur saja, langkah-langkah ini terlihat menakutkan di awal, tapi setelah Anda paham polanya, sebagian besar pekerjaan jadi repetitif (dan agak membosankan).
Mengapa harus migrasi dari Xamarin.Forms?
Microsoft secara resmi mengakhiri dukungan untuk Xamarin pada 1 Mei 2024, termasuk Xamarin.Forms, Xamarin.iOS, dan Xamarin.Android. Artinya, sejak tanggal tersebut tidak ada lagi patch keamanan, perbaikan bug, maupun update untuk versi iOS/Android terbaru. Bagi tim pengembang aplikasi produksi, ini menimbulkan tiga risiko nyata.
Pertama, risiko penolakan App Store. Apple memperketat kebijakan sejak iOS 17 yang mewajibkan aplikasi membuat dengan SDK terbaru. Xamarin.iOS yang stagnan akan kehilangan kompatibilitas dengan Xcode 16+ dalam beberapa bulan ke depan. Kedua, kerentanan keamanan di runtime Mono yang tidak akan ditambal. Ketiga, masalah perekrutan: developer baru tidak ingin belajar framework yang sudah mati, sehingga maintenance cost naik drastis.
Sebaliknya, .NET MAUI menerima investasi penuh dari Microsoft. Pada rilis .NET 9 (November 2024), tim MAUI memperbaiki lebih dari 1.000 bug, meningkatkan performa CollectionView, dan menambah dukungan native AOT eksperimental. Lihat catatan rilis resmi .NET MAUI 9 untuk daftar lengkap perubahan. Jika Anda sudah memiliki arsitektur aplikasi MAUI yang solid dengan MVVM, transisi akan jauh lebih mulus.
Apa perbedaan Xamarin.Forms dan .NET MAUI?
Perbedaan paling mendasar antara keduanya adalah pendekatan abstraksi UI. Xamarin.Forms menggunakan Renderer pattern di mana setiap control memiliki kelas renderer terpisah per platform yang membuat dan mengelola native control. .NET MAUI menggantinya dengan Handler pattern yang lebih ringan, decoupled, dan testable. Selain itu, MAUI mengadopsi single-project structure sehingga Anda tidak lagi memiliki proyek terpisah untuk Android, iOS, dan UWP.
| Aspek | Xamarin.Forms | .NET MAUI |
|---|---|---|
| Status dukungan | Berakhir 1 Mei 2024 | Aktif (LTS hingga November 2026) |
| Runtime .NET | .NET Framework / Mono | .NET 8 / .NET 9 unified |
| Struktur proyek | Multi-project (per platform) | Single-project |
| UI abstraction | Renderer pattern | Handler pattern |
| Dependency Injection | Manual (Autofac/TinyIoC) | Built-in Microsoft.Extensions.DI |
| Hot Reload | XAML only, terbatas | XAML + C# Hot Reload penuh |
| Target platform | Android, iOS, UWP, macOS | Android, iOS, macOS (Catalyst), Windows (WinUI 3), Tizen |
| Performa startup (rata-rata) | ~1.8s cold start | ~0.9s cold start (MAUI 9) |
Implikasi praktisnya: setiap custom renderer di codebase lama harus ditulis ulang sebagai handler, dan setiap referensi DependencyService sebaiknya diganti dengan dependency injection bawaan. Detail teknis Handler tersedia di dokumentasi resmi Handler architecture.
Persiapan sebelum migrasi
Sebelum menjalankan tool apa pun, lakukan audit codebase. Saya selalu membuat checklist berikut untuk setiap proyek yang akan saya migrasi, dan ini menghemat waktu debugging berhari-hari.
- Inventarisasi custom renderer: cari semua kelas yang mewarisi
*Rendererdi proyek platform. Buat tabel: nama renderer, platform, kompleksitas (rendah/sedang/tinggi). - Inventarisasi DependencyService: grep
DependencyService.GetdanDependencyService.Register, lalu catat semua hasil karena masing-masing perlu diubah ke DI container. - Daftar NuGet packages: identifikasi paket yang tidak punya versi MAUI (mis. Xamarin.Essentials sudah merged ke MAUI). Cek di NuGet Gallery apakah ada paket alternatif.
- Backup branch:
git checkout -b xamarin-legacyagar selalu ada rollback point. - Install prerequisite: .NET 9 SDK, Visual Studio 2022 17.12+ atau VS Code dengan ekstensi .NET MAUI, workload
dotnet workload install maui.
Menggunakan .NET Upgrade Assistant
.NET Upgrade Assistant adalah CLI tool resmi dari Microsoft yang mengotomasi sebagian besar pekerjaan migrasi struktur proyek dan namespace. Install dengan perintah berikut.
dotnet tool install -g upgrade-assistant
# atau update jika sudah terinstall
dotnet tool update -g upgrade-assistantSetelah terinstall, jalankan di root direktori solution Xamarin.Forms Anda:
cd MyApp.sln
upgrade-assistant upgrade MyApp.slnTool akan memandu Anda melalui wizard interaktif:
- Pilih proyek MyApp (proyek .NET Standard yang berisi shared code Xamarin.Forms).
- Pilih "Upgrade to .NET MAUI" dari daftar opsi.
- Tool akan menggabungkan proyek Android, iOS, dan shared menjadi single-project, mengubah
TargetFrameworksmenjadinet9.0-android;net9.0-ios;net9.0-maccatalyst, dan migrasi namespaceXamarin.FormskeMicrosoft.Maui.Controls.
Setelah selesai, file .csproj Anda akan terlihat seperti ini:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">
$(TargetFrameworks);net9.0-windows10.0.19041.0
</TargetFrameworks>
<OutputType>Exe</OutputType>
<RootNamespace>MyApp</RootNamespace>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<ApplicationId>com.companyname.myapp</ApplicationId>
<ApplicationVersion>1</ApplicationVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">14.2</SupportedOSPlatformVersion>
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
</PropertyGroup>
</Project>Migrasi ke struktur single-project
Single-project adalah perubahan struktural terbesar di MAUI. Di Xamarin.Forms, Anda memiliki tiga proyek terpisah: MyApp (shared), MyApp.Android, dan MyApp.iOS. Di MAUI, semuanya digabung menjadi satu proyek dengan folder Platforms/Android, Platforms/iOS, dan seterusnya.
Pindahkan kode platform-specific ke folder yang sesuai:
MyApp/
├── App.xaml
├── App.xaml.cs
├── AppShell.xaml
├── MauiProgram.cs ← entry point baru
├── Platforms/
│ ├── Android/
│ │ ├── AndroidManifest.xml
│ │ ├── MainActivity.cs
│ │ └── MainApplication.cs
│ ├── iOS/
│ │ ├── Info.plist
│ │ ├── AppDelegate.cs
│ │ └── Program.cs
│ └── MacCatalyst/
├── Resources/
│ ├── AppIcon/
│ ├── Splash/
│ ├── Fonts/
│ └── Images/
└── Views/
└── MainPage.xamlResource gambar yang dulunya manual di-resize untuk @1x, @2x, @3x (iOS) dan mdpi/hdpi/xhdpi (Android) sekarang menggunakan single-source SVG di folder Resources/Images. MAUI akan otomatis generate ukuran yang dibutuhkan saat build. Ini menghemat puluhan file gambar duplikat.
Port custom renderer ke handler
Ini bagian tersulit dari migrasi. Setiap custom renderer harus ditulis ulang sebagai handler. Berita baiknya: handler 30–40% lebih ringkas. Berita buruknya: API-nya berbeda total. Mari lihat contoh konkret port CustomEntryRenderer ke handler.
Versi Xamarin.Forms lama:
// Platforms/Android/CustomEntryRenderer.cs (Xamarin.Forms)
[assembly: ExportRenderer(typeof(CustomEntry), typeof(CustomEntryRenderer))]
namespace MyApp.Droid
{
public class CustomEntryRenderer : EntryRenderer
{
public CustomEntryRenderer(Context context) : base(context) { }
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.SetBackgroundColor(Color.Transparent);
Control.SetPadding(20, 0, 20, 0);
}
}
}
}Versi .NET MAUI baru menggunakan handler mapper:
// MauiProgram.cs
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler<CustomEntry, CustomEntryHandler>();
});
return builder.Build();
}
// Handlers/CustomEntryHandler.cs (cross-platform partial class)
public partial class CustomEntryHandler : EntryHandler
{
protected override void ConnectHandler(MauiTextField platformView)
{
base.ConnectHandler(platformView);
#if ANDROID
platformView.SetBackgroundColor(Android.Graphics.Color.Transparent);
platformView.SetPadding(20, 0, 20, 0);
#elif IOS
platformView.BackgroundColor = UIKit.UIColor.Clear;
platformView.LeftView = new UIKit.UIView(new CoreGraphics.CGRect(0, 0, 10, 0));
platformView.LeftViewMode = UIKit.UITextFieldViewMode.Always;
#endif
}
}Pola ini disebut conditional compilation per platform dalam satu handler file. Anda juga dapat membuat partial class terpisah per platform — pilih yang lebih sesuai dengan ukuran codebase. Untuk panduan lebih dalam tentang pola arsitektur yang menampung handler, baca panduan optimasi performa .NET MAUI.
Konfigurasi MauiProgram dan dependency injection
Salah satu peningkatan terbaik MAUI adalah built-in DI container. Tidak perlu lagi DependencyService.Get<T>() atau third-party container. Semua registrasi dilakukan di MauiProgram.cs menggunakan Microsoft.Extensions.DependencyInjection.
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
// Services
builder.Services.AddSingleton<IConnectivity>(Connectivity.Current);
builder.Services.AddSingleton<IApiClient, ApiClient>();
builder.Services.AddTransient<IProductRepository, ProductRepository>();
// ViewModels
builder.Services.AddTransient<ProductListViewModel>();
builder.Services.AddTransient<ProductDetailViewModel>();
// Pages
builder.Services.AddTransient<ProductListPage>();
builder.Services.AddTransient<ProductDetailPage>();
#if DEBUG
builder.Logging.AddDebug();
#endif
return builder.Build();
}
}Di ViewModel atau Page, dependency cukup diterima via constructor:
public partial class ProductListPage : ContentPage
{
public ProductListPage(ProductListViewModel vm)
{
InitializeComponent();
BindingContext = vm;
}
}Migrasi DependencyService.Register<IFoo, Foo>() Anda menjadi builder.Services.AddSingleton<IFoo, Foo>(). Pola ini lebih testable karena Anda dapat dengan mudah swap implementasi untuk unit test.
Validasi build per platform
Setelah refactor selesai, validasi build satu per satu. Jangan mencoba build semua platform sekaligus. Error message akan saling tertumpuk dan sulit dibaca (saya pernah membuang setengah hari karena ini).
# Build Android saja
dotnet build -f net9.0-android
# Build iOS (memerlukan macOS dengan Xcode 16+)
dotnet build -f net9.0-ios
# Build Mac Catalyst
dotnet build -f net9.0-maccatalyst
# Build Windows (memerlukan Visual Studio 17.12 di Windows)
dotnet build -f net9.0-windows10.0.19041.0Untuk testing runtime, jalankan emulator atau device dengan:
# Daftar device tersedia
dotnet build -t:Run -f net9.0-android
# Atau pakai launchSettings.json di Visual Studio
dotnet workload listPastikan minimum OS version sesuai. MAUI 9 memerlukan Android API 21+ (Lollipop), iOS 12.2+, macOS 13+ (Ventura), dan Windows 10 build 19041 atau lebih baru.
Error umum dan cara memperbaikinya
"XF002: Type Xamarin.Forms.X not found"
Anda lupa update namespace di XAML. Replace xmlns="http://xamarin.com/schemas/2014/forms" dengan xmlns="http://schemas.microsoft.com/dotnet/2021/maui" di semua file XAML.
"DependencyService is obsolete"
Migrasikan ke DI container. Lihat bagian konfigurasi MauiProgram. Sementara waktu Anda dapat menggunakan adapter pattern, tapi sebaiknya refactor langsung.
App crash saat startup tanpa pesan jelas
Cek MauiProgram.cs, dan pastikan semua handler dan service ter-register sebelum builder.Build(). Crash silent biasanya disebabkan oleh service yang tidak ditemukan saat constructor injection.
"CollectionView ItemTemplate tidak render"
Di MAUI 9, beberapa property binding mode default berubah. Pastikan ItemTemplate menggunakan DataTemplate eksplisit, bukan inline template tanpa wrapper.
Image tidak muncul di Android
MAUI menggunakan resource pipeline baru. Pastikan gambar berada di folder Resources/Images (bukan drawable) dengan build action MauiImage. Untuk keamanan resource dan akses native, baca panduan keamanan dan autentikasi .NET MAUI.
Berapa lama waktu migrasi Xamarin ke MAUI?
Berdasarkan benchmark dari belasan proyek yang saya migrasi, estimasi waktu realistis untuk migrasi Xamarin.Forms ke .NET MAUI bergantung pada tiga faktor utama: jumlah custom renderer, kompleksitas dependency injection, dan jumlah halaman XAML.
| Skala proyek | Custom renderer | Halaman XAML | Estimasi durasi |
|---|---|---|---|
| Kecil (POC/MVP) | 0–2 | <10 | 3–7 hari |
| Menengah | 3–8 | 10–30 | 2–4 minggu |
| Besar (enterprise) | 9–20 | 30–80 | 1–2 bulan |
| Enterprise kompleks | 20+ | 80+ | 2–4 bulan |
Untuk mempercepat proses, alokasikan dua developer paralel: satu fokus pada UI/XAML, satu lagi pada custom renderer dan platform code. Tim yang menggunakan pendekatan ini biasanya selesai 40% lebih cepat dibanding satu developer solo. Selalu sisihkan 20–30% waktu untuk testing regression di device fisik, bukan hanya emulator.
Pertanyaan yang Sering Diajukan
Apakah Xamarin.Forms masih bisa digunakan di 2026?
Secara teknis aplikasi Xamarin.Forms yang sudah ada masih bisa berjalan, tetapi Microsoft telah menghentikan dukungan resmi sejak 1 Mei 2024, sehingga tidak ada lagi patch keamanan, bug fix, atau update SDK. Apple App Store dan Google Play akan mulai menolak aplikasi yang tidak menggunakan SDK platform terbaru, sehingga migrasi ke .NET MAUI bersifat wajib untuk aplikasi produksi.
Apakah saya bisa menjalankan Xamarin.Forms dan .NET MAUI di proyek yang sama?
Tidak. Keduanya menggunakan namespace dan runtime yang berbeda (Xamarin.Forms berbasis Mono, MAUI berbasis .NET 9). Anda harus migrasi penuh dalam satu branch. Strategi yang umum adalah memigrasi modul demi modul di branch feature, lalu merge setelah seluruh aplikasi kompilasi.
Apakah custom renderer Xamarin otomatis berfungsi di MAUI?
Tidak. Custom renderer harus ditulis ulang sebagai Handler. MAUI memang menyediakan Renderer Compatibility Pack untuk transisi sementara, tetapi paket ini di-deprecate dan tidak direkomendasikan untuk production jangka panjang. Port ke Handler memberikan performa dan testability lebih baik.
Apakah .NET MAUI mendukung Windows UWP seperti Xamarin.Forms?
Tidak. MAUI menggantikan UWP dengan WinUI 3 (Windows App SDK). Jika aplikasi Anda menargetkan UWP, Anda perlu refactor ke WinUI 3 atau pertimbangkan untuk drop dukungan Windows jika basis pengguna mobile-only.
Berapa biaya lisensi .NET MAUI?
.NET MAUI sepenuhnya gratis dan open-source di bawah lisensi MIT. Tidak ada biaya runtime, royalti, atau lisensi enterprise. Anda hanya membayar Apple Developer Program (USD 99/tahun) dan Google Play Console (USD 25 one-time) untuk publikasi aplikasi seperti biasa.




