当应用程序在后台时,不会调用Firebase onMessageReceived

Cyo*_*nos 201 android firebase firebase-cloud-messaging

我正在使用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"));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Art*_*son 123

这是按预期工作的,只有当您的应用位于前台时,通知消息才会传递到您的onMessageReceived回调.如果您的应用程序处于后台或已关闭,则通知中心会显示通知消息,并且该消息中的任何数据都会传递给由于用户点击通知而启动的意图.

您可以指定click_action以指示在用户点击通知时应启动的意图.如果未指定click_action,则使用主活动.

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

getIntent().getExtras();
Run Code Online (Sandbox Code Playgroud)

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

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

  • 当我使用Firebase通知控制台时,有没有办法设置`click_action`? (5认同)
  • 好的,但如果应用程序被杀死(没有前景或背景)怎么办? (5认同)
  • 正确!因此,在向Android发送通知消息时,附带的数据应该是增强通知体验的数据.它不应该是app关键数据,即使用户解除通知,也要使用数据消息来获取应用程序所需的数据. (4认同)
  • 但是如何禁用用户丢弃通知?因为如果用户丢弃它,则意味着将跳过所有数据......对吗? (2认同)
  • 这并不完全正确。如果消息仅包含数据而不是通知有效负载,则无论应用程序是否处于前台,消息都将始终传递到onMessageReceive。 (2认同)
  • 不要发送通知!仅发送数据并在其中包含“title”和“message”字段。在这种情况下,“onMessageReceived()”将在打开和关闭的应用程序上调用。您将构建自定义通知并使用 BroadcastReceiver 进行翻译。在这种情况下,完全控制每个应用程序状态中的任何通知。 (2认同)

Zoh*_*Ali 106

notification从服务器请求中完全删除字段.data发送并处理它,onMessageReceived()否则onMessageReceived()当应用程序处于后台或被杀时,您将不会被触发.

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

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

{
  "data":{
    "id": 1,
    "missedRequests": 5
    "addAnyDataHere": 123
  },
  "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......",
  "priority": "high"
}
Run Code Online (Sandbox Code Playgroud)

所以你可以onMessageReceived(RemoteMessage message)像这样收到你的数据....让我说我必须得到身份证明

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

  • 我发现,如果我只发送数据消息,那么从任务管理器中清除的应用程序将无法获得通知.这是一个预期的行为吗? (8认同)
  • 在奥利奥杀死app时,onMessageReceived没有被调用.我只有有效载荷数据.你有任何更新吗? (4认同)
  • 爱你很多这个答案:p (3认同)
  • 这是我在后台接收消息的解决方案! (2认同)
  • 奇迹般有效! (2认同)
  • 你好,但是当应用程序完全关闭时,它就不起作用了 (2认同)

man*_*rol 63

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

  1. 前台状态:通知的单击将转到您正在提供的待处理的Intent活动,同时通过编程方式创建通知,因为它通常使用通知的数据有效负载创建.

  2. 后台/已杀死状态 - 此处,系统本身会根据通知有效负载创建通知,单击该通知将转到应用程序的启动器活动,您可以在任何生命周期方法中轻松获取Intent数据.

  • 我有com.google.firebase:firebase-messaging:11.6.2&handleIntent现在是最终版.检查/sf/ask/3311570881/ (8认同)
  • 太棒了,但在这种情况下我没有看到"OnMessageReceived"有用! (5认同)
  • 我在handleIntent(Intent intent)中处理通知显示逻辑,但是当应用程序在后台时,会显示2个通知,一个是我创建的,另一个是默认包含来自通知的整个消息. (4认同)

小智 29

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

在该课程中,您可以使用notificationbuilder进行自己的通知.

例:

 @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());
    }
Run Code Online (Sandbox Code Playgroud)

  • 谢谢..我改变了我的服务器代码并使用"数据"而不是"通知",现在它的工作完美, (6认同)
  • @Koot只有在应用程序位于前景时才有效,如果它在后台则不行.你能帮助我在这两种情况下触发这个事件吗? (4认同)
  • 这里实际上有三种可能的情况.1)应用程序在前台.2)应用程序在后台.3)应用程序没有运行.如您所说,前两种情况下将收到"数据"消息,但在应用程序未运行时,在第三种情况下不会*.要满足所有三种情况,您需要在消息中设置"通知"字段.(如果你想支持iOS和Android客户端,也是一个好主意) (3认同)

