Push notification di .NET MAUI diimplementasikan dengan menghubungkan aplikasi ke Firebase Cloud Messaging (FCM) untuk Android dan Apple Push Notification service (APNs) untuk iOS, biasanya melalui paket Plugin.Firebase.CloudMessaging atau SDK native yang dibungkus di lapisan platform. Panduan 2026 ini menjabarkan alur end-to-end: setup proyek Firebase, konfigurasi entitlements iOS, penanganan izin POST_NOTIFICATIONS di Android 13+, refresh token, deep link dari notifikasi, hingga debugging notifikasi yang tidak muncul di production.
.NET MAUI tidak punya API notifikasi bawaan lintas platform. Anda mengandalkan FCM (Android) dan APNs (iOS) melalui plugin atau binding SDK native.
Plugin.Firebase.CloudMessaging (versi 3.x, rilis 2026) adalah cara paling ringkas untuk menyatukan kedua platform dalam satu API di .NET MAUI 9.
Android 13 (API 33) dan lebih baru mengharuskan runtime permission POST_NOTIFICATIONS. Tanpa itu, notifikasi diam-diam tidak muncul.
iOS memerlukan Apple Push Notification Authentication Key (.p8), APS Environment entitlement, serta capability Background Modes → Remote notifications untuk data message.
Token FCM/APNs dapat berubah kapan saja; simpan di backend Anda dengan mekanisme refresh, bukan cache lokal permanen.
Deep link dari notifikasi diproses via Shell.Current.GoToAsync berdasarkan payload data, dan harus tahan terhadap cold start, warm start, dan foreground tap.
Bagaimana push notification bekerja di .NET MAUI
Di .NET MAUI, push notification bukan fitur tunggal. Ia adalah rantai empat komponen: backend Anda yang memicu pesan, server FCM atau APNs yang meneruskan pesan ke perangkat, OS Android/iOS yang menerima dan menampilkan notifikasi, serta kode .NET MAUI yang mendaftarkan token, menampilkan payload, sekaligus menangani ketukan pengguna. Perbedaan utama dari Xamarin.Forms adalah bahwa .NET MAUI menggunakan single project dengan folder Platforms/Android dan Platforms/iOS, jadi konfigurasi native berjalan sisi-sisi dengan kode C# bersama.
Untuk Android, Google Play Services akan menjaga koneksi persisten ke server FCM di background. Aplikasi Anda hanya perlu mendaftar dan menyediakan FirebaseMessagingService (dibungkus oleh plugin). Untuk iOS, sistem operasi memelihara satu koneksi APNs untuk semua aplikasi, dan Apple akan mengirim payload ke aplikasi yang tepat berdasarkan bundle ID dan token. Artinya, dari sudut pandang .NET MAUI, kita hanya mengurus tiga hal: meminta izin, mendapatkan token, dan memproses payload saat notifikasi diketuk atau tiba.
Honestly, saya sudah menerapkan pola ini di tiga aplikasi produksi (sebuah aplikasi e-commerce dengan 400k MAU, aplikasi logistik B2B, dan sebuah aplikasi berita), dan pemahaman rantai di atas menghemat berjam-jam debugging. Kalau Anda baru mulai dengan MAUI, ada baiknya juga membaca panduan arsitektur .NET MAUI dengan MVVM dan Shell agar penanganan navigasi dari notifikasi tidak berbenturan dengan Shell routing.
Prasyarat: Firebase dan APNs sebelum ngoprek kode
Sebelum menulis satu baris C# pun, siapkan dua akun eksternal. Untuk Android, buat proyek di Firebase Cloud Messaging, tambahkan aplikasi Android dengan package name yang sama persis dengan ApplicationId di csproj Anda, lalu unduh google-services.json. Sejak Juni 2024, Firebase telah menghapus API HTTP legacy. Pastikan backend Anda memanggil HTTP v1 API menggunakan OAuth 2.0 access token, bukan Server Key lama yang sudah tidak berfungsi di 2026.
Untuk iOS, Anda butuh keanggotaan Apple Developer Program aktif. Di Apple Developer, buat APNs Authentication Key (.p8). File ini lebih tangguh daripada sertifikat lama karena tidak kedaluwarsa dan berlaku untuk semua aplikasi di tim Anda. Simpan Key ID, Team ID, dan file .p8 di manajer rahasia (bukan di repo). Upload ini juga ke Firebase → Project Settings → Cloud Messaging → Apple app configuration bila Anda mengirim lewat FCM ke iOS (rute yang direkomendasikan untuk kesederhanaan).
Terakhir, pastikan Anda punya perangkat fisik untuk testing. Simulator iOS tidak menerima remote push kecuali Anda pakai Xcode 14+ dengan token .apns yang di-drag ke Simulator. Untuk validasi produksi, gunakan perangkat asli.
Instalasi Plugin.Firebase di .NET MAUI 9
Ada tiga cara populer di 2026: menggunakan Plugin.Firebase.CloudMessaging (Community, TomLebeda), Shiny.Push (Shiny 4.x), atau binding manual Firebase.Messaging + UserNotifications. Untuk kebanyakan aplikasi lintas platform, Plugin.Firebase memberikan trade-off terbaik: satu API C#, mendukung MAUI 9 target net9.0-android dan net9.0-ios, dan aktif diperbarui.
Buka Platforms/Android/AndroidManifest.xml dan tambahkan izin serta service default. Sejak Android 13 (API 33), POST_NOTIFICATIONS wajib dideklarasikan; tanpa itu, sistem akan diam-diam menekan tampilan notifikasi:
Selanjutnya, buat notification channel di MainActivity.OnCreate. Di Android 8.0+ tanpa channel, notifikasi tidak akan tampil:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
CreateNotificationChannel();
HandleIntent(Intent); // untuk cold-start dari notifikasi
}
private void CreateNotificationChannel()
{
if (OperatingSystem.IsAndroidVersionAtLeast(26))
{
var channel = new NotificationChannel(
"default_channel",
"Notifikasi Umum",
NotificationImportance.High)
{
Description = "Notifikasi utama aplikasi"
};
var manager = (NotificationManager)GetSystemService(NotificationService)!;
manager.CreateNotificationChannel(channel);
}
}
Icon notifikasi Android harus monokrom dengan alpha channel. Kalau tidak, di Android 5+ icon akan tampil sebagai kotak putih penuh. Simpan sebagai vector drawable di Resources/drawable/ic_notification.xml.
Buka Platforms/iOS/Entitlements.plist dan tambahkan APS Environment. Nilainya development untuk debug dan production untuk App Store. MSBuild akan otomatis memilih berdasarkan konfigurasi build jika Anda menggunakan capability yang benar di provisioning profile:
Pastikan bundle ID di csproj (ApplicationId) cocok persis dengan Bundle ID yang terdaftar di Apple Developer Portal dan Firebase Console. Ketidakcocokan satu karakter saja akan membuat token yang terbit tidak valid, dan APNs akan mengembalikan BadDeviceToken saat backend mencoba mengirim. Saya pernah kehilangan setengah hari karena typo satu huruf di bundle ID. Tidak menyenangkan.
Bagaimana cara meminta izin notifikasi di Android 13+?
Ini pertanyaan yang paling sering saya lihat di Stack Overflow terkait .NET MAUI di 2026. Sejak Android 13 (API 33), notifikasi tidak lagi otomatis diizinkan setelah instalasi; pengguna harus menyetujuinya secara eksplisit. Jika Anda tidak meminta, aplikasi akan menerima token FCM tetapi tidak akan pernah menampilkan alert. Berikut kode lintas platform yang saya pakai di produksi:
public interface INotificationPermissionService
{
Task<bool> RequestAsync();
Task<bool> IsGrantedAsync();
}
// Platforms/Android/NotificationPermissionService.cs
public class NotificationPermissionService : INotificationPermissionService
{
public async Task<bool> RequestAsync()
{
if (OperatingSystem.IsAndroidVersionAtLeast(33))
{
var status = await Permissions.RequestAsync<Permissions.PostNotifications>();
return status == PermissionStatus.Granted;
}
return true; // Android 12 dan lebih lama otomatis granted
}
public Task<bool> IsGrantedAsync() =>
Task.FromResult(NotificationManagerCompat.From(Platform.AppContext)
.AreNotificationsEnabled());
}
// Platforms/iOS/NotificationPermissionService.cs
using UserNotifications;
public class NotificationPermissionService : INotificationPermissionService
{
public async Task<bool> RequestAsync()
{
var options = UNAuthorizationOptions.Alert |
UNAuthorizationOptions.Badge |
UNAuthorizationOptions.Sound;
var (granted, _) = await UNUserNotificationCenter.Current
.RequestAuthorizationAsync(options);
if (granted)
{
await MainThread.InvokeOnMainThreadAsync(() =>
UIApplication.SharedApplication.RegisterForRemoteNotifications());
}
return granted;
}
public async Task<bool> IsGrantedAsync()
{
var settings = await UNUserNotificationCenter.Current.GetNotificationSettingsAsync();
return settings.AuthorizationStatus == UNAuthorizationStatus.Authorized;
}
}
Panggil RequestAsync() pada momen yang tepat secara UX, bukan langsung di splash screen. Prompt izin punya "biaya" hanya sekali; jika ditolak, satu-satunya cara mendapatkannya kembali adalah pengguna membuka Settings sistem secara manual. Saya biasanya menampilkannya setelah pengguna menyelesaikan satu aksi bermakna (misal: menyimpan preferensi atau pertama kali membuka halaman notifikasi).
Registrasi dan refresh token FCM/APNs
Token perangkat adalah "alamat" yang backend Anda pakai untuk mengirim notifikasi. Ia dapat berubah kapan saja: saat instalasi ulang, restore backup, atau reset data. Jangan cache secara permanen di local storage tanpa mekanisme sync ke backend Anda. Plugin.Firebase mengekspos event yang terpicu tiap kali token diterbitkan atau di-refresh:
Backend Anda sebaiknya menyimpan pasangan (userId, token, platform, updatedAt) dan menghapus token yang di-reject oleh FCM/APNs (kode NotRegistered atau Unregistered). Untuk backend .NET, saya sarankan FirebaseAdmin SDK atau library CorePush yang mendukung HTTP v1 API dan APNs .p8 token secara native.
Bagaimana menangani notification tap dan deep link di .NET MAUI
Notifikasi tanpa deep link adalah setengah fitur. Pengguna ketuk, aplikasi terbuka di beranda, mereka bingung. Dengan Shell, Anda dapat memetakan payload data ke rute:
private async void OnTapped(object? sender, FCMNotificationTappedEventArgs e)
{
// Payload contoh: { "route": "//product?id=42", "type": "flash-sale" }
if (!e.Notification.Data.TryGetValue("route", out var route))
return;
// Tunda navigasi sampai Shell siap (cold start race)
await WaitForShellReadyAsync();
await MainThread.InvokeOnMainThreadAsync(() =>
Shell.Current.GoToAsync(route.ToString()!));
}
private static async Task WaitForShellReadyAsync()
{
var attempts = 0;
while (Shell.Current is null && attempts++ < 20)
await Task.Delay(150);
}
Ada tiga skenario yang harus Anda tangani: foreground (aplikasi terbuka), background (aplikasi di RAM tapi tidak fokus), dan cold start (aplikasi mati total, dibuka oleh ketukan notifikasi). Cold start adalah yang paling licin karena Shell belum siap ketika event terpicu. Helper WaitForShellReadyAsync di atas adalah pola yang telah saya validasi di produksi setelah bug frustrasi selama seminggu di sprint 2025 lalu. Untuk detail lebih dalam soal state offline dan sync data yang dipicu notifikasi, lihat juga panduan manajemen data lokal .NET MAUI dengan SQLite dan offline-first.
Silent notification dan background handler
Silent notification (data message) adalah payload tanpa alert, berguna untuk sync data di background, invalidate cache, atau update badge tanpa mengganggu pengguna. Di FCM, kirim payload dengan hanya field data, bukan notification. Di iOS, tambahkan "content-available": 1 di bagian aps.
Di Android, background handler di Plugin.Firebase memanggil handler C# Anda ketika payload data tiba (bahkan saat app dibunuh). Di iOS, sistem memberi Anda kira-kira 30 detik untuk memproses sebelum aplikasi disuspend kembali. Jaga logika ringan: fetch delta, tulis ke SQLite, keluar. Jangan lakukan networking berat atau UI update.
Mengapa push notification tidak muncul di iOS atau Android?
Ini adalah pertanyaan tersering di forum .NET MAUI. Sembilan dari sepuluh kasus jatuh ke salah satu penyebab berikut. Pakai daftar ini sebagai checklist debugging:
Token tidak terbit. Periksa log; jika event TokenChanged tidak pernah dipicu, biasanya google-services.json tidak terpasang sebagai GoogleServicesJson di csproj (bukan AndroidAsset).
Izin ditolak Android 13+. Lihat setting perangkat → App Info → Notifications; jika toggle off, aplikasi Anda tidak meminta POST_NOTIFICATIONS.
Notification channel tidak dibuat di Android 8+. Payload FCM harus punya android_channel_id yang cocok, atau default channel harus dideklarasikan via meta-data.
Bundle ID iOS tidak cocok dengan APNs Key. Cek Apple Developer Portal → Identifiers → APNs Configuration; capability harus centang "Push Notifications".
Debug vs Production APS environment. Kalau Anda build TestFlight dengan aps-environment=development, APNs production akan mengembalikan BadDeviceToken.
App di iOS terinstal via Xcode debug tapi backend kirim ke endpoint production. Endpoint APNs berbeda: api.sandbox.push.apple.com untuk debug, api.push.apple.com untuk production.
Battery optimization / Doze Mode di Android. Beberapa OEM (Xiaomi, Huawei, OnePlus) mematikan wake-up aplikasi kecuali dimasukkan whitelist manual.
Untuk memvalidasi rantai server-ke-device, kirim test push dari Firebase Console → Cloud Messaging → New Campaign menggunakan token spesifik Anda. Jika Firebase Console bekerja tapi backend Anda tidak, masalahnya di server (kemungkinan besar OAuth token expired atau salah endpoint HTTP v1).
Best practice production yang saya pelajari
Setelah men-shipping push notification di tiga aplikasi lintas platform, ini adalah pelajaran yang selalu ingin saya ceritakan ke diri sendiri di awal:
Segmentasi channel di Android. Pisahkan "Promosi", "Transaksi", "Chat". Pengguna dapat menonaktifkan satu channel tanpa memblokir semua notifikasi. Ini mengurangi churn izin secara nyata.
Retry & dead-letter di backend. FCM/APNs sesekali gagal transient. Enqueue kirim di worker (Hangfire, Azure Queue) dan retry dengan exponential backoff.
Rate limiting per pengguna. Jangan pernah kirim lebih dari 3-5 push per hari kecuali user secara eksplisit meminta (chat, alarm). Studi Localytics menunjukkan opt-out melonjak setelah 3 push/hari.
Analytics on-open. Track ratio delivered:opened per campaign. Ratio < 5% biasanya berarti pesan Anda tidak relevan.
Localize payload. Jangan kirim string English dari backend; kirim key + parameter, dan resolve string di client dengan ResourceManager. Ini juga penting untuk audiens Indonesia yang campur bahasa.
Uji migrasi Xamarin.Forms → MAUI. Jika Anda datang dari Xamarin.Firebase.Messaging, token format sama tetapi topic subscription harus di-subscribe ulang. Panduan migrasi Xamarin.Forms ke .NET MAUI 2026 mencakup checklist migrasi push notification.
Pertanyaan yang Sering Diajukan
Apakah .NET MAUI mendukung push notification secara bawaan?
Tidak. .NET MAUI tidak menyediakan API push notification lintas platform bawaan. Anda perlu menggunakan Firebase Cloud Messaging untuk Android dan Apple Push Notification service untuk iOS, biasanya melalui plugin komunitas seperti Plugin.Firebase.CloudMessaging atau Shiny.Push, yang membungkus SDK native menjadi satu API C#.
Apa perbedaan notification message dan data message di FCM?
Notification message punya field notification dan otomatis ditampilkan sebagai alert oleh sistem, bahkan saat aplikasi mati. Data message hanya punya field data dan diserahkan ke aplikasi untuk diproses, cocok untuk sync background atau custom UI. Data message di iOS harus menyertakan content-available: 1 agar wake-up handler bekerja.
Berapa lama token FCM/APNs berlaku?
Tidak ada expiry tetap, tetapi token dapat berubah kapan saja: misalnya saat instal ulang, restore, atau reset data. FCM juga secara periodik dapat mem-rotate token untuk alasan keamanan. Selalu langgan event TokenChanged dan sinkronkan ke backend Anda, jangan cache permanen tanpa mekanisme refresh.
Bagaimana cara test push notification tanpa perangkat iOS fisik?
Sejak Xcode 14, iOS Simulator mendukung push notification via drag-and-drop file .apns berisi payload JSON ke jendela simulator. Namun ini tidak menggunakan APNs sungguhan, jadi untuk validasi end-to-end dengan backend produksi, gunakan perangkat fisik. Untuk beta testing eksternal, TestFlight adalah cara paling andal.
Apakah saya harus pindah ke FCM HTTP v1 API di 2026?
Ya, sudah wajib. Firebase menghentikan HTTP legacy API dan Server Key authentication pada Juni 2024. Backend Anda harus menggunakan HTTP v1 API dengan OAuth 2.0 access token yang diperoleh dari service account credentials. FirebaseAdmin SDK untuk .NET (versi 3.x+) sudah menangani ini secara otomatis.