You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

App非活跃状态下PubNub无推送通知问题求助

我来帮你梳理下这个问题的核心原因和解决办法——我之前也踩过类似的PubNub+FCM在Android后台推送的坑,结合你的描述,核心问题其实是Android Oreo+的后台限制导致Token刷新时,PubNub的推送注册操作没被正确执行,进而出现"NotRegistered"错误。以下是分步解决思路:

核心问题分析

你提到Firebase控制台直接推送正常,但PubNub推送在应用非活跃时失败,还收到"GCM Error: NotRegistered",说明:

  1. FCM的Token本身是有效的(不然Firebase控制台也推不了);
  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:33:35