Firebase onMessageReceived 在后台应用时未调用

Firebase onMessageReceived not called when app in background

提问人:Cyogenos 提问时间:5/21/2016 最后编辑:Frank van PuffelenCyogenos 更新时间:5/30/2023 访问量:283047

问:

我正在使用 Firebase,并测试在应用处于后台时从我的服务器向我的应用发送通知。通知发送成功,甚至出现在设备的通知中心,但是当通知出现时,或者即使我单击它,也不会调用我的 FCMessagingService 中的 onMessageReceived 方法。

当我的应用程序在前台时测试它时,调用了 onMessageReceived 方法,一切正常。当应用程序在后台运行时,会出现此问题。

这是预期的行为,还是有办法解决这个问题?

这是我的FBMessagingService:

import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class FBMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i("PVL", "MESSAGE RECEIVED!!");
        if (remoteMessage.getNotification().getBody() != null) {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getNotification().getBody());
        } else {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getData().get("message"));
        }
    }
}
android firebase firebase-cloud-messaging

评论

0赞 Kato 5/21/2016
除了 json 正文,你的 onTokenRefresh 代码在哪里?你完成了 Android 设置吗?
4赞 Cyogenos 5/22/2016
通知的 json 正文是什么意思?此外,我的 onTokenRefresh 代码位于我的 FirebaseInstanceID 服务中。
0赞 AL. 5/23/2016
你能发布你要发送的样本有效负载吗?
0赞 YasirSE 7/25/2016
使用 istudy.io/android-push-notifications-using-firebase-fcm
0赞 Md. Sajedul Karim 8/27/2016
您也可以 stackoverflow.com/questions/39046270/ 检查此线程...

答:

1赞 Octavian Lari 5/23/2016 #1

我遇到了这个问题(如果应用程序在后台或已关闭,应用程序不想在通知单击时打开),并且问题是通知正文中无效,请尝试将其删除或更改为有效内容。click_action

198赞 Arthur Thompson 5/24/2016 #2

这按预期工作,仅当您的应用处于前台时,通知消息才会发送到您的 onMessageReceived 回调。如果您的应用处于后台或已关闭状态,则通知中心会显示一条通知消息,并且该消息中的所有数据都会传递到因用户点击通知而启动的 Intent。

您可以在 JSON 中指定 a,以指示在用户点击通知时应启动的 intent。如果未指定click_action,则使用主活动。click_action

启动 intent 后,您可以使用

getIntent().getExtras();

检索一个 Set,该 Set 将包含与通知消息一起发送的任何数据。

有关通知消息的更多信息,请参阅文档

评论

7赞 Nii Laryea 5/31/2016
有没有办法设置我使用 Firebase 通知控制台的时间?click_action
7赞 michalu 6/15/2016
好的,但是如果应用程序被杀死(没有前景或背景)怎么办?
4赞 Sirop4ik 9/1/2016
但是如何禁用用户丢弃通知呢?因为如果用户丢弃它,则意味着所有数据都将被跳过......右?
4赞 Arthur Thompson 9/3/2016
正确!因此,在向 Android 发送通知消息时,随附的数据应该是增强通知体验的数据。它不应该是应用关键数据,即使用户关闭通知,也应将数据消息用于应用程序所需的数据。
15赞 JacksOnF1re 8/15/2017
这并不完全正确。如果消息仅包含数据而不包含通知有效负载,则无论应用是否在前台,消息都将始终传递到 onMessageReceive。
32赞 Koot 5/27/2016 #3

我也有同样的问题。使用“数据消息”而不是“通知”更容易。数据消息始终加载类 onMessageReceived。

在该类中,您可以使用通知生成器制作自己的通知。

例:

 @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        sendNotification(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"));
    }

    private void sendNotification(String messageTitle,String messageBody) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0 /* request code */, intent,PendingIntent.FLAG_UPDATE_CURRENT);

        long[] pattern = {500,500,500,500,500};

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setVibrate(pattern)
                .setLights(Color.BLUE,1,1)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

评论

