当应用程序处于前台或后台时如何使用 FCM 处理通知 [英] How to handle notifications with FCM when app is in either foreground or background

查看:24
本文介绍了当应用程序处于前台或后台时如何使用 FCM 处理通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 firebase 来构建我的项目.
它还将使用 FCM(firebase 云消息).
但是有一个问题.
当应用程序在后台时,我无法处理 FCM(创建我的自定义通知).

官网教程
情况 1:应用程序前台 -> 覆盖onMessageReceived()"以创建您的自定义通知.
案例2:应用后台->系统会直接创建通知.我们不需要也不能做任何事情.因为在这种情况下它不会触发onMessageReceived()".

但是,如果在应用程序处于后台时我无能为力,则无法创建自定义通知.(例如,当用户点击通知后,它会弹出一个窗口显示详细信息.)

那么当应用程序在后台时如何使用 FCM 处理通知?

解决方案

有一个坏消息.
Google 在com.google.firebase:firebase-messaging:11.6"版本中更改了 Firebase 源代码.0'.
handelIntent 现在是public final void 方法".这意味着我们不能覆盖它.
如果要使用该解决方案,请将版本更改为com.google.firebase:firebase-messaging:11.4.2"



试试我的方法.在Android 6.0以上(api level 23)的项目构建版本上可以完美运行,我已经试过了.

有比官方网站教程更好的方法

官网说应用在后台时系统会创建通知.所以你不能通过覆盖onMessageReceived()"来处理它.因为onMessageReceived()"仅在应用程序处于前台时触发.

但事实并非如此.实际上,通知(当应用处于后台时)是由 Firebase 库创建的.

在我追踪 firebase 库代码之后.我找到了更好的方法.

<块引用>

第 1 步:覆盖 FirebaseMessagingService 中的handleIntent()"而不是onMessageReceived()"
为什么:
因为该方法将触发应用程序在前台或后台.因此,我们可以在两种情况下处理 FCM 消息并创建自定义通知.

@Override公共无效handleIntent(意图意图){Log.d("FCM", "handleIntent");}


<块引用>

步骤 2. 解析来自 FCM 的消息
如何:
如果您不知道您设置的消息格式.打印它并尝试解析它.
这里是基本说明

Bundle bundle = intent.getExtras();如果(捆绑!= null){对于(字符串键:bundle.keySet()){对象值 = bundle.get(key);Log.d("FCM", "Key: " + key + " Value: " + value);}}


<块引用>

第 2 步:删除应用在后台时 Firebase 库创建的通知
为什么:
我们可以创建自定义通知.但是 Firebase 库创建的通知仍然存在(实际上它是由 ""super.handleIntent(intent)"" 创建的.下面有详细说明.).然后我们会有两个通知.这就比较奇怪了.所以我们必须删除 Firebase 库创建的通知

how(项目构建级别为Android 6.0以上):
识别我们要删除的通知并获取信息.并使用notificationManager.cancel()"删除它们.

