Push известия в .NET MAUI: Пълно ръководство за Firebase FCM и APNs (2026)
Практическо ръководство за push известия в .NET MAUI 9. Настройка на Firebase FCM за Android, APNs за iOS, разрешения, deep linking, silent push и сравнение на Azure Notification Hubs с OneSignal.
За да добавите push известия в .NET MAUI приложение, регистрирайте устройството при съответната платформена услуга — Firebase Cloud Messaging (FCM) за Android и Apple Push Notification service (APNs) за iOS, получете токен на устройството, изпратете го към собствен бекенд и обработете входящите съобщения през платформените обратни извиквания. .NET MAUI 9 нямa вграден единен API за push, но с NuGet пакетите Plugin.Firebase и Plugin.LocalNotification, плюс минимална нативна конфигурация, се стига до продукционно решение за няколко часа. Това ръководство показва цялата пътечка, от инсталация на SDK и обработка на разрешения до deep links и Azure Notification Hubs.
Push известията в .NET MAUI 9 изискват отделни SDK за Android (FCM) и iOS (APNs); .NET 10 (preview) въвежда единен Microsoft.Maui.Notifications, но той не е още стабилен.
Android 13+ и iOS ≥12 задължително изискват runtime разрешение (POST_NOTIFICATIONS, respectively UNAuthorizationOptions), а без него доставката е тиха.
Токенът на устройството може да се обнови по всяко време; винаги записвайте новия OnNewToken callback в бекенда, иначе доставката прекратява след ротация.
Deep linking се реализира като предадете route ключ в payload-а и извикате Shell.Current.GoToAsync от глобалния обработчик.
Azure Notification Hubs и OneSignal премахват необходимостта от собствен FCM/APNs endpoint, но добавят месечни разходи над определен обем.
Silent (data-only) push на iOS изисква content-available: 1 и специфично разрешение за remote-notification в Info.plist.
Как работят push известията в .NET MAUI
Push известието в мобилно приложение винаги минава през три ясно разграничени страни: издател (вашият бекенд), gateway на платформата (FCM за Google, APNs за Apple) и клиент (приложението на устройството). .NET MAUI работи с двата gateway-я поотделно, а една абстракция върху тях в основния SDK все още липсва, макар че .NET 10 preview започна да експериментира с Microsoft.Maui.Notifications. За .NET MAUI 9 (тек през септември 2026) подходът е практичен: използвайте Plugin.Firebase (последна стабилна версия 3.1.2 от юли 2026) за Android и вградените iOS API на UserNotifications.framework, обвити от MauiProgram.
Различията между Android и iOS не са само в SDK. Android приема push дори когато приложението е убито от системата, стига процесът да не е блокиран от батерийни оптимизации на OEM (Xiaomi, Huawei са тук особено агресивни). iOS от друга страна изисква изрично разрешение на потребителя още при първо показване и обработва background delivery по-строго. Не можете да разчитате на изпълнение при силент push, а само на възможност за такова. Разбирането на тази разлика спестява седмици дебъгинг.
В моята практика с корпоративни MAUI внедрявания първите две грешки, които виждам, са една и съща: (1) разработчиците третират push токен като статичен и (2) не обработват edge case, в който потребителят е отказал разрешението, но по-късно го е върнал от Settings. И двете чупят доставката тихо: известията се изпращат от бекенда, платформата ги приема, устройството не ги показва. За системен обзор на .NET MAUI архитектурата, вижте официалната документация на Microsoft.
Настройка на Firebase FCM за Android
Първо създайте проект в Firebase Console, добавете Android app с exact package name (например com.mobiletechlead.demo), свалете google-services.json и го поставете в Platforms/Android/. В .csproj файла на MAUI проекта го маркирайте като GoogleServicesJson:
В Platforms/Android/MainApplication.cs инициализирайте Firebase преди Xamarin.Essentials да е стартирал:
[Application]
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership) { }
public override void OnCreate()
{
base.OnCreate();
Firebase.FirebasePlatform.Initialize(this, CrossFirebase.Current);
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
В AndroidManifest.xml добавете разрешенията и Firebase service декларацията. Android 13 (API 33) и по-нови изискват runtime POST_NOTIFICATIONS, а за по-стари версии разрешението е автоматично.
За iOS процесът минава през Apple Developer Portal. Създайте APNs Auth Key (препоръчително пред стария certificate-based подход, тъй като key-ът не изтича) и запишете Key ID и Team ID. В Xcode добавете capability Push Notifications и Background Modes → Remote notifications към Entitlements.plist на MAUI проекта:
В Platforms/iOS/AppDelegate.cs регистрирайте приложението за отдалечени известия при стартиране:
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
UNUserNotificationCenter.Current.RequestAuthorization(
UNAuthorizationOptions.Alert
| UNAuthorizationOptions.Badge
| UNAuthorizationOptions.Sound,
(granted, error) =>
{
if (granted)
{
MainThread.BeginInvokeOnMainThread(() =>
UIApplication.SharedApplication.RegisterForRemoteNotifications());
}
});
return base.FinishedLaunching(application, launchOptions);
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
var token = BitConverter.ToString(deviceToken.ToArray())
.Replace("-", string.Empty)
.ToLowerInvariant();
// Изпратете token към собствения бекенд
_ = TokenService.RegisterAsync(token, "ios");
}
}
За SDK-та и подписвания, които автоматизирате в CI, вижте практическото ръководство за CI/CD на .NET MAUI с GitHub Actions. Там е разгледано инжектирането на APNs auth key чрез GitHub Secrets, което е задължително преди публикуване към TestFlight.
Как да поискате разрешение за известия в .NET MAUI?
Разрешенията се разминават драматично между платформите. iOS изисква UNUserNotificationCenter.RequestAuthorization преди всяка регистрация; Android 12 и по-стари не изискват runtime разрешение, но Android 13+ изисква POST_NOTIFICATIONS. Създайте кросплатформен сервиз, който абстрахира различията и връща единна булева стойност към ViewModel-а:
public interface INotificationPermissionService
{
Task<bool> RequestAsync(CancellationToken ct = default);
Task<PermissionStatus> GetStatusAsync();
}
// Platforms/Android/Services/NotificationPermissionService.cs
public class NotificationPermissionService : INotificationPermissionService
{
public async Task<bool> RequestAsync(CancellationToken ct = default)
{
if (OperatingSystem.IsAndroidVersionAtLeast(33))
{
var status = await Permissions.RequestAsync<Permissions.PostNotifications>();
return status == PermissionStatus.Granted;
}
return true; // По-старите версии дават разрешение автоматично
}
public async Task<PermissionStatus> GetStatusAsync() =>
OperatingSystem.IsAndroidVersionAtLeast(33)
? await Permissions.CheckStatusAsync<Permissions.PostNotifications>()
: PermissionStatus.Granted;
}
За .NET MAUI 9 Permissions.PostNotifications е официално поддържан от юни 2026 (преди това се разчиташе на Xamarin.Essentials.Permissions.AndroidPermission-обвивка). Задължително обяснете защо искате разрешение преди системния диалог — процентът на съгласие се увеличава с ~35% според Apple Human Interface Guidelines. Никога не показвайте системния prompt при първо стартиране; изчакайте потребителят да достигне екран, където известия имат смисъл (например след завършване на onboarding).
Регистрация и ротация на токени
FCM и APNs токените не са вечни. FCM токен може да се ротира при преинсталация, при изтриване на данни на приложение, при смяна на устройство или при неактивност на приложение >270 дни. APNs токенът се сменя при iCloud restore и при преинсталация. Затова никога не приемайте, че първо получения при стартиране токен е окончателният. Регистрирайте hook на промяна:
В моята практика най-често виждам следния антипатерн: разработчиците регистрират токен само при първо стартиране и запазват в Preferences. Шест месеца по-късно получават email от support: "известията спряха". Причината почти винаги е ротация. Решението е двойно: изпращайте текущия токен при всяко студено стартиране и абонирайте TokenChanged постоянно през жизнения цикъл. Бекендът от своя страна трябва да поддържа история: при получаване на нов токен маркирайте стария като revoked, но не го изтривайте, за да улесните диагностика.
Ако използвате REST API с HttpClient и Refit за комуникация с бекенда, добавете PolicyHandler с Polly retry (максимум 3 опита с експоненциален backoff). Регистрацията на токен е един от малкото места, където загубени POST-ове са критични. Не използвайте FireAndForget тук.
Как да отворите конкретен екран от push известие?
Deep linking се реализира чрез custom payload в push съобщението. Изпратете от бекенда JSON с data секция, съдържаща route и опционални параметри, след което в обработчика на известие извикайте Shell навигация:
// Обработчик в App.xaml.cs
private async void HandleIncoming(FCMNotification notification)
{
if (!notification.Data.TryGetValue("route", out var route)) return;
var parameters = notification.Data
.Where(kvp => kvp.Key != "route")
.ToDictionary(kvp => kvp.Key, object (kvp) => kvp.Value);
await MainThread.InvokeOnMainThreadAsync(async () =>
{
await Shell.Current.GoToAsync(route, parameters);
});
}
Ключовата тънкост: обработката се различава при cold start (приложението е било убито) спрямо warm start (приложението е било във фон). На iOS cold-start payload идва през launchOptions в FinishedLaunching, а warm-start през UserNotificationCenter.WillPresentNotification. Ако забравите първия случай, deep link работи само при отворено приложение, класически бъг, който минава през QA, защото тестерите обичайно оставят приложението отворено.
Silent push и фонови данни
Silent push (наричан още data-only push) позволява бекендът да събуди приложението във фон, за да синхронизира данни без визуално известие. Полезно е при чат приложения, live tracking, или обновяване на баджове. Пращате JSON безnotification секция и с content-available: 1 на iOS:
iOS дозира silent пушовете агресивно, най-много около 2-3 на час, а системата решава дали въобще да събуди процеса. Никога не разчитайте на silent push за критична доставка; използвайте го за оптимизация. На Android FCM data-only messages работят по-надеждно, но батерийните оптимизации (особено при OEM като Samsung One UI 8) могат да ги забавят с часове.
Изборът на бекенд стратегия зависи от обем, регулация и опит с DevOps. За enterprise MAUI проекти, при които съм работил, най-често използваме Azure Notification Hubs — той се справя с broadcast към милиони устройства, поддържа tag-based targeting и абстрахира FCM/APNs различията. За стартиращи проекти OneSignal е по-лесен, но добавя vendor lock-in.
Характеристика
Собствен бекенд
Azure Notification Hubs
OneSignal
Начална сложност
Висока (HTTP/2 към APNs, FCM SDK)
Средна
Ниска (drop-in SDK)
Месечна цена (1M push)
Само хостинг
~10 USD (Basic tier)
Безплатно до 10K абонати
Targeting (сегменти, тагове)
Изисква имплементация
Вграден
Вграден
Аналитика на доставка
Изисква имплементация
Основна
Богата
GDPR / данни в ЕС
Пълен контрол
Регионален избор
Ограничени опции
Локална разработка
Сложна
Има emulator
Има dashboard
За регулирани индустрии (здравеопазване, финанси) собственият бекенд с директен HTTP/2 към APNs и Firebase Admin SDK към FCM е единственият вариант. Причината: не искате payload с чувствителни данни (макар и криптиран) да минава през трети посредник. За всичко останало Azure Notification Hubs дава най-добър баланс. Свързва се с Azure AD за MFA (нещо, което лично съм използвал при няколко клинични внедрявания), поддържа Xamarin/MAUI SDK и има разумна цена.
Тестване и диагностика
Никога не тествайте push известия само на emulator. Firebase Cloud Messaging изисква Google Play Services, което липсва на много Android емулатори (например Waydroid, Genymotion без Play Store вариант). За iOS simulator-ът от Xcode 15 нататък поддържа push тестване чрез .apns файл, който drag-и в симулатора, но реалната APNs пътечка се тества само на устройство.
За Firebase използвайте Firebase Console → Cloud Messaging → New campaign → Test on device, като поставите device token, който сте логнали от приложението. За production дебъгинг настройте logging middleware в бекенда, което записва response от FCM/APNs: 4xx грешки (invalid token, unregistered) са ясни, но 5xx от APNs често изисква retry с експоненциален backoff.
Често срещани проблеми при доставка
За девет години работа с push сред мобилни приложения, следните пет проблема ми се появяват в 90% от случаите:
Известия не пристигат на Android, но пристигат на iOS. Проверете google-services.json, че package name съвпада точно, включително case. Firebase console показва грешен package като "0 регистрирани устройства".
Silent push не будят приложението на iOS. Пропуснат apns-push-type: background header или липсваща UIBackgroundModes → remote-notification в Info.plist.
Deep link не отваря правилния екран при cold start. Не обработвате launchOptions[UIApplication.LaunchOptionsRemoteNotificationKey] в FinishedLaunching.
Токен се сменя всеки път при отваряне. Не сте инициализирали Firebase преди първо извикване към GetToken(); race condition в MainApplication.OnCreate.
Известия работят локално, но спират след публикуване в Google Play. Play App Signing преподписва APK-а с различен ключ, така че SHA-256 fingerprint в Firebase console трябва да съответства на този на Google Play, не на локалния keystore.
За систематична диагностика използвайте adb logcat -s FirebaseMessaging FA FCM на Android и Console.app с filter process:apsd на iOS. Тези два реда команди спестяват часове.
Често задавани въпроси
Има ли .NET MAUI вграден API за push известия?
Не в стабилната версия .NET MAUI 9. Има LocalNotification поддръжка чрез Plugin.LocalNotification, но за отдалечени push се разчита на Firebase SDK за Android и UserNotifications.framework за iOS. .NET 10 preview (септември 2026) въвежда Microsoft.Maui.Notifications namespace, но той е експериментален.
Каква е разликата между FCM и APNs?
FCM (Firebase Cloud Messaging) е услугата на Google за доставка към Android устройства, докато APNs (Apple Push Notification service) обслужва iOS/iPadOS/macOS. FCM може да прокси APNs съобщения, но подписването и токените са различни. APNs изисква auth key или certificate от Apple Developer Portal; FCM изисква service account JSON от Firebase.
Работят ли push известия в .NET MAUI на Windows?
Да, чрез WNS (Windows Notification Service), но настройката е отделна. Регистрирате приложението в Microsoft Partner Center, получавате Package Family Name и Client Secret, и използвате PushNotificationChannel API. Обхватът на WNS е ограничен до Store-published приложения; sideloaded MAUI приложения не могат да получават push.
Колко струват push известията?
FCM и APNs са безплатни за неограничен брой съобщения. Разходи възникват само при използване на посредник (Azure Notification Hubs от ~10 USD/месец, OneSignal безплатно до 10 000 абонати) или ако имплементирате собствен бекенд, който консумира ресурси. За mid-size приложение с 100 000 активни устройства цените остават под 50 USD/месец.
Мога ли да изпращам push от .NET MAUI приложение към друго устройство?
Не директно от клиент към клиент, защото това би изисквало вграждане на FCM server key в приложението, което е сериозен пропуск в сигурността. Правилният подход: клиентското приложение прави HTTP заявка към ваш бекенд, който валидира потребителя и след това извиква FCM/APNs с server credentials. Никога не съхранявайте FCM server key или APNs auth key в клиентски код.
Защо някои устройства получават известия с голямо закъснение?
Най-често виновници са батерийните оптимизации на OEM (Xiaomi MIUI, Huawei EMUI, Samsung One UI). Те убиват процесите на приложението във фон, а FCM има вградени backoff интервали. За критични известия използвайте priority: "high" във FCM payload, но не злоупотребявайте, тъй като Google понижава priority-то на приложения, които пращат "high" непрекъснато.
Caleb has shipped seven mobile apps to the App Store and Play Store over the last nine years, four of them in Xamarin and three in .NET MAUI. He spent five years at a healthcare-tech company in Boston building a clinician-facing iPad app used by roughly 14,000 nurses, then moved to a freelance practice in 2024 focused on enterprise MAUI rollouts for regulated industries.
His writing tends toward the practical: CI pipelines on App Center successors, MSAL token caching across Android lifecycle resets, MAUI Blazor Hybrid in production, and the awkward seams between MAUI and native SDKs that vendors haven't gotten around to wrapping. He runs a small Discord for enterprise MAUI engineers and writes a Friday newsletter from his home in Portland, Maine.
Практическо ръководство за миграция от Xamarin.Forms към .NET MAUI 2026 с upgrade-assistant, handlers, single project и истински решения на често срещаните грешки.
Научете как да създавате хибридни мобилни и десктоп приложения с .NET MAUI Blazor Hybrid. Архитектура, споделен UI чрез RCL, достъп до нативни API-та и новостите в .NET 10 с практически примери.