7赞 Mahesh Kavathiya 6/2/2016
谢谢。。我更改了我的服务器代码并使用“数据”而不是“通知”,现在它运行良好,
5赞 Anant Shah 7/16/2016
@Koot只有当应用程序在前台时才起作用,而不是在后台时才起作用。你能帮我在这两种情况下触发这个事件吗?
0赞 Koot 7/23/2016
@AnantShah Firebase 服务器的 POST 是什么样的?
5赞 Steve Moseley 8/26/2016
这里实际上有三种可能的情况。1)前台应用。2)后台应用程序。3)应用程序未运行。正如您所说,在前两种情况下将收到“数据”消息,但在第三种情况下,当应用程序未运行时不会收到。为了满足所有三种情况,您需要在消息中设置“通知”字段。(如果您想支持 iOS 和 Android 客户端,这也是一个好主意)
1赞 Koot 8/27/2016
即使在应用程序未运行的情况下,我也会在函数 onmessagereceived 上收到来自服务器的消息。我同意你的看法,如果你也想支持ios,最好使用'notification'。
30赞 Ankit Adlakha 6/3/2016 #4

根据 Firebase Cloud Messaging 文档 - 如果 Activity 在前台,则将调用 onMessageReceived。如果活动处于后台或已关闭状态,则通知消息会显示在应用启动器活动的通知中心中。 如果您的应用处于后台状态,您可以通过调用 REST Service API for firebase messaging 来调用自定义活动,如下所示:

URL-https://fcm.googleapis.com/fcm/send

方法类型 - POST

Header- Content-Type:application/json
Authorization:key=your api key

车身/有效载荷:

{ "notification": {
    "title": "Your Title",
    "text": "Your Text",
     "click_action": "OPEN_ACTIVITY_1" // should match to your intent filter
  },
    "data": {
    "keyname": "any value " //you can get this data as extras in your activity and this data is optional
    },
  "to" : "to_id(firebase refreshedToken)"
} 

在您的应用程序中使用它,您可以在要调用的活动中添加以下代码:

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

评论

0赞 Cyogenos 6/4/2016
我应该在哪里创建意向并让它打开特定活动?我知道这会在清单中注册OPEN_ACTIVITY_1意图,但我实际上在哪里调用它?
1赞 Ankit Adlakha 6/7/2016
检查这个:firebase.google.com/docs/cloud-messaging/...
0赞 CoolMind 6/25/2019
我们应该从 intent-filters 调用一个活动吗?还是在 ?onMessageReceived
7赞 Uzair 6/18/2016 #5

默认情况下,当您的应用程序处于后台并单击通知时,您的应用程序中的启动器活动将启动,如果您有任何数据部分的通知,您可以在相同的活动中处理它,如下所示:

if(getIntent().getExtras()! = null){
  //do your stuff
}else{
  //do that you normally do
}

评论

0赞 Mac_Play 3/11/2018
如果我从 mainActivity 导航,如何导航回特定的 Activity?
0赞 Komal12 3/28/2019
@Uzair getIntent().getExtras()总是得到null,你还有其他解决方案吗?当应用运行时,onMessageReceived 方法不调用
0赞 Eric B. 7/20/2016 #6

我遇到了同样的问题,并对此进行了更多挖掘。当应用程序在后台时,通知消息会发送到系统托盘,但会向
See https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3
https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java 发送数据消息
onMessageReceived()

为确保您发送的消息,文档会说:“使用您的应用服务器和 FCM 服务器 API:仅设置数据密钥。可以是可折叠的,也可以是不可折叠的。
查看 https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

0赞 Shongsu 8/17/2016 #7

消息有两种类型:通知消息和数据消息。 如果仅发送数据消息,则消息字符串中没有通知对象。当您的应用程序在后台时,将调用它。

44赞 Md. Sajedul Karim 8/27/2016 #8

以下是有关 firebase 消息的更清晰概念。我是从他们的支持团队那里找到的。

Firebase 有三种消息类型

通知消息:通知消息在后台或前台工作。当应用程序处于后台时,通知消息将传递到系统托盘。如果应用位于前台,则消息由 或 回调处理。这些实质上就是所谓的显示消息。onMessageReceived()didReceiveRemoteNotification

数据消息:在Android平台上,数据消息可以在后台和前台工作。数据消息将由 onMessageReceived() 处理。此处特定于平台的说明如下:在 Android 上,可以在用于启动活动的 Intent 中检索数据有效负载。详细地说,如果有 ,则只能从 中检索此意图。"click_action":"launch_Activity_1"getIntent()Activity_1

