firebase 应用程序在前台或后台时如何使用FCM处理通知

wqsoz72f  于 2022-12-30  发布在  其他
关注(0)|答案(5)|浏览(284)

我用firebase来建立我的项目。
它还将使用FCM(firebase云消息)。
但是有一个问题。
我不能处理FCM(创建我的自定义通知)时,应用程序在后台。
The official site tutorial
案例1:应用程序前台-〉覆盖"onMessageReceived()"以创建自定义通知。
案例2:App后台-〉系统会直接创建通知,我们不需要也不能做任何事情,因为本例中它没有触发"onMessageReceived()"。
但是,如果我可以什么都不做时,应用程序是后台,我不能创建我的自定义通知。(例如,用户点击通知后,它会弹出一个窗口显示详细信息。
那么,当应用程序在后台时,我如何使用FCM处理通知?

dy2hfwbg

dy2hfwbg1#

    • 有一个坏消息。

谷歌更改了版本"com. google. firebase:firebase消息传递:11.6.0"中的Firebase源代码。
handelIntent现在是"public final void方法"。这意味着我们不能覆盖它。
如果您想使用该解决方案,请将版本更改为"com. google. firebase:firebase-messaging:11.4.2"**

    • 试试我的方式。它可以完美地工作在项目构建版本是Android 6.0以上(API级别23),我已经尝试过了。**

有比official site tutorial更好的方法
官方网站称,该通知将在应用程序处于后台时由系统创建。因此,您无法通过覆盖"onMessageReceived()"来处理它。因为"onMessageReceived()"仅在应用程序处于前台时触发。
但事实并非如此,实际上通知(当应用程序在后台时)是由Firebase库创建的。
在我追踪了Firebase库的代码之后。我找到了一个更好的方法。

    • 步骤1.覆盖FirebaseMessagingService中的"handleIntent()"而不是"onMessageReceived()"**

原因:
因为方法将被触发应用程序在前台或后台。所以我们可以处理FCM消息,并创建我们的自定义通知在这两种情况下。

@Override
public void handleIntent(Intent intent) {
    Log.d( "FCM", "handleIntent ");
}
    • 步骤2.解析来自FCM的消息**

方法:
如果你不知道你设置的消息格式,打印它并尝试解析它。
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);
    }
}
    • 步骤2.删除应用程序在后台运行时由Firebase库创建的通知**

原因:
我们可以创建自定义通知。但是由Firebase库创建的通知仍然存在(实际上它是由"super. handleIntent(intent)"创建的。下面有详细的解释。)然后我们将有两个通知。这很奇怪。所以我们必须删除由Firebase库创建的通知
方法(项目构建级别为Android 6.0以上版本):
识别我们想要删除的通知并获取信息。然后使用"notificationManager. cancel()"删除它们。

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);
    }
}
    • 我的完整示例代码:**
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);
    }
}
}
lmyy7pcs

lmyy7pcs2#

