【问题标题】:FCM - Setting badge in onMessageReceivedFCM - 在 onMessageReceived 中设置徽章
【发布时间】:2016-09-05 08:26:36
【问题描述】:

我有一个 Android 应用程序,我正在使用某种方法在应用程序图标上显示通知编号。现在我想在收到通知时设置那个数字。

我认为我应该在收到通知时设置数字,所以我将它设置在 onMessageReceived 方法中。但是,我的问题是当我的应用程序在后台时,onMessageReceived 方法未调用,因此未设置通知编号。

以下是我的代码。我在onMessageReceived 中设置了号码。我已经测试了setBadge 方法并且可以验证它是否有效。问题是onMessageReceived没有被调用所以setBadge也没有被调用,它没有设置数字。

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

    // TODO(developer): Handle FCM messages here.
    Log.d(TAG, "From: " + remoteMessage.getFrom());
    Conts.notificationCounter ++;
    //I am setting in here.
    setBadge(getApplicationContext(),Conts.notificationCounter  );
    Log.e("notificationNUmber",":"+ Conts.notificationCounter);

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());
    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }

    // Also if you intend on generating your own notifications as a result of a received FCM
    // message, here is where that should be initiated. See sendNotification method below.
}
// [END receive_message]



public static void setBadge(Context context, int count) {
    String launcherClassName = getLauncherClassName(context);
    if (launcherClassName == null) {
        Log.e("classname","null");
        return;
    }
    Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
    intent.putExtra("badge_count", count);
    intent.putExtra("badge_count_package_name", context.getPackageName());
    intent.putExtra("badge_count_class_name", launcherClassName);
    context.sendBroadcast(intent);
}

public static String getLauncherClassName(Context context) {

    PackageManager pm = context.getPackageManager();

    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);

    List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
    for (ResolveInfo resolveInfo : resolveInfos) {
        String pkgName = resolveInfo.activityInfo.applicationInfo.packageName;
        if (pkgName.equalsIgnoreCase(context.getPackageName())) {
            String className = resolveInfo.activityInfo.name;
            return className;
        }
    }
    return null;
}

当我搜索这个issue 时,我发现如果即将到来的消息是显示消息,那么只有当应用程序处于前台时才会调用onMessageReceived。但如果传入消息是数据消息,那么即使应用程序是后台,也会调用onMessageReceived。

但是我的朋友告诉我谁在发送通知(服务器端),消息已经作为显示和数据消息发送。他说数据对象被填充了。

以下是即将到来的消息的JSON,它有数据对象。

{  
   "to":"my_device_id",
   "priority":"high",

   "notification":{  
      "body":"Notification Body",
      "title":"Notification Title",
      "icon":"myicon",
      "sound":"default"
   },

   "data":{  
      "Nick":"DataNick",
      "Room":"DataRoom"
   }
}

如果我只使用数据对象,则按他们所说的那样调用 onMessageReceived,但该时间通知不会出现在顶部。

如果消息也是数据消息,为什么不调用onMessageReceived。我应该做一些不同的事情来处理数据消息吗?它是否与客户端的显示消息相同。

任何帮助将不胜感激。提前致谢。

【问题讨论】:

    标签: android google-cloud-messaging firebase-cloud-messaging firebase-notifications


    【解决方案1】:

    没有办法调用 onMessageReceived,除非即将到来的 json 包含 ONLY 数据负载,正如我从 Firebase 支持中了解到的那样。

    所以我必须使用数据有效负载,但如果您使用数据有效负载,它不会在顶部显示通知,因此您应该使用数据有效负载信息创建自定义通知。

    所以当我在 onMessageReceived 中获得数据负载时,我向自己发送了通知。我在向自己发送通知后立即在 onMessageReceived 中设置了徽章。

    以下代码为最终版本。

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        //for data payload
        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
    
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());
            title = remoteMessage.getData().get("title");
            sendNotification(remoteMessage.getData().get("body"), title);
            badge = Integer.parseInt(remoteMessage.getData().get("badge"));
            Log.e("notificationNUmber",":"+badge);
            setBadge(getApplicationContext(), badge);
    
        }
        //for notification payload so I did not use here
        // Check if message contains a notification payload.
        if (remoteMessage.getNotification() != null) {
    
            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    
        }
    
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
    }
    // [END receive_message]
    
    private void sendNotification(String messageBody, String title) {
        Intent intent = new Intent(this, MainMenuActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, notify_no /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);
        if (notify_no < 9) {
            notify_no = notify_no + 1;
        } else {
            notify_no = 0;
        }
        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher_3_web)
                .setContentTitle(title)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);
    
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
        notificationManager.notify(notify_no + 2 /* ID of notification */, notificationBuilder.build());
    }
    

    谢谢大家。

    【讨论】:

    • setBadge 默认方法? > setBadge(getApplicationContext(), badge);
    • 不,不是。我使用了一些 github 代码。 Setbadge 就是其中的一部分。
    • 能否提供您使用的 Github 代码的链接
    • 好的对不起我之前的评论。我想我对 setBadge 方法感到困惑,因为我试图找到几个小时的库并且找不到任何相关的库。这似乎 setBadge 下的那些代码可以在没有任何库的情况下工作,但我想只适用于三星设备=> stackoverflow.com/a/20261795/5528870 人们说这个库很好并且可以在许多设备上工作=> github.com/leolin310148/ShortcutBadger 我还了解到,由于 api 级别 26 有一个默认值设置徽章的方法。 developer.android.com/training/notify-user/badges#java@Pratik
    【解决方案2】:

    要在后台接收通知负载时做一些事情,只需覆盖 FirebaseMessagingService 中的 zzE。方法名称可能会在版本之间发生变化,只需在类中输入 @Override 并查看它对您的建议。就我而言,我找到了 zzD 和 zzE,通过试用它们,我注意到 zzE 拥有我想要的数据。 zzD 在它的附加功能中有一些唤醒锁的东西。 zzE的返回值基本上表示通知是否被处理,所以如果你返回true,操作系统就不会显示通知。我更喜欢在完成我的事情后返回 super.zzE(intent),让操作系统处理通知。

    更新徽章仅适用于 ShortcutBadger 支持的启动器。不过,您几乎可以做任何您想做的事情。

    这是我的代码(我的通知在数据负载中包含“徽章”):

    public class PushNotificationService extends FirebaseMessagingService
    {
        @Override
        public void onMessageReceived(RemoteMessage remoteMessage)
        {
            // This is called when the app is in the foreground
            // Show a custom notification or send a broadcast to update the UI here
        }
    
        @Override
        public boolean zzE(Intent intent)
        {
            if(intent.hasExtra("badge"))
            {
                try
                {
                    ShortcutBadger.applyCount(getApplicationContext(), Integer.parseInt(intent.getStringExtra("badge"));
                }
                catch (Exception e)
                {
                    Log.e("failedToParse", "Badge!?");
                }
            }
            // pass the intent through to the non-overriden zzE 
            // to show the default notification. 
            return super.zzE(intent);
    
            // You could also show a custom notification here
            // and return true instead of this if you 
            // don't want the default notifications.
        }
    
    }
    

    【讨论】:

    • 找不到 zzE()
    • 这适用于 firebase 10.2.1,在更高版本中该方法已被隐藏。那个旧版本仍然可以很好地工作,所以我坚持使用它,直到出现不同的解决方案。我真的不明白他们为什么要隐藏它,我不明白允许开发人员覆盖通知的显示方式会有什么危害......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-12
    • 1970-01-01
    • 2018-08-21
    • 2011-06-18
    • 1970-01-01
    相关资源
    最近更新 更多