同时包含通知和数据负载的消息:在后台时,应用会在通知托盘中接收通知有效负载,并且仅在用户点击通知时处理数据负载。在前台时,您的应用会收到一个消息对象,其中包含两个可用的有效负载。其次,click_action参数通常用于通知负载,而不是数据负载。如果在数据负载中使用,此参数将被视为自定义键值对,因此您需要实现自定义逻辑才能使其按预期工作。

另外,我建议您使用 onMessageReceived 方法(请参阅数据消息)来提取数据包。根据您的逻辑,我检查了捆绑包对象,但没有找到预期的数据内容。这里引用了一个类似的案例,可能会提供更清晰的信息。

从服务器端来看,firebase 通知的格式应如下

服务器端应发送“通知”对象。我缺少“通知”对象,没有收到消息。TargetActivitygetIntent()

正确的消息格式如下:

{
 "data": {
  "body": "here is body",
  "title": "Title"
 },
"notification": {
  "body": "here is body",
  "title": "Title",
  "click_action": "YOUR_ACTION"
 },
 "to": "ffEseX6vwcM:APA91bF8m7wOF MY FCM ID 07j1aPUb"
}

欲了解更多信息,请访问 https://stackoverflow.com/a/39805517

评论

6赞 Sameer J 2/22/2019
值得一提的是,如果设备处于深度打瞌睡模式(在 Android 7.0 中引入),则不会收到“数据消息”。小心那些!
1赞 gdenuf 9/18/2016 #9

值得强调的一点是,即使应用程序在后台,您也必须使用数据消息(仅数据键)来调用 onMessageReceived 处理程序。有效负载中不应有任何其他通知消息密钥,否则,如果应用处于后台状态,则不会触发处理程序。

这里提到了(但在 FCM 文档中没有强调):

https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

使用应用服务器和 FCM 服务器 API:仅设置数据密钥。可以是 可折叠或不可折叠。

189赞 Zohab Ali 10/17/2016 #10

从服务器请求中完全删除通知字段。仅发送数据并对其进行处理,否则当应用程序处于后台或被杀死时,您将不会被触发。onMessageReceived()onMessageReceived()

不要忘记在通知请求中包含字段。根据文档:数据消息以正常优先级发送,因此它们不会立即到达;这也可能是问题所在。"priority": "high"

这是我从服务器发送的内容

{
  "data":{
    "id": 1,
    "missedRequests": 5
    "addAnyDataHere": 123
  },
  "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......",
  "priority": "high"
}

因此,您可以像这样接收数据。假设我必须获得 idonMessageReceived(RemoteMessage message)

Object obj = message.getData().get("id");
        if (obj != null) {
            int id = Integer.valueOf(obj.toString());
        }

评论