private void removeFirebaseOrigianlNotificaitons() {//检查通知管理器是否可用通知管理器通知管理器 =(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);如果(通知管理器 == null )返回;//检查API级别的getActiveNotifications()如果 (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {//如果你的Build版本低于android 6.0//我们可以删除所有通知.//notificationManager.cancelAll();返回;}//检查是否有通知StatusBarNotification[] activeNotifications =NotificationManager.getActiveNotifications();如果(activeNotifications == null)返回;//删除所有由库创建的通知(super.handleIntent(intent))for (StatusBarNotification tmp : activeNotifications) {Log.d("FCM StatusBarNotification","StatusBarNotification tag/id:" + tmp.getTag() + "/" + tmp.getId());字符串标签 = tmp.getTag();int id = tmp.getId();//跟踪库源代码,按照规则删除.if (tag != null && tag.contains("FCM-Notification"))notificationManager.cancel(tag, id);}}

<块引用>

我的整个示例代码:

public class MyFirebaseMessagingService 扩展 FirebaseMessagingService {私有静态 int 通知计数 = 0;@覆盖公共无效handleIntent(意图意图){//添加一个日志,你会看到该方法会一直被触发(前台和后台).Log.d( "FCM", "handleIntent");//如果您不知道 FCM 消息的格式,//只要打印出来,你就会知道如何解析它捆绑包 = intent.getExtras();如果(捆绑!= null){对于(字符串键:bundle.keySet()){对象值 = bundle.get(key);Log.d("FCM", "Key: " + key + " Value: " + value);}}//后台通知由super方法创建//但是你不能删除超级方法.//super 方法做其他事情,而不仅仅是创建通知super.handleIntent(意图);//删除通知removeFirebaseOrigianlNotificaitons();如果(捆绑==空)返回;//解析消息CloudMsg cloudMsg = parseCloudMsg(bundle);//如果你想把数据带到Activity,设置它捆绑 myBundle = new Bundle();myBundle.putSerializable(TYPE_FCM_PLATFORM,cloudMsg);Intent myIntent = new Intent(this, NotificationActivity.class);myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);myIntent.putExtras(myBundle);PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationCount, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);//设置通知NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.mipmap.icon).setContentTitle(cloudMsg.getTitle()).setContentText(cloudMsg.getMessage()).setAutoCancel(true).setContentIntent(pendingIntent);NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);notificationManager.notify(notificationCount++, notificationBuilder.build());}/*** 解析来自 FCM 的消息* @param 包*/私有 CloudMsg parseCloudMsg(捆绑包){字符串标题=空,味精=空;//如果消息是从 Firebase 平台发送的,则关键是msg = (String) bundle.get("gcm.notification.body");if(bundle.containsKey("gcm.notification.title"))title = (String) bundle.get("gcm.notification.title");//解析你的自定义消息字符串测试值=空;testValue = (String) bundle.get("testKey");//将它们打包成一个对象(CloudMsg是你自己的结构),很容易发送到Activity.CloudMsg cloudMsg = new CloudMsg(title, msg, testValue);返回 cloudMsg;}/*** 删除由super.handleIntent(intent)"创建的通知*/私有无效 removeFirebaseOrigianlNotificaitons() {//检查通知管理器是否可用通知管理器通知管理器 =(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);如果(通知管理器 == null )返回;//检查API级别的getActiveNotifications()如果 (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {//如果你的Build版本低于android 6.0//我们可以删除所有通知.//notificationManager.cancelAll();返回;}//检查是否有通知StatusBarNotification[] activeNotifications =NotificationManager.getActiveNotifications();如果(activeNotifications == null)返回;//删除所有由库创建的通知(super.handleIntent(intent))for (StatusBarNotification tmp : activeNotifications) {Log.d("FCM StatusBarNotification",标签/ID:" + tmp.getTag() + /" + tmp.getId());字符串标签 = tmp.getTag();int id = tmp.getId();//跟踪库源代码,按照规则删除.if (tag != null && tag.contains("FCM-Notification"))notificationManager.cancel(tag, id);}}}

I used firebase to build My project.
It will also use the FCM (firebase cloud message).
But there is a problem.
I can't handle the FCM (create my custom notificaion) when app is in background.

The official site tutorial said that
case 1: App foreground -> override the "onMessageReceived()" to create your custom notification.
case 2: App background -> System will create the notification directly. We needn't and can't do anything. Because it doesn't trigger the "onMessageReceived()" in this case.

However if I can do nothing when app is background, I can't create my custom notification. (e.g. After Users click the notification and it will pop up a window to show detail information.)

So how do I handle notifications with FCM when app is in background?

解决方案

There is a bad news.
Google change the Firebase source code in version 'com.google.firebase:firebase-messaging:11.6.0'.
handelIntent is "public final void method" now. which means we can't override it .
If you want to use the solution, change the version to be "com.google.firebase:firebase-messaging:11.4.2"



Try my way. It can perfectly work on the project build version is Android 6.0 above(api level 23) and I have tried it already.

There is better way than official site tutorial

The official site said that the notification will be created by system when app is in background. So you can't handle it by overriding the "onMessageReceived()". Because the "onMessageReceived()" is only triggered when app is in foreground.

But the truth is not. Actually the notificaions (when app is in background) are created by Firebase Library.

After I traced the firebase library code. I find a better way.

Step 1. Override the "handleIntent()" instead of "onMessageReceived()" in FirebaseMessagingService
why:
Because the method will be trigger either app is in foreground or the background. So we can handle FCM message and create our custom notifications in both cases.

@Override
public void handleIntent(Intent intent) {
    Log.d( "FCM", "handleIntent ");
}


Step 2. Parse the message from FCM
how:
If you don't know the format of the message you set. Print it and try to parse it.
Here is the basic illustration

Bundle bundle = intent.getExtras();
if (bundle != null) {
    for (String key : bundle.keySet()) {
        Object value = bundle.get(key);
        Log.d("FCM", "Key: " + key + " Value: " + value);
    }
}


Step 2. Remove the notifications created by Firebase library when the app is in background
why:
We can create our custom notification. But the notification created by Firebase Library will still be there (Actually it created by ""super.handleIntent(intent)"". There is detail explaination below.). Then we'll have two notifcations. That is rather weird. So we have to remove the notificaion created by Firebase Library

how (project build level is Android 6.0 above):
Recognize the notifications which we want to remove and get the informaion. And use the "notificationManager.cancel()" to remove them.

private void removeFirebaseOrigianlNotificaitons() {

    //check notificationManager is available
    NotificationManager notificationManager = 
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    if (notificationManager == null )
        return;

    //check api level for getActiveNotifications()
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        //if your Build version is less than android 6.0
        //we can remove all notifications instead. 
        //notificationManager.cancelAll();
        return;
    }


    //check there are notifications
    StatusBarNotification[] activeNotifications = 
        notificationManager.getActiveNotifications();
    if (activeNotifications == null)
        return;

    //remove all notification created by library(super.handleIntent(intent))
    for (StatusBarNotification tmp : activeNotifications) {
        Log.d("FCM StatusBarNotification", 
            "StatusBarNotification tag/id: " + tmp.getTag() + " / " + tmp.getId());
        String tag = tmp.getTag();
        int id = tmp.getId();

        //trace the library source code, follow the rule to remove it.
        if (tag != null && tag.contains("FCM-Notification"))
            notificationManager.cancel(tag, id);
    }
}

The my whole sample code:

public class MyFirebaseMessagingService extends FirebaseMessagingService {

private static int notificationCount=0;

@Override
public void handleIntent(Intent intent) {
    //add a log, and you'll see the method will be triggered all the time (both foreground and background).
    Log.d( "FCM", "handleIntent");

    //if you don't know the format of your FCM message,
    //just print it out, and you'll know how to parse it
    Bundle bundle = intent.getExtras();
    if (bundle != null) {
        for (String key : bundle.keySet()) {
            Object value = bundle.get(key);
            Log.d("FCM", "Key: " + key + " Value: " + value);
        }
    }

    //the background notification is created by super method
    //but you can't remove the super method. 
    //the super method do other things, not just creating the notification
    super.handleIntent(intent);

    //remove the Notificaitons
    removeFirebaseOrigianlNotificaitons();

    if (bundle ==null)
        return;

    //pares the message
    CloudMsg cloudMsg = parseCloudMsg(bundle);

    //if you want take the data to Activity, set it
    Bundle myBundle = new Bundle();
    myBundle.putSerializable(TYPE_FCM_PLATFORM, cloudMsg);
    Intent myIntent = new Intent(this, NotificationActivity.class);
    myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    myIntent.putExtras(myBundle);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationCount, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    //set the Notification
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.mipmap.icon)
            .setContentTitle(cloudMsg.getTitle())
            .setContentText(cloudMsg.getMessage())
            .setAutoCancel(true)
            .setContentIntent(pendingIntent);

    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    notificationManager.notify(notificationCount++, notificationBuilder.build());
}



/**
 * parse the message which is from FCM
 * @param bundle
 */
private CloudMsg parseCloudMsg(Bundle bundle) {
    String title = null, msg=null;

    //if the message is sent from Firebase platform, the key will be that
    msg = (String) bundle.get("gcm.notification.body");

    if(bundle.containsKey("gcm.notification.title"))
    title = (String) bundle.get("gcm.notification.title");

    //parse your custom message
    String testValue=null;
    testValue =  (String) bundle.get("testKey");

    //package them into a object(CloudMsg is your own structure), it is easy to send to Activity.
    CloudMsg cloudMsg = new CloudMsg(title, msg, testValue);
    return cloudMsg;
}


/**
 * remove the notification created by "super.handleIntent(intent)"
 */
    private void removeFirebaseOrigianlNotificaitons() {

    //check notificationManager is available
    NotificationManager notificationManager = 
        (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    if (notificationManager == null )
        return;

    //check api level for getActiveNotifications()
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        //if your Build version is less than android 6.0
        //we can remove all notifications instead. 
        //notificationManager.cancelAll();
        return;
     }

    //check there are notifications
    StatusBarNotification[] activeNotifications = 
        notificationManager.getActiveNotifications();
    if (activeNotifications == null)
        return;

    //remove all notification created by library(super.handleIntent(intent))
    for (StatusBarNotification tmp : activeNotifications) {
        Log.d("FCM StatusBarNotification", 
            "tag/id: " + tmp.getTag() + " / " + tmp.getId());
        String tag = tmp.getTag();
        int id = tmp.getId();

        //trace the library source code, follow the rule to remove it.
        if (tag != null && tag.contains("FCM-Notification"))
            notificationManager.cancel(tag, id);
    }
}
}

这篇关于当应用程序处于前台或后台时如何使用 FCM 处理通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