App非活跃状态下PubNub无推送通知问题求助
我来帮你梳理下这个问题的核心原因和解决办法——我之前也踩过类似的PubNub+FCM在Android后台推送的坑,结合你的描述,核心问题其实是Android Oreo+的后台限制导致Token刷新时,PubNub的推送注册操作没被正确执行,进而出现"NotRegistered"错误。以下是分步解决思路:
核心问题分析
你提到Firebase控制台直接推送正常,但PubNub推送在应用非活跃时失败,还收到"GCM Error: NotRegistered",说明:
- FCM的Token本身是有效的(不然Firebase控制台也推不了);
- PubNub那边的推送注册状态和当前FCM Token不同步——当应用非活跃时Token刷新,你的旧逻辑无法在后台完成PubNub的Token更新操作,导致PubNub还在用失效的旧Token推送,自然触发"未注册"错误。
具体解决方案
1. 用WorkManager替代后台服务执行PubNub Token更新
Android Oreo+严格限制后台服务启动,OnTokenRefresh()在后台触发时,直接在里面调用PubNub的网络操作很可能被系统杀死。WorkManager是Jetpack专门用来处理后台任务的组件,不受后台限制,能保证任务在合适时机执行。
实现步骤(Xamarin C#):
首先安装Xamarin.AndroidX.Work.Runtime NuGet包,然后:
// 在你的FirebaseMessagingService中重写OnTokenRefresh public override void OnTokenRefresh() { var newToken = FirebaseInstanceId.Instance.Token; // 把新Token传给WorkManager执行更新 var inputData = new Data.Builder() .PutString("NewFCMToken", newToken) .Build(); var updateWork = OneTimeWorkRequestBuilder<PubNubPushSyncWorker>() .SetInputData(inputData) .Build(); WorkManager.Instance.Enqueue(updateWork); } // 定义WorkManager的Worker类,处理PubNub推送注册 public class PubNubPushSyncWorker : Worker { public PubNubPushSyncWorker(Context context, WorkerParameters params) : base(context, params) { } public override Result DoWork() { var newToken = InputData.GetString("NewFCMToken"); if (string.IsNullOrEmpty(newToken)) return Result.Failure(); // 确保使用你项目的单例PubNub实例(避免重复初始化) var pubnub = YourPubNubSingleton.Instance; var oldToken = FirebaseInstanceId.Instance.GetToken(FirebaseInstanceId.Instance.GetSenderId(), "FCM"); try { // 先移除旧Token的推送注册(如果存在且和新Token不同) if (!string.IsNullOrEmpty(oldToken) && oldToken != newToken) { pubnub.RemovePushNotificationsFromChannels() .Channels(new List<string> { "你的目标频道名" }) .DeviceId(oldToken) .Execute(); } // 用新Token注册PubNub推送 pubnub.AddPushNotificationsOnChannels() .Channels(new List<string> { "你的目标频道名" }) .DeviceId(newToken) .PushType(PushType.Gcm) // PubNub用Gcm兼容FCM .Execute(); return Result.Success(); } catch (Exception ex) { Log.Error("PubNubWorker", $"推送注册更新失败: {ex.Message}"); return Result.Retry(); // 失败自动重试 } } }
2. 补充应用唤醒时的Token校验逻辑
除了Token刷新时的自动同步,每次应用从后台唤醒(比如用户打开App),都要校验当前FCM Token和PubNub的注册状态是否一致:
// 在MainActivity的OnResume方法中 protected override void OnResume() { base.OnResume(); var currentToken = FirebaseInstanceId.Instance.Token; var pubnub = YourPubNubSingleton.Instance; // 检查当前Token是否已在PubNub注册 pubnub.GetPushNotificationsEnabledForChannel() .Channel("你的目标频道名") .DeviceId(currentToken) .Execute((result, status) => { if (status.Error || !result.Enabled) { // 未注册则触发更新 var inputData = new Data.Builder() .PutString("NewFCMToken", currentToken) .Build(); var updateWork = OneTimeWorkRequestBuilder<PubNubPushSyncWorker>() .SetInputData(inputData) .Build(); WorkManager.Instance.Enqueue(updateWork); } }); }
3. 处理"NotRegistered"错误的重试机制
当PubNub返回"NotRegistered"错误时,说明当前Token已失效,需要立即触发Token刷新和重新注册:
- 可以通过PubNub的状态监听器捕获这个错误:
pubnub.AddListener(new SubscribeCallbackExt( status => { if (status.Category == PNStatusCategory.PNPushErrorCategory) { if (status.ErrorData.Information.Contains("NotRegistered")) { // 强制刷新FCM Token,触发OnTokenRefresh FirebaseInstanceId.Instance.DeleteToken(FirebaseInstanceId.Instance.GetSenderId(), "FCM"); FirebaseInstanceId.Instance.GetToken(); } } }, message => {}, presence => {} ));
4. 确保通知渠道配置正确
虽然Firebase控制台推送正常,但PubNub的推送可能没指定正确的通知渠道,导致非活跃状态下被系统拦截:
// 在Application的OnCreate方法中创建通知渠道(Android Oreo+必需) if (Build.VERSION.SdkInt >= BuildVersionCodes.O) { var channel = new NotificationChannel("pubnub_push_channel", "PubNub推送", NotificationImportance.Default) { Description = "接收PubNub的实时推送消息" }; var notificationManager = (NotificationManager)GetSystemService(NotificationService); notificationManager.CreateNotificationChannel(channel); }
同时,确保PubNub推送的Payload中包含channel_id字段,值为你创建的渠道ID。
5. 验证PubNub的FCM配置
最后检查PubNub控制台的推送设置:
- 确认已正确填入Firebase控制台的FCM Server Key;
- 确认推送目标频道和你代码中注册的一致。
内容的提问来源于stack exchange,提问作者Himadri Nath
相关产品推荐
相关产品推荐