11赞 Prabhjot Singh 12/28/2016
我发现如果我只发送数据消息,那么从任务管理器中清除的应用程序将无法收到通知。这是预期的行为吗?
0赞 Javier Delgado 4/20/2017
这是否意味着在控制台中我们无法处理通知数据,如果我们发送没有通知部分的纯 HTTP 请求,那么我们可以处理通知数据?我开始使用 Firebase 控制台,希望我能做到这一点,所以我又回到了 HTTP POST 通知:-(
9赞 Samir Mangroliya 2/27/2018
在 Oreo 中,当应用被杀死时,onMessageReceived 不会被调用。我只是只有数据的有效载荷。你有更新吗?
2赞 C Williams 8/13/2019
嗨,但是当应用程序完全关闭时,它不起作用
1赞 coolcool1994 8/25/2020
我在应用程序的onCreate中有代码,如果应用程序被杀死,它就会崩溃,并且我收到了通知。还发现,在运行android studio后立即杀死应用程序后,您不会收到通知。我再次打开应用程序并再次杀死它并收到通知。奇怪。
1赞 Vito Valov 11/25/2016 #11

我正在使用的后端使用的是通知消息,而不是数据消息。因此,在阅读了所有答案后,我试图从启动活动的意图捆绑包中检索额外内容。 但无论我尝试从哪个键中检索,该值始终为 null。getIntent().getExtras();

但是,我终于找到了一种使用通知消息发送数据并从意图中检索数据的方法。

这里的关键是将数据有效负载添加到通知消息中。

例:

{
    "data": {
        "message": "message_body",
        "title": "message_title"
    },
    "notification": {
        "body": "test body",
        "title": "test title"
    },
    "to": "E4An.."
}

执行此操作后,您将能够通过以下方式获取您的信息:

intent.getExtras().getString("title")将是message_title

并将intent.getExtras().getString("message")message_body

参考

2赞 Aman Shekhar 12/7/2016 #12

只需在 MainActivity 的 onCreate 方法中调用它:

if (getIntent().getExtras() != null) {
           // Call your NotificationActivity here..
            Intent intent = new Intent(MainActivity.this, NotificationActivity.class);
            startActivity(intent);
        }

评论

0赞 Mac_Play 3/11/2018
如果我从 mainActivity 导航,如何导航回特定的 Activity?
16赞 Gent 1/19/2017 #13

如果应用程序处于后台模式或非活动(已杀),并且您单击通知,则应检查 LaunchScreen 中的有效负载(在我的情况下,启动屏幕是 MainActivity.java)。

因此,在 MainActivity 中.javaonCreate 上检查 Extras

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

评论

0赞 Md.Tarikul Islam 1/2/2018
如何获取通知标题、正文和数据?
1赞 felixwcf 1/26/2018
谢谢,这就是答案。@Md.Tarikul Islam 使用 onMessageReceived() 如本问题所述。
1赞 Arun 3/1/2017 #14

如果您的问题与显示大图像有关,即如果您从 firebase 控制台发送带有图像的推送通知,并且仅当应用程序在前台时才会显示图像。此问题的解决方案是发送仅包含数据字段的推送消息。像这样的东西:

{ "data": { "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg", "message": "Firebase Push Message Using API" "AnotherActivity": "True" }, "to" : "device id Or Device token" }

评论

0赞 jekaby 6/22/2017
您在“AnotherActivity”之前丢失了逗号。我的机器人振动,但实际上什么也没显示(没有文字,没有图像,没有推送)。
69赞 manas.abrol 5/9/2017 #15

此方法 handleIntent() 已弃用,因此可以按如下方式处理通知:

  1. 前台状态:单击通知将转到您在按语法创建通知时提供的待处理 Intent 活动,因为它通常使用通知的数据负载创建。

  2. 后台/终止状态 - 在这里,系统本身会根据通知有效负载创建通知,单击该通知将带您进入应用程序的启动器活动,您可以在其中轻松获取任何生命周期方法中的 Intent 数据。

评论

1赞 Igor Janković 5/24/2017
谢谢!!!我在这个问题上浪费了几天时间,而这个问题救了我。
0赞 EduXavier 5/24/2017
真的是完美的解决方案!
4赞 Joyson 6/9/2017
我正在处理handleIntent(Intent intent)中的通知显示逻辑,但是当应用程序处于后台时,会显示2个通知,一个是我创建的,另一个默认包含通知中的完整消息。
5赞 Alaa AbuZarifa 10/4/2017
太棒了,但在这种情况下我看不出有什么用!?OnMessageReceived
8赞 Ronak Poriya 12/18/2017
我有com.google.firebase:firebase-messaging:11.6.2 & handleIntent现在是最终的。检查 stackoverflow.com/questions/47308155/...
10赞 t3h Exi 10/4/2017 #16

为我覆盖作品的方法。handleIntentFirebaseMessageService

这里是 C# (Xamarin) 中的代码

public override void HandleIntent(Intent intent)
{
    try
    {
        if (intent.Extras != null)
        {
            var builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            foreach (string key in intent.Extras.KeySet())
            {
                builder.AddData(key, intent.Extras.Get(key).ToString());
            }

            this.OnMessageReceived(builder.Build());
        }
        else
        {
            base.HandleIntent(intent);
        }
    }
    catch (Exception)
    {
        base.HandleIntent(intent);
    }
}

这就是 Java 代码

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

            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);
    }
}

评论

0赞 Ettore Gallina 11/16/2017
handleIntent() 是最终的
0赞 Hiroto 11/17/2017
@Ettore 如何调用handleIntent函数?
0赞 Ettore Gallina 11/17/2017
当您收到来自 Firebase 的消息时,系统会调用该方法,但您无法覆盖该方法,因为该方法已声明为 final。(Firebase 11.6.0)
5赞 Frank 10/26/2017 #17