但是,如果我可以什么都不做时,应用程序是后台,我不能创建我的自定义通知。(例如,用户点击通知后,它会弹出一个窗口显示详细信息。
那么,当应用程序在后台时,我如何使用FCM处理通知?
首先,您需要创建正确的消息有效负载,并将其发送到fcm服务器。

{
  "to": "topic_name",
  "priority": "high",
  "data": {
    "field1": "field1 value" 
    "field2": "field2 value" 
  }

  "notification" : {
      "body" : "Lorem ipsum",
      "title" : "sampke title" 
      "click_action": "SHOW_DETAILS" 
    }
}

data payload是用户点击通知后您希望显示为消息详细信息的实际数据,notification payload表示生成的通知的外观(可以设置的属性多得多),您不需要自己构建通知,只需在此处设置其属性。
要在用户点击通知后显示您的活动,您需要设置对应于click_action的Intent filter:

<intent-filter>
     <action android:name="SHOW_DETAILS"/>
     <category android:name="android.intent.category.DEFAULT"/>
 </intent-filter>

因此,当用户点击通知时,具有上述Intent过滤器Activity将自动启动。最后一步是在点击通知后启动Activity时检索数据。这非常简单。自定义数据通过bundle传递给Activity。在Activity的onCreate方法中执行以下操作:

Bundle bundle = getIntent().getExtras();
if(bundle.getString("action").equals("SHOW_DETAILS")) /*This indicates activity is launched from notification, not directly*/
{
 //Data retrieved from notification payload send 
 String filed1 = bundle.getString("field1");
 String filed2 = bundle.getString("field2");
}

如果应用程序没有运行或在后台运行,以上所有操作都有效。如果您的应用程序在前台运行,则不会创建通知。相反,您将收到onMessageReceived()事件,以便您可以在那里处理相同的数据(我猜您知道如何处理)。
参考:
https://firebase.google.com/docs/cloud-messaging/http-server-refhttps://github.com/firebase/quickstart-android/tree/master/messaging

ezykj2lf

ezykj2lf3#

你需要使用FCM数据消息来创建自定义通知,即使你的应用在后台,onMessageReceived也会被调用,这样你就可以处理数据并显示自定义通知。
https://firebase.google.com/docs/cloud-messaging/android/receive
必须从服务器发送的数据消息格式:

{"message":{
"token":"Your Device Token",
"data":{
  "Nick" : "Mario",
  "body" : "great match!",
  "Room" : "PortugalVSDenmark"
}
}
}
rqdpfwrv

rqdpfwrv4#

  • FCM* 不会发送后台通知,如果你的应用程序被杀死了,正如你在你的answer中描述的handleIntent()解决方案它可能适用于一些设备和一些旧版本的 FCM,也如果你@override方法,没有在官方文档中描述的firebase你可能会遇到一些问题,你使用它在你自己的风险!.
    解决方案是什么

除了 FCM 之外,您还需要使用自己的推送通知服务,如 Telegram
或者在 GCM 旁边使用 * SyncAdapter *,如 Gmail
因此,如果你需要它像那些应用程序一样成功地工作,你必须使用你自己的黑客

dwbf0jvd

dwbf0jvd5#

公共类FirebaseMessageReceiver扩展了FirebaseMessageService {

private static final String TAG = "main";
String s12;
String channel_id = "general";
Intent intent;

@Override
public void onNewToken(@NonNull String token)
{
    Log.d(TAG, "Refreshed token: " + token);
}
@Override
public void
onMessageReceived(RemoteMessage remoteMessage) {
    s12=remoteMessage.getNotification().getClickAction();
    Log.d("tttt",(remoteMessage.getData().toString()));
    Log.d("ttttttt",(remoteMessage.getNotification().toString()));
    if (remoteMessage.getNotification() != null) {
        showNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
    }
    //
}

public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("FirebaseMessageReceiver");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }

            onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}

private RemoteViews getCustomDesign(String title, String message) {
    RemoteViews remoteViews = new RemoteViews(getApplicationContext().getPackageName(), R.layout.notification);
    remoteViews.setTextViewText(R.id.title111, title);
    remoteViews.setTextViewText(R.id.message111, message);
    remoteViews.setImageViewResource(R.id.icon111, R.drawable.favicon);
    return remoteViews;
}
// Method to display the notifications
public void showNotification(String title, String message) {
    intent  = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(s12));
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent notifyIntent = PendingIntent.getActivity(this, 0, intent,
            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
    Log.d("notifyy",notifyIntent.toString());
    NotificationCompat.Builder builder
            = new NotificationCompat
            .Builder(getApplicationContext(),
            channel_id)
            .setSmallIcon(R.drawable.favicon)
            .setAutoCancel(true)
            .setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
            .setOnlyAlertOnce(true)
            .setContentIntent(notifyIntent);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
        builder = builder.setContent(getCustomDesign(title, message));
    }
    else {
        builder = builder.setContentTitle(title)
                .setContentText(message)
                .setSmallIcon(R.drawable.favicon);
    }
    NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    // Check if the Android Version is greater than Oreo
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(channel_id, "web_app",
                NotificationManager.IMPORTANCE_HIGH);
        notificationManager.createNotificationChannel(
                notificationChannel);
    }
    notificationManager.notify(0, builder.build());
}

}

相关问题