Xamarin FCM推送前台/杀进程不显示、后台Data计数异常问题
问题对应修复方案
核心问题根因
- 后台打开通知时Data计数异常递增:事件重复绑定+消息未做去重,多场景触发下同一消息会被多次处理
- 进程被杀/前台状态下通知不弹出:缺少SDK前置初始化、未适配高版本Android通知权限与通知渠道、默认配置下前台不自动弹窗
分步修复操作
解决事件重复绑定问题
所有推送事件绑定逻辑执行前,先解绑同名委托,避免应用重建、后台切前台时构造函数重复执行导致的多次订阅。如果需要做消息计数,给每一条推送下发唯一message_id字段,客户端处理前先校验本地是否已经处理过该ID,已处理的消息直接跳过,杜绝重复计数。解决前台不弹通知问题
推送插件默认不会在应用前台时自动弹出通知栏提醒,需要在收到消息的回调里判断当前应用状态,处于前台时主动调用本地通知渲染方法弹出提醒。解决进程被杀不弹通知问题
仅在共享项目的App构造函数中初始化逻辑是不够的,需要在Android项目的Application类的OnCreate生命周期中提前完成推送SDK初始化,保证进程冷启动时SDK已经完成推送服务注册,能正常接收系统推送。同时需要完成两项高版本适配:- 为Android 8.0及以上系统创建默认通知渠道,未创建渠道的通知会被系统直接拦截
- 在应用启动时针对Android 13及以上系统动态申请
POST_NOTIFICATIONS权限,未获得权限的应用无法弹出任何通知
修正后核心代码
共享项目 App.xaml.cs
using System; using Xamarin.Forms; using Plugin.FirebasePushNotification; using Xamarin.Forms.Xaml; using Xamarin.Essentials; namespace FCMTest { public partial class App : Application { public App() { InitializeComponent(); MainPage = new MainPage(); // 绑定前先解绑,防止重复订阅 CrossFirebasePushNotification.Current.OnTokenRefresh -= Current_OnTokenRefresh; CrossFirebasePushNotification.Current.OnNotificationReceived -= Current_OnNotificationReceived; CrossFirebasePushNotification.Current.OnNotificationOpened -= Current_OnNotificationOpened; CrossFirebasePushNotification.Current.Subscribe("all"); CrossFirebasePushNotification.Current.OnTokenRefresh += Current_OnTokenRefresh; CrossFirebasePushNotification.Current.OnNotificationReceived += Current_OnNotificationReceived; CrossFirebasePushNotification.Current.OnNotificationOpened += Current_OnNotificationOpened; } private void Current_OnTokenRefresh(object source, FirebasePushNotificationTokenEventArgs e) { System.Diagnostics.Debug.WriteLine($"Token from function OnTokenRefresh: {e.Token}"); } private void Current_OnNotificationReceived(object source, FirebasePushNotificationDataEventArgs d) { System.Diagnostics.Debug.WriteLine("Received"); // 消息去重逻辑,可替换为自己的本地存储校验 if (d.Data.ContainsKey("message_id") && Preferences.ContainsKey($"processed_{d.Data["message_id"]}")) { return; } if (d.Data.ContainsKey("message_id")) { Preferences.Set($"processed_{d.Data["message_id"]}", true); } foreach (var data in d.Data) { System.Diagnostics.Debug.WriteLine($"{data.Key} : {data.Value}"); } // 前台状态手动弹出通知 if (IsAppForeground()) { var title = d.Data.ContainsKey("title") ? d.Data["title"].ToString() : "Test from code"; var body = d.Data.ContainsKey("body") ? d.Data["body"].ToString() : "Here is your test!"; CrossFirebasePushNotification.Current.PresentLocalNotification(title, body, d.Data); } } private void Current_OnNotificationOpened(object source, FirebasePushNotificationResponseEventArgs d) { System.Diagnostics.Debug.WriteLine("Opened"); // 同样加去重逻辑,避免打开事件重复触发计数 if (d.Data.ContainsKey("message_id") && Preferences.ContainsKey($"opened_{d.Data["message_id"]}")) { return; } if (d.Data.ContainsKey("message_id")) { Preferences.Set($"opened_{d.Data["message_id"]}", true); } foreach (var data in d.Data) { System.Diagnostics.Debug.WriteLine($"{data.Key} : {data.Value}"); } } private bool IsAppForeground() { try { return Platform.CurrentActivity != null; } catch { return false; } } protected override void OnStart() { // Android13+ 动态申请通知权限 if (DeviceInfo.Platform == DevicePlatform.Android && DeviceInfo.Version.Major >= 13) { Permissions.RequestAsync<Permissions.PostNotifications>(); } } protected override void OnSleep() { } protected override void OnResume() { } } }
Android项目 MainApplication.cs(需新增)
using System; using Android.App; using Android.Runtime; using Plugin.FirebasePushNotification; namespace FCMTest.Droid { [Application] public class MainApplication : Application { protected MainApplication(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer) { } public override void OnCreate() { base.OnCreate(); // 初始化SDK并创建默认通知渠道 FirebasePushNotificationManager.Initialize(this, new PushNotificationChannel[] { new PushNotificationChannel("fcm_default_channel", "推送通知", NotificationImportance.Default) { LockscreenVisibility = NotificationVisibility.Public } }, true); // 处理进程被杀状态下点击通知拉起应用的场景 FirebasePushNotificationManager.ProcessIntent(Intent); } } }
服务端发送调整
原有发送逻辑无需大改,只需要在Data字段中补充唯一message_id字段,配合客户端做消息去重即可:
var message = new Message() { Data = new Dictionary<string, string>() { {"myData", "One more try to say Succeded!"}, {"message_id", Guid.NewGuid().ToString()} // 新增唯一消息ID }, Token = registrationToken, Notification = new Notification() { Title = "Test from code", Body = "Here is your test!" } };
内容的提问来源于stack exchange,提问作者Joseph Dagher
相关产品推荐
相关产品推荐