根据 t3h Exi 的解决方案,我想在这里发布干净的代码。只需将其放入 MyFirebaseMessagingService 中,如果应用程序处于后台模式,一切正常。您至少需要编译 com.google.firebase:firebase-messaging:10.2.1

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

            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);
    }
}

评论

0赞 matdev 1/15/2018
我正在尝试实现您的解决方案,但 handleIntent() 方法在我的 SDK 版本 (SDK 27) 中是最终的,所以我无法在我的服务中覆盖它......
0赞 Frank 1/19/2018
是的,但这不是我的错,也不是给 -1 !!的任何理由很嚣张。它一直工作到 firebase 11.4.2,然后谷歌更改了它(使此方法最终确定)。因此,现在您必须使用通知编写自己的解决方案。
0赞 matdev 1/19/2018
我没有给-1,而是+1!
0赞 Amitabha Biswas 2/26/2018
你救了我的工作:P
13赞 Nagendra Badiganti 11/20/2017 #18

我遇到了同样的问题。如果应用是前台 - 它会触发我的后台服务,我可以在其中根据通知类型更新我的数据库。 但是,应用程序会进入后台 - 默认通知服务将负责向用户显示通知。

这是我的解决方案,用于在后台识别应用程序并触发后台服务,

public class FirebaseBackgroundService extends WakefulBroadcastReceiver {

  private static final String TAG = "FirebaseService";

  @Override
  public void onReceive(Context context, Intent intent) {
    Log.d(TAG, "I'm in!!!");

    if (intent.getExtras() != null) {
      for (String key : intent.getExtras().keySet()) {
        Object value = intent.getExtras().get(key);
        Log.e("FirebaseDataReceiver", "Key: " + key + " Value: " + value);
        if(key.equalsIgnoreCase("gcm.notification.body") && value != null) {
          Bundle bundle = new Bundle();
          Intent backgroundIntent = new Intent(context, BackgroundSyncJobService.class);
          bundle.putString("push_message", value + "");
          backgroundIntent.putExtras(bundle);
          context.startService(backgroundIntent);
        }
      }
    }
  }
}

在清单 .xml 中

<receiver android:exported="true" android:name=".FirebaseBackgroundService" android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </receiver>

在最新的android 8.0版本中测试了此解决方案。谢谢

评论

0赞 11/22/2017
要使用这个 FirebaseBackgroundService 类吗?@Nagendra 巴迪甘蒂
0赞 11/22/2017
在何处使用此代码 public class FirebaseBackgroundService extends WakefulBroadcastReceiver @Nagendra Badiganti
0赞 Nagendra Badiganti 11/22/2017
在包中创建一个服务类,并在清单 .xml 中注册。确保您有通知的过滤器。由于该服务会针对每个 GCM 通知触发。
0赞 11/22/2017
firebase.google.com/docs/cloud-messaging/android/......我正在点击这个链接,我需要添加这个类来接收通知。只是从Firebase发送消息 第一条消息..它说已完成,但没有收到 Badiganti @Nagendra通知
1赞 Minoru 2/22/2018
WakefulBroadcastReceiver自 API 级别 26.1.0 起已弃用。
3赞 Hiren 12/7/2017 #19

如果应用程序在后台 Fire-base 默认处理通知,但是如果我们想要自定义通知,则必须更改我们的服务器端,该端负责发送我们的自定义数据(数据有效负载)

从服务器请求中完全删除通知有效负载。仅发送数据并在 onMessageReceived() 中处理它,否则当应用程序处于后台或被终止时,您的 onMessageReceived 将不会被触发。

现在,你的服务器端代码格式是这样的,

{
  "collapse_key": "CHAT_MESSAGE_CONTACT",
  "data": {
    "loc_key": "CHAT_MESSAGE_CONTACT",
    "loc_args": ["John Doe", "Contact Exchange"],
    "text": "John Doe shared a contact in the group Contact Exchange",
    "custom": {
      "chat_id": 241233,
      "msg_id": 123
    },
    "badge": 1,
    "sound": "sound1.mp3",
    "mute": true
  }
}

注意:请参阅上面代码
“text”中的这一行:“John Doe 在组 Contact Exchange 中共享了一个联系人” 在数据有效负载中,您应该使用“text”参数而不是“body”或“message”参数来描述消息描述或任何您想要使用的文本。