Md.*_*rim 28

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

Firebase有三种消息类型:

通知消息:通知消息适用于背景或前景.当应用程序处于后台时,通知消息将传递到系统托盘.如果应用程序是在前台,消息被处理onMessageReceived()didReceiveRemoteNotification回调.这些基本上就是所谓的显示消息.

数据消息:在Android平台上,数据消息可以在后台和前台工作.数据消息将由onMessageReceived()处理.这里的平台特定说明如下:在Android上,可以在用于启动活动的Intent中检索数据有效负载.具体地说就是,如果你有"click_action":"launch_Activity_1",你可以通过检索此意图getIntent()仅从Activity_1.

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

另外,我建议您使用onMessageReceived方法(请参阅数据消息)来提取数据包.根据您的逻辑,我检查了bundle对象,但没有找到预期的数据内容.以下是对可能提供更清晰的类似案例的引用.

有关更多信息,请访问我的主题

  • 值得一提的是,如果设备处于深度打ze模式(Android 7.0中引入),则不会收到“数据消息”。小心那些! (2认同)

小智 21

根据Firebase Cloud Messaging文档 - 如果Activity在前台,则将调用onMessageReceived.如果活动处于后台或已关闭,则通知中心会显示应用启动器活动的通知消息.如果您的应用处于后台,可以通过调用用于firebase消息传递的rest service api来点击通知来调用您的自定义活动:

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

方法类型 - POST

Header- Content-Type:application/json
Authorization:key=your api key
Run Code Online (Sandbox Code Playgroud)

车身/有效载荷:

{ "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)"
} 
Run Code Online (Sandbox Code Playgroud)

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

<intent-filter>
                <action android:name="OPEN_ACTIVITY_1" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
Run Code Online (Sandbox Code Playgroud)


vis*_*156 16

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"
  }
}
Run Code Online (Sandbox Code Playgroud)
  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"
  }
}
Run Code Online (Sandbox Code Playgroud)

调用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());


}
Run Code Online (Sandbox Code Playgroud)

参考链接:

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


Nag*_*nti 12

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

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

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);
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

在manifest.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>
Run Code Online (Sandbox Code Playgroud)

在最新的Android 8.0版本中测试了这个解决方案.谢谢


Gen*_*ani 11

如果应用程序在后台模式或无效(杀死),以及您点击通知,您应该为您在LaunchScreen有效载荷(在我的情况下推出的屏幕是MainActivity.java).

所以在onCreate的MainActivity.java中检查Extras:

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


Gan*_*kar 8

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

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

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

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

例子:

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

A.如果是前景:

  • remoteMessage.data["key"] 会起作用

B.在后台情况下:-remoteMessage.data["key"] 将返回 null,但如果您在默认活动中找到相同的意图数据,则使用 getIntent().getExtras().getString("key") 将起作用

C.如果终止:-remoteMessage.data["key"] 将返回 null,但如果您在默认活动中找到相同的意图数据,则 getIntent().getExtras().getString("key") 将起作用

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

D.如果是前景:

  • remoteMessage.data["key"] 会起作用

E.如果有背景:

  • remoteMessage.data["key"] 会起作用

F.如果发生杀戮:

  • remoteMessage.data["key"] 会起作用

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

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

  • 非常有用的消息,为什么它没有在 android 文档中突出显示。 (2认同)

小智 8

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

但有时,如果您无法确定收到的消息类型,则必须对其进行处理。我在这里发布我的方法。您刚刚实现了 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

}

  • +1,因为所有其他答案都对我不起作用。我没有收到有效负载或收到 onMessageRecieved 调用,因为我的应用程序位于前台。为了接收通知有效负载/数据,我们需要重写handleIntent。这次真是万分感谢。 (2认同)

t3h*_*Exi 7

覆盖我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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Uza*_*air 5

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

if(getIntent().getExtras()! = null){
  //do your stuff
}else{
  //do that you normally do
}
Run Code Online (Sandbox Code Playgroud)


Fra*_*ank 5

根据 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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Rav*_*831 5

尝试这个:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

好运


归档时间:

查看次数:

163025 次

最近记录:

5 年,11 月 前