我正在使用Firebase并测试在应用程序处于后台时从服务器发送通知到我的应用程序。通知发送成功,它甚至出现在设备的通知中心,但当通知出现或即使我点击它,我的FCMessagingService中的onmessagerreceived方法永远不会被调用。

当我测试这个,而我的应用程序是在前台,onmessagerreceived方法被调用,一切工作正常。问题发生在应用程序在后台运行时。

这是我有意为之的行为吗,或者我有办法解决这个问题吗?

这是我的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"));
        }
    }
}

当前回答

基于以下情况调用的onmessagerecreceived (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"
  }
}

应用程序在前台:

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

后台应用:

onmessagerreceived (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"
  }
}

调用onmessagerreceived()的解决方案

应用程序在前台:

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

后台应用:

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

Code

 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

其他回答

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

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

我也有同样的问题。如果应用程序是前台-它会触发我的后台服务,我可以根据通知类型更新我的数据库。 但是,应用程序将转到后台-默认的通知服务将小心地向用户显示通知。

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

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

在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>

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

消息有两种类型:通知消息和数据消息。 如果你只发送数据消息,那就是在你的消息字符串中没有通知对象。它会在应用程序在后台时被调用。

值得强调的一点是,你必须使用数据消息-数据键-让onmessagerecreceived处理程序被调用,即使应用程序是在后台。你不应该在你的有效负载中有任何其他通知消息键,否则如果应用程序在后台,处理程序将不会被触发。

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

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

使用您的应用服务器和FCM服务器API:只设置数据键。可以 要么可折叠,要么不可折叠。

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

然而,我最终找到了一种方法,使用通知消息发送数据,并从意图中检索它。

这里的关键是向Notification消息添加数据有效负载。

例子:

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

在你这样做之后,你将能够以这种方式获得你的信息:

intent.getExtras () .getString(“标题”) message_title

而且 intent.getExtras () .getString(“信息”) message_body

参考