onMessageReceived()

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.e(TAG, "From: " + remoteMessage.getData().toString());

        if (remoteMessage == null)
            return;

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
           /* Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());*/
            Log.e(TAG, "Data Payload: " + remoteMessage);

            try {

                Map<String, String> params = remoteMessage.getData();
                JSONObject json = new JSONObject(params);
                Log.e("JSON_OBJECT", json.toString());


                Log.e(TAG, "onMessageReceived: " + json.toString());

                handleDataMessage(json);
            } catch (Exception e) {
                Log.e(TAG, "Exception: " + e.getMessage());
            }
        }
    }
4赞 Ravi Lokhande 9028351831 3/21/2018 #20

试试这个:

public void handleIntent(Intent intent) {
    try {
        if (intent.getExtras() != null) {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            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);
    }
}

祝你好运

评论

0赞 Shihab Uddin 4/8/2018
handleIntent 不再用于 firebase:11.8.0 及更高版本。
1赞 Sanjeev S 6/28/2018 #21

当收到消息并且您的应用处于后台时,通知将发送到主要活动的额外意图。

您可以在主活动的 oncreate() 或 onresume() 函数中检查额外的值。

您可以检查数据、表格等字段(通知中指定的字段)

例如,我使用数据作为密钥发送

public void onResume(){
    super.onResume();
    if (getIntent().getStringExtra("data")!=null){
            fromnotification=true;
            Intent i = new Intent(MainActivity.this, Activity2.class);
            i.putExtra("notification","notification");
            startActivity(i);
        }

}
-1赞 Kostadin Georgiev 2/1/2019 #22

Firebase 推送通知有 2 种类型

1-通知消息(显示消息)-> -- 1.1 如果您选择此变体,如果应用程序处于后台,操作系统将自行创建通知,并将数据传递到 .然后由客户端来处理这些数据。intent

-- 1.2 如果应用程序在前台,则它将通过 在 中接收通知,并由客户端来处理它。callback-functionFirebaseMessagingService

2- 数据消息(最多 4k 数据) -> 这些消息仅用于向客户端发送数据(静默),并且由客户端通过 callback-function 在后台/前台两种情况下处理它FirebaseMessagingService

这是根据官方文档:https://firebase.google.com/docs/cloud-messaging/concept-options

22赞 vishnuc156 6/19/2019 #23

onMessageReceived(RemoteMessage remoteMessage) 方法基于以下情况调用。

  • FCM 响应使用通知数据块:
{
  
"to": "device token list",
  "notification": {
    "body": "Body of Your Notification",
    "title": "Title of Your Notification"
  },
  "data": {
    "body": "Body of Your Notification in Data",
    "title": "Title of Your Notification in Title",
    "key_1": "Value for key_1",
    "image_url": "www.abc.com/xyz.jpeg",
    "key_2": "Value for key_2"
  }
}
  1. 前台应用:

onMessageReceived(RemoteMessage remoteMessage) 调用,在通知栏中显示 LargeIcon 和 BigPicture。我们可以从通知数据块中读取内容

  1. 后台应用:

onMessageReceived(RemoteMessage remoteMessage) 未调用,系统托盘将接收消息并读取通知块中的正文和标题,并在通知栏中显示默认消息和标题。

  • FCM 响应仅使用数据块:

在这种情况下,请从 json 中删除通知

{
  
"to": "device token list",
  "data": {
    "body": "Body of Your Notification in Data",
    "title": "Title of Your Notification in Title",
    "key_1": "Value for key_1",
    "image_url": "www.abc.com/xyz.jpeg",
    "key_2": "Value for key_2"
  }
}

调用 onMessageReceived() 的解决方案

  1. 前台应用:

onMessageReceived(RemoteMessage remoteMessage) 调用,在通知栏中显示 LargeIcon 和 BigPicture。我们可以从通知数据块中读取内容

  1. 后台应用:

onMessageReceived(RemoteMessage remoteMessage) 调用,系统托盘不会收到消息,因为通知键不在响应中。在通知栏中显示 LargeIcon 和 BigPicture

