当应用程序在后台时,FCM带有数据的Intent会被发送到哪里?

14

我已经在我的应用程序中实施了Firebase,并且使用额外数据发送推送通知。当我的应用程序在前台时,我可以正确处理数据并显示自己的通知,但是当Firebase在应用程序处于“已回到主页”状态(未被杀死)时,“自动”显示通知时,我会遇到一个获取数据的问题。根据文档Activity 应该收到使用我的值填充的新Intent和额外参数,但实际上应用程序只是返回到前台,恢复旧状态。

场景:

  1. 打开应用程序,按主页键
  2. 通过Firebase控制台发送推送通知,Firebase创建Notification而没有调用onMessageReceived(根据文档中的表格,应该调用?)
  3. 当用户选择通知时,应用程序将以与“已回到主页”状态相同的状态带到前台,并且Intent使用用于打开最上面的Activity的“原始”额外参数进行填充

我在onCreateonNewIntentonResumeActivity)和onMessageReceived (Service)中都有日志,只调用了onResume,在其中我打印出额外参数,如下所示:

if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("Activity onResume", "Key: " + key + " Value: " + value);
        }
    }
4个回答

7

所以我在寻找这个答案并阅读了相同的内容,它必须在某个地方。 我知道这已经是一年前的事了,但他们仍然没有真正澄清。 在与通知相关联的pendingActivity中(在我的情况下是MainActivity),我添加了以下内容。 请注意,我是通过Google CodeLabs com.example.android.eggtimernotifications来解决问题的,而不是这个答案。

    override fun onResume() {
        super.onResume()
        intent?.run {
            val keys = this.extras?.keySet()
            if (!keys.isNullOrEmpty()) {
                keys.forEach { key ->
                    when (this.extras!![key]) {
                        is Long -> println("$key = ${this.getLongExtra(key, 0L)}")
                        is Int -> println("$key = ${this.getIntExtra(key, 0)}")
                        is String -> println("$key = ${this.getStringExtra(key)}")
                        is Boolean -> println("$key = ${this.getBooleanExtra(key, false)}")
                        else -> println("unkonwn Type")
                    }
                }
            }
        }
    }

这导致以下结果。
  • I/System.out: google.delivered_priority = high
  • I/System.out: google.sent_time = 1585284914411
  • I/System.out: google.ttl = 2419200
  • I/System.out: google.original_priority = high
  • I/System.out: cereal = Shreddies
  • I/System.out: from = /topics/breakfast
  • I/System.out: milk = 1 杯
  • I/System.out: sugar = 无
  • I/System.out: google.message_id = 0:1585284914700957%f6ddf818f6ddf818
  • I/System.out: collapse_key = com.example.android.eggtimernotifications

数据键是cereal、from、milk和sugar。


完美,但我可以得到消息和标题吗? - Fortran

6

同时包含通知和数据负载的消息,无论是在后台还是前台。在这种情况下,数据负载将传递给启动器活动意图的extras中。如果您想在其他活动中获取它,则必须在数据负载上定义click_action。因此,请在启动器活动中获取意图extra。

编辑:

文档中得知:-

当应用程序处于后台时,应用程序会在通知托盘中接收通知负载,并且只有在用户点击通知时才处理数据负载。

因此,请在单击通知后检查启动器活动的oncreate()方法以获取getIntent() extras。


1
Firebase会在应用程序处于后台时调用启动器活动的getIntent()部分。您是否在应用程序处于后台时收到通知? - Nainal
2
如果您收到通知,请单击通知并检查是否调用了启动器活动的getIntent方法? - Nainal
FCM会调用此方法,在您的代码下的splashScreen的oncreate方法中放置一个日志:- 如果(getIntent().getExtras() != null)... - Nainal
即使我定义了click_action,按下Home键并收到通知,对我来说仍无法工作-> 它会将应用程序带回当前状态,我无法获取通知数据。 - famfamfam
找到问题了,我的MainScreen设置了laughMode = single top?去掉这行就可以获取数据了。 - famfamfam
显示剩余2条评论

2

当应用程序处于后台时,不会调用onMessageReceived()方法。我几个月前遇到了这个问题。我通过重写handlerIntent方法来解决它。但是你的firebase消息库应该

implementation '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("MessagingService");

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

如果您不想降级您的库,则可以指定一个click_action来指示当用户点击通知时应启动的意图。如果未指定click_action,则使用主要活动。

当意图被启动时,您可以使用

getIntent().getExtras();

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

有关通知消息的更多信息,请参见https://firebase.google.com/docs/cloud-messaging/android/receive#sample-receive


当前Firebase版本为17(我正在使用17.1.+),我不会降级此库,尤其是这么多,因此这不是一个解决方案。在当前版本中,我们无法覆盖handleIntent - snachmsm
我知道有些人不愿意降级库,因此我已经提到了最新版本的解决方案。 - Erselan Khan

1
根据云消息文档,消息可以分为以下3种状态:
  1. 通知
  2. 数据
  3. 通知和数据
对于第二种情况,onMessageReceived将在没有UI和其他处理的情况下被调用。稍后您可以自定义显示内容。
当涉及到第三种情况时,Android将显示通知并保留数据,直到有用户交互。点击后,它只是恢复您现有的活动。您的onNewIntent未触发,因为启动模式不是FLAG_ACTIVITY_SINGLE_TOP
您还应检查日志输出,以获取Google Play服务已过期的信息。

使用 Firebase 控制台,我只能发送通知或通知和数据推送。我必须使用第二个选项来进行自定义参数。当应用程序在后台处于“home”状态时,“onMessageReceived”根本不会被调用(无论在接收推送的时候还是当通知被点击时)。 - snachmsm
@snachmsm,无法仅从控制台发送数据消息。根据文档:在受信任的环境中,例如Cloud Functions或您的应用程序服务器,请仅使用Admin SDK或FCM服务器协议:设置数据键。 - 3mpty
这不是真的,发送推送表单中的最后一部分称为“高级设置”(或选项,我已本地化控制台),它允许您添加自定义键值参数。当应用程序在前台或被杀死时,我可以毫无问题地获取它们。 - snachmsm
控制台允许您发送文本和可选数据。但是您无法仅从控制台发送数据消息。这就是区别所在。 - 3mpty
这是正确的,但它并没有解决我的问题...我需要额外的数据,所以我必须自己处理自动显示“通知”,其中携带着我的字段。问题在于,在问题描述的情况下,我无法获取我的键值对... - snachmsm
你是对的,在AndroidManifest中移除laughMode=singleTop,然后它就可以工作了。 - famfamfam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接