法典

 private void sendNotification(Bitmap bitmap,  String title, String 
    message, PendingIntent resultPendingIntent) {

    NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
    style.bigPicture(bitmap);

    Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

    NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    String NOTIFICATION_CHANNEL_ID = mContext.getString(R.string.default_notification_channel_id);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);

        notificationManager.createNotificationChannel(notificationChannel);
    }
    Bitmap iconLarge = BitmapFactory.decodeResource(mContext.getResources(),
            R.drawable.mdmlogo);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.drawable.mdmlogo)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(defaultSound)
            .setContentText(message)
            .setContentIntent(resultPendingIntent)
            .setStyle(style)
            .setLargeIcon(iconLarge)
            .setWhen(System.currentTimeMillis())
            .setPriority(Notification.PRIORITY_MAX)
            .setChannelId(NOTIFICATION_CHANNEL_ID);


    notificationManager.notify(1, notificationBuilder.build());


}

参考链接:

https://firebase.google.com/docs/cloud-messaging/android/receive

评论

0赞 Ramy M. Mousa 4/22/2020
对于遇到后台问题的人来说,最重要的部分是从服务器发送的JSON中删除“notification”属性。这样就解决了问题。多谢。
0赞 Huy Nguyen 3/20/2020 #24

检查@Mahesh Kavathiya的答案。就我而言,在服务器代码中只有这样的:

{
"notification": {
  "body": "here is body",
  "title": "Title",
 },
 "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
}

您需要更改为:

{
 "data": {
  "body": "here is body",
  "title": "Title",
  "click_action": "YOUR_ACTION"
 },
"notification": {
  "body": "here is body",
  "title": "Title"
 },
 "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
}

然后,如果应用程序在后台,默认活动意图额外将获取“数据”

祝你好运!

3赞 Neeraja Gandla 3/20/2021 #25

我有类似的问题。根据本页中提到的答案和参考资料,以下是我如何通过以下方法解决问题的两分钱:

我之前的消息格式如下:

    {
  "notification": {
    "title": "AppName",
    "sound": null,
    "body": "Hey!YouhaveaMessage"
  },
  "data": {
    "param1": null,
    "param2": [
      238
    ],
    "id": 1
  },
  "to": "--the device push token here--"
}

我将消息格式修改为以下内容:

    {
  "data": {
    "title": "AppName",
    "body": "Hey! You have a message",
    "param1": null,
    "param2": [
      238
    ],
    "id": 1
  },
  "priority": "high",
  "to": " — device push token here — "
}

然后,我从“数据”有效负载本身中检索了标题、正文和所有参数。这解决了问题,即使应用程序在后台,我也可以获得 OnMessageReceived 回调。 我写了一篇博文来解释同样的问题,你可以在这里找到它。

评论

1赞 Syscall 3/20/2021
请更改为 .实际上,它不是有效的 JSON。"
0赞 Neeraja Gandla 3/21/2021
感谢您指出这一点。我现在已经修复了引号以制作这些有效的 JSON。
8赞 Ganesh Katikar 11/4/2021 #26

我可能很晚才回答,但官方文档有点令人困惑。

此外,还明确指出有两种类型的通知

  • 通知消息:FCM 自动处理
  • 数据消息:由客户端应用处理。

毫无疑问,如果服务器发送数据消息,那么 onMessageReceived() 方法肯定会被调用,但在通知消息的情况下,onMessageReceived() 方法只有在应用程序处于前台时才会被调用,并且当应用程序在后台时,我们发送的数据只是空。

例:

假设服务器正在发送通知消息类型:

一个。在前景的情况下:

  • remoteMessage.data[“key”] 将起作用

湾。如果是背景: -remoteMessage.data[“key”] 将返回 null 但在这里,如果您使用 getIntent().getExtras().getString(“key”) 在 defaul 活动中找到相同的意图数据将起作用

三.在杀戮的情况下: -remoteMessage.data[“key”] 将返回 null 但在这里,如果您使用 getIntent().getExtras().getString(“key”) 在 defaul 活动中找到相同的意图数据将起作用

现在,让我们假设服务器正在发送数据消息类型:

D.在前景的情况下:

  • remoteMessage.data[“key”] 将起作用

E.如果是背景:

  • remoteMessage.data[“key”] 将起作用

六.在杀戮的情况下:

  • remoteMessage.data[“key”] 将起作用

毫无疑问,数据消息将始终调用 onMessageReceived() 方法,但如果通知消息并且应用程序处于后台/kill 状态,您可以使用 B 的解决方案。谢谢

我希望它能节省每个人的时间。

评论

2赞 Suchith 4/19/2022
非常有用的消息,为什么它没有在Android文档中突出显示。
3赞 Sahal Nazar 6/8/2022 #27
{
      "notification": {
        "title": "Notification Title",
        "body": "Notification Body",
        "click_action": "ActivityToOpen"
      },
      "data": {
        "key": "value "
      },
      "to": "id"
}

如果 FCM 有效负载具有如上所述的 notification{} 块,并且应用处于后台,系统会使用 notification{} 中给出的标题和正文为您构建通知。当用户单击它时,click_action中提到的活动将打开,如果未提供任何内容,则默认启动器活动将打开,并且可以从以下位置访问 data{} 块中的数据

intent.extras // of the launcher activity

如果应用位于前台,则会触发 FirebaseMessagingService() 类中的函数 onMessageReceived()。我们必须自己构建通知,我们可以按如下方式访问数据:

val value = message.data.getOrDefault("key", "")

如果 FCM 有效负载没有通知块{},如下所示;

{ 
    "data": {
    "title": "Notification Title",
     "body": "Notification Body",
    "key": "value "
    },
  "to" : "id"
} 

FirebaseMessagingService() 类中的函数 onMessageReceived() 无论应用在后台还是前台都会被触发,我们必须自己构建通知。

我们可以按如下方式访问数据:

    override fun onMessageReceived(message: RemoteMessage) {
        super.onMessageReceived(message)
        val title = message.data.getOrDefault("title", "")
        val body = message.data.getOrDefault("body", "")
}
0赞 Akinyemi Jamiu 9/15/2022 #28

这是预期的行为,您需要在 firebase 通知数据集中设置click_action,以便能够从后台接收数据。

在此处查看更新的答案:https://stackoverflow.com/a/73724040/7904082

8赞 Johnny Song 11/2/2022 #29

我认为告诉您将消息类型更改为数据的答案对您来说很清楚。

但有时,如果您无法确定您是收到的消息类型,则必须处理它。我在这里发布我的方法。您刚刚实现了 FirebaseMessagingService,并在 handlIntent() 方法中处理了您的消息。从那里,您可以自定义自己的通知。您可以实现自己的方法 sendYourNotificatoin()

class FCMPushService : FirebaseMessagingService() {

companion object {
    private val TAG = "FCMPush"
}



override fun handleIntent(intent: Intent?) {
    Logger.t(TAG).i("handleIntent:${intent.toString()}")
    val data = intent?.extras as Bundle
    val remoteMessage = RemoteMessage(data)

    if (remoteMessage.data.isNotEmpty()) {
        val groupId: String = remoteMessage.data[MESSAGE_KEY_GROUP_ID] ?: ""
        val title = remoteMessage.notification?.title ?: ""
        val body =  remoteMessage.notification?.body ?: ""
        if (title.isNotEmpty() && body.isNotEmpty())
            sendYourNotificatoin(this, title, body, groupId)
    }
}

}

评论

2赞 Hamza Khan 11/25/2022
+1,因为所有其他答案都对我不起作用。我没有收到有效负载或收到 onMessageReceived 调用,因为我的应用在前台。为了接收通知有效负载/数据,我们需要覆盖 handleIntent。谢谢你。
2赞 Mert Uludogan 3/23/2023 #30

FirebaseMessagingService 具有

public void handleIntent(Intent intent) {
    String action = intent.getAction();
    if (!"com.google.android.c2dm.intent.RECEIVE".equals(action) && !"com.google.firebase.messaging.RECEIVE_DIRECT_BOOT".equals(action)) {
        if ("com.google.firebase.messaging.NEW_TOKEN".equals(action)) {
            this.onNewToken(intent.getStringExtra("token"));
        } else {
            Log.d("FirebaseMessaging", "Unknown intent action: " + intent.getAction());
        }
    } else {
        this.handleMessageIntent(intent);
    }

}

您可以简单地在自己的服务类中覆盖此函数,该类扩展了 FirebaseMessagingService。

this.handleMessageIntent(意图);-> 在应用程序关闭/后台时处理通知。您可以删除此行并使用覆盖的 onMessageRecieved() 方法中使用的函数来显示自定义布局。因此,您可以在背景/前景中显示自己的自定义布局。