Firebase onMessageReceived no se llama cuando la aplicación está en segundo plano


234

Estoy trabajando con Firebase y probando el envío de notificaciones a mi aplicación desde mi servidor mientras la aplicación está en segundo plano. La notificación se envía con éxito, incluso aparece en el centro de notificaciones del dispositivo, pero cuando aparece la notificación o incluso si hago clic en ella, nunca se llama al método onMessageReceived dentro de mi FCMessagingService.

Cuando probé esto mientras mi aplicación estaba en primer plano, se llamó al método onMessageReceived y todo funcionó bien. El problema ocurre cuando la aplicación se ejecuta en segundo plano.

¿Es este el comportamiento previsto, o hay alguna manera de que pueda solucionarlo?

Aquí está mi 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"));
        }
    }
}

Además del cuerpo json, ¿dónde está su código onTokenRefresh ? ¿Has completado la configuración de Android ?
Kato

44
¿Qué quieres decir con el cuerpo json de la notificación? Además, mi código onTokenRefresh está dentro de mi servicio FirebaseInstanceID.
Cyogenos

¿Puedes publicar la carga útil de muestra que estás enviando?
AL.


También puede consultar este hilo stackoverflow.com/questions/39046270/…
Md. Sajedul Karim

Respuestas:


144

Esto funciona según lo previsto, los mensajes de notificación se envían a su devolución de llamada onMessageReceived solo cuando su aplicación está en primer plano. Si su aplicación está en segundo plano o cerrada, se muestra un mensaje de notificación en el centro de notificaciones, y cualquier dato de ese mensaje se pasa a la intención que se inicia como resultado de que el usuario toque la notificación.

Puede especificar una acción click_ para indicar la intención que debe iniciarse cuando el usuario toca la notificación. La actividad principal se usa si no se especifica click_action.

Cuando se inicia la intención, puede usar el

getIntent().getExtras();

para recuperar un Conjunto que incluiría cualquier dato enviado junto con el mensaje de notificación.

Para más información sobre el mensaje de notificación, consulte los documentos .


66
¿Hay alguna manera de configurar click_actioncuando estoy usando la consola de notificaciones de Firebase?
Nii Laryea

66
ok, pero ¿qué pasa si se mata la aplicación (sin primer plano ni fondo)?
michalu

3
Pero, ¿cómo deshabilitar la notificación de descarte de usuario? Porque si el usuario lo descarta, significa que se omitirán todos los datos ... ¿Verdad?
Aleksey Timoshchenko

44
¡Correcto! Entonces, al enviar mensajes de notificación a Android, los datos que lo acompañan deben ser datos que mejoren la experiencia de notificación. No deben ser datos críticos de la aplicación, use mensajes de datos para los datos que la aplicación necesita incluso si el usuario rechaza la notificación.
Arthur Thompson

3
Esto no es del todo correcto. Si el mensaje solo contiene datos y no una notificación de carga, el mensaje SIEMPRE se entregará a onMessageReceive, si la aplicación está en primer plano o no.
JacksOnF1re

126

Elimine el notificationcampo completamente de su solicitud de servidor. Envíe solodata y adminístrelo; de lo onMessageReceived()contrario onMessageReceived(), no se activará cuando la aplicación esté en segundo plano o se cierre.

No olvide incluir el "priority": "high"campo en su solicitud de notificación. Según la documentación: los mensajes de datos se envían con una prioridad normal, por lo que no llegarán instantáneamente; También podría ser el problema.

Esto es lo que estoy enviando desde el servidor

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

Para que pueda recibir sus datos de onMessageReceived(RemoteMessage message)esta manera ... digamos que tengo que obtener la identificación

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

99
Descubrí que si solo envío un mensaje de datos, la aplicación que se borra del administrador de tareas no podrá recibir notificaciones. ¿Es este un comportamiento previsto?
Prabhjot Singh

2
¡Esta fue la solución para mí recibir mensajes en segundo plano!
Ray Hulha

55
En Oreo cuando se apaga la aplicación, no se llama a onMessageReceived. Solo tengo carga útil solo con datos. alguna actualización tienes?
Samir Mangroliya

2
¡Funciona de maravilla!
ssk

3
Te quiero mucho por esta respuesta: p
Ahmad Arslan

63

Este método handleIntent () se ha depreciado, por lo que el manejo de una notificación se puede hacer de la siguiente manera:

  1. Estado de primer plano: el clic de la notificación irá a la actividad del Intento pendiente que está proporcionando al crear una notificación de forma programática, ya que generalmente se crea con la carga de datos de la notificación.

  2. Antecedentes / Estado eliminado: aquí, el sistema mismo crea una notificación basada en la carga útil de la notificación y al hacer clic en esa notificación lo llevará a la actividad del iniciador de la aplicación, donde puede obtener fácilmente datos de intención en cualquiera de sus métodos de ciclo de vida.


¡¡¡Gracias!!! Perdí un par de días en este problema y este me salvó.
Igor Janković

Realmente la solución perfecta!
EduXavier

44
Estoy manejando la lógica de visualización de notificaciones en handleIntent (intento de intención), sin embargo, cuando la aplicación está en segundo plano, se muestran 2 notificaciones, una que he creado y otra por defecto que contiene todo el mensaje de la notificación.
Joyson

55
Impresionante, pero no veo ningún uso OnMessageReceiveden este caso!
Alaa AbuZarifa

8
Estoy teniendo com.google.firebase: base de fuego de mensajes: 11.6.2 y handleIntent es now.Check última stackoverflow.com/questions/47308155/...
Ronak Poriya

31

Aquí hay conceptos más claros sobre el mensaje de Firebase. Lo encontré de su equipo de soporte.

Firebase tiene tres tipos de mensajes :

Mensajes de notificación : el mensaje de notificación funciona en segundo plano o en primer plano. Cuando la aplicación está en segundo plano, los mensajes de notificación se entregan a la bandeja del sistema. Si la aplicación está en primer plano, los mensajes son manejados por onMessageReceived()o didReceiveRemoteNotificationdevoluciones de llamada. Estos son esencialmente lo que se denomina Mostrar mensajes.

Mensajes de datos : en la plataforma Android, los mensajes de datos pueden funcionar en segundo plano y en primer plano. El mensaje de datos será manejado por onMessageReceived (). Una nota específica de la plataforma aquí sería: En Android, la carga útil de datos se puede recuperar en la intención utilizada para iniciar su actividad. Para elaborar, si tiene "click_action":"launch_Activity_1", puede recuperar esta intención getIntent()desde solo Activity_1.

Mensajes con notificaciones y cargas de datos : cuando están en segundo plano, las aplicaciones reciben la carga de notificaciones en la bandeja de notificaciones y solo manejan la carga de datos cuando el usuario toca la notificación. Cuando está en primer plano, su aplicación recibe un objeto de mensaje con ambas cargas disponibles. En segundo lugar, el parámetro click_action se usa a menudo en la carga de notificación y no en la carga de datos. Si se usa dentro de la carga útil de datos, este parámetro se trataría como un par clave-valor personalizado y, por lo tanto, necesitaría implementar una lógica personalizada para que funcione según lo previsto.

Además, le recomiendo que use el método onMessageReceived (consulte Mensaje de datos) para extraer el paquete de datos. Desde su lógica, verifiqué el objeto del paquete y no he encontrado el contenido de datos esperado. Aquí hay una referencia a un caso similar que podría proporcionar más claridad.

Desde el lado del servidor, la notificación de Firebase debe seguir el siguiente formato :

El lado del servidor debe enviar el objeto "notificación" . La falta de objeto de "notificación" en mi TargetActivityno recibió el mensaje usando getIntent().

El formato de mensaje correcto se da a continuación:

{
 "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"
}

Aquí hay conceptos más claros sobre el mensaje de Firebase. Lo encontré de su equipo de soporte.

Para más información visite mi este hilo y este hilo


3
Vale la pena mencionar que no se recibirán "mensajes de datos" si el dispositivo está en modo de reposo profundo (introducido en Android 7.0). ten cuidado con esos!
Sameer J

30

Yo tuve el mismo problema. Es más fácil usar el 'mensaje de datos' en lugar de la 'notificación'. El mensaje de datos siempre carga la clase onMessageReceived.

En esa clase, puede hacer su propia notificación con el generador de notificaciones.

Ejemplo:

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

77
Gracias. Cambié mi código de servidor y uso "datos" en lugar de "notificación" y ahora funciona perfectamente.
Mahesh Kavathiya

55
@Koot funciona solo si la aplicación está en primer plano, no si está en segundo plano. ¿Me pueden ayudar a desencadenar este evento en ambos casos?
Anant Shah

@AnantShah, ¿cómo se ve tu POST en el servidor Firebase?
Koot

3
En realidad, hay tres casos posibles aquí. 1) Aplicación en primer plano. 2) Aplicación en segundo plano. 3) La aplicación no se está ejecutando. Como usted dice, se recibirá un mensaje de "datos" en los primeros dos casos, pero no en el tercer caso, cuando la aplicación no se esté ejecutando. Para atender los tres casos, debe configurar el campo 'notificación' en el mensaje. (También es una buena idea si desea admitir clientes iOS y Android)
Steve Moseley

1
Incluso en la aplicación no se está ejecutando, todavía recibo un mensaje del servidor sobre la función recibida en el mensaje. Estoy de acuerdo con usted en que es mejor usar 'notificación' si también desea admitir ios.
Koot

21

Según la documentación de Firebase Cloud Messaging: si la actividad está en primer plano, se llamará a onMessageReceived. Si la actividad está en segundo plano o cerrada, se muestra un mensaje de notificación en el centro de notificaciones para la actividad del iniciador de aplicaciones. Puede llamar a su actividad personalizada al hacer clic en la notificación si su aplicación está en segundo plano llamando a la API del servicio de descanso para mensajes de Firebase como:

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

Tipo de método: POST

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

Cuerpo / carga útil:

{ "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)"
} 

Y con esto en su aplicación, puede agregar el siguiente código en su actividad que se llamará:

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

¿Dónde crearía la intención y abriría una actividad específica? Sé que esto registra la intención OPEN_ACTIVITY_1 en el manifiesto, pero ¿dónde lo llamo realmente?
Cyogenos


¿Deberíamos llamar a una actividad desde filtros intencionales? ¿O iniciarlo manualmente onMessageReceived?
CoolMind

14

Método onMessageReceived (RemoteMessage remoteMessage) llamado en función de los siguientes casos.

  • Respuesta de FCM con notificación y bloqueo de datos :
{
  
"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. Aplicación en primer plano:

onMessageReceived (RemoteMessage remoteMessage) llamado, muestra LargeIcon y BigPicture en la barra de notificaciones. Podemos leer el contenido tanto de la notificación como del bloque de datos

  1. Aplicación en segundo plano:

onMessageReceived (RemoteMessage remoteMessage) no se llama, la bandeja del sistema recibirá el mensaje y leerá el cuerpo y el título del bloque de notificaciones y muestra el mensaje y el título predeterminados en la barra de notificaciones.

  • Respuesta FCM con solo bloque de datos :

En este caso, eliminar bloques de notificación de 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"
  }
}

Solución para llamar a onMessageReceived ()

  1. Aplicación en primer plano:

onMessageReceived (RemoteMessage remoteMessage) llamado, muestra LargeIcon y BigPicture en la barra de notificaciones. Podemos leer el contenido tanto de la notificación como del bloque de datos

  1. Aplicación en segundo plano:

onMessageReceived (RemoteMessage remoteMessage) llamado, la bandeja del sistema no recibirá el mensaje porque la clave de notificación no está en la respuesta. Muestra LargeIcon y BigPicture en la barra de notificaciones

Código

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


}

Link de referencia:

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


La parte más importante para las personas que sufren problemas de fondo es eliminar la propiedad de "notificación" de JSON que envía el servidor. Esto resuelve el problema. Muchas gracias.
Ramy M. Mousa

13

Tengo el mismo problema. Si la aplicación está en primer plano, activa mi servicio en segundo plano donde puedo actualizar mi base de datos según el tipo de notificación. Pero, la aplicación pasa a segundo plano: el servicio de notificación predeterminado se encargará de mostrar la notificación al usuario.

Aquí está mi solución para identificar la aplicación en segundo plano y activar su servicio en segundo plano,

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

En el manifiesto.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>

Probé esta solución en la última versión de Android 8.0. Gracias


¿Cuál es el uso de esta clase FirebaseBackgroundService? @Nagendra Badiganti

dónde usar este código clase pública FirebaseBackgroundService extiende WakefulBroadcastReceiver @Nagendra Badiganti

cree una clase de servicio en su paquete y regístrese en su manifest.xml. Asegúrese de tener el filtro para sus notificaciones. Dado que el servicio se dispara para cada notificación de GCM.
Nagendra Badiganti

firebase.google.com/docs/cloud-messaging/android/… Estoy siguiendo este enlace, necesito agregar esta clase para recibir la notificación. simplemente enviando un mensaje desde el primer mensaje de Firebase ... dice completado pero no recibe notificación @Nagendra Badiganti

1
WakefulBroadcastReceiverestá en desuso desde el nivel de API 26.1.0.
Minoru

12

Si la aplicación está en modo de fondo o inactiva (inactiva) y hace clic en Notificación , debe verificar la carga útil en LaunchScreen (en mi caso, la pantalla de inicio es MainActivity.java).

Entonces, en MainActivity.java en onCreate verifique Extras :

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

¿Cómo puedo obtener el título, el cuerpo y los datos de la notificación?
Md.Tarikul Islam

1
Gracias, esta es la respuesta. @ Md.Tarikul Islam usando onMessageReceived () como se menciona en esta pregunta.
felixwcf

7

Anular el handleIntentmétodo de las FirebaseMessageServiceobras para mí.

aquí el código en 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);
    }
}

y ese es el Código en 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);
    }
}

handleIntent () es final
Ettore

@Ettore ¿Cómo puedo invocar la función handleIntent?
Hiroto

Se llama al método cuando recibe el mensaje de Firebase, pero no puede anularlo porque el método se declara final. (Firebase 11.6.0)
Ettore

5

De forma predeterminada, la Actividad de inicio en su aplicación se iniciará cuando su aplicación esté en segundo plano y haga clic en la notificación; si tiene alguna parte de datos con su notificación, puede manejarla en la misma actividad de la siguiente manera,

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

Si navego desde mainActivity, ¿cómo funcionará volver a una Actividad en particular?
Mac_Play

@Uzair getIntent (). GetExtras () siempre se vuelve nulo, ¿tiene alguna otra solución? Cuando la aplicación se va a la base en el método de MensajeRecibido no llame
usuario2025187

3

Si la aplicación está en segundo plano Fire-base por notificación de manejo predeterminada Pero si queremos recibir nuestra notificación personalizada, entonces tenemos que cambiar nuestro lado del servidor, que es responsable de enviar nuestros datos personalizados (carga de datos)

Elimine la carga de notificación por completo de su solicitud de servidor. Enviar solo datos y manejarlos en onMessageReceived () de lo contrario, su onMessageReceived no se activará cuando la aplicación esté en segundo plano o se cierre.

ahora, el formato del código del lado del servidor se ve así,

{
  "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
  }
}

NOTA : vea esta línea en el código
"texto" anterior: "John Doe compartió un contacto en el grupo Intercambio de contactos" en Carga de datos, debe usar el parámetro "texto" en lugar de los parámetros "cuerpo" o "mensaje" para la descripción del mensaje o lo que sea quiero usar texto.

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

2

Simplemente llame a esto en el método onCreate de su MainActivity:

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

Si navego desde mainActivity, ¿cómo funcionará volver a una Actividad en particular?
Mac_Play

2

De acuerdo con la solución de t3h Exi, me gustaría publicar el código limpio aquí. Simplemente colóquelo en MyFirebaseMessagingService y todo funcionará bien si la aplicación está en modo de fondo. Necesita al menos compilar 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);
    }
}

Estoy tratando de implementar la solución, pero el método handleIntent () es definitivo en mi versión SDK (SDK 27), así que no puedo anularlo en mi servicio ...
matdev

Sí, pero no es mi culpa ni ninguna razón para dar -1. Muy arrogante. Funciona hasta Firebase 11.4.2 y luego Google lo cambió (hizo que este método fuera definitivo). Entonces ahora debe programar su propia solución con notificación.
Frank

¡No le di un -1 sino un +1!
matdev

Usted salvó mi trabajo: P
amitabha2715

2

Prueba esto:

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

handleIntent ya no se usa en firebase: 11.8.0 y superior.
Shihab Uddin

1

Tuve este problema (la aplicación no quiere abrir al hacer clic en la notificación si la aplicación está en segundo plano o cerrada), y el problema no era válido click_actionen el cuerpo de la notificación, intente eliminarlo o cambiarlo a algo válido.


1

El punto que merece destacarse es que debe usar el mensaje de datos, solo la clave de datos , para obtener una llamada al manejador de mensajes recibidos incluso cuando la aplicación está en segundo plano. No debería tener ninguna otra clave de mensaje de notificación en su carga útil, de lo contrario, el controlador no se activará si la aplicación está en segundo plano.

Aquí se menciona (pero no se enfatiza tanto en la documentación de FCM):

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

Use su servidor de aplicaciones y la API del servidor FCM: configure solo la clave de datos . Puede ser plegable o no plegable.


1

El backend con el que estoy trabajando está usando mensajes de notificación y no mensajes de datos. Entonces, después de leer todas las respuestas, traté de recuperar los extras del paquete de la intención que viene con la actividad lanzada. Pero no importa de qué claves traté de recuperar getIntent().getExtras();, el valor siempre fue nulo.

Sin embargo, finalmente encontré una manera de enviar datos usando mensajes de notificación y recuperarlos de la intención.

La clave aquí es agregar el carga útil de datos al mensaje de notificación.

Ejemplo:

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

Después de hacer esto, podrá obtener su información de esta manera:

intent.getExtras().getString("title") estarán message_title

y intent.getExtras().getString("message") serámessage_body

Referencia


1

Si su problema está relacionado con mostrar Big Image, es decir, si está enviando notificaciones push con una imagen desde la consola de Firebase y muestra la imagen solo si la aplicación está en primer plano. La solución para este problema es enviar un mensaje push con solo un campo de datos. Algo como esto:

{ "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" }

Perdiste una coma antes de "AnotherActivity". Mi Android vibra pero realmente no se muestra nada (sin texto, sin imagen, sin inserción).
jekaby

1

Cuando se recibe un mensaje y su aplicación está en segundo plano, la notificación se envía a la intención adicional de la actividad principal.

Puede verificar el valor adicional en la función oncreate () u onresume () de la actividad principal.

Puede verificar los campos como datos, tabla, etc. (el especificado en la notificación)

por ejemplo envié usando datos como clave

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

}

0

Estaba teniendo el mismo problema e investigé un poco más sobre esto. Cuando la aplicación está en segundo plano, se envía un mensaje de notificación a la bandeja del sistema, PERO se envía un mensaje de datos a onMessageReceived()
Ver https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3
y https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java

Para asegurarse de que el mensaje que está enviando, los documentos dicen: " Use su servidor de aplicaciones y la API del servidor FCM: configure solo la clave de datos. Puede ser plegable o no plegable " .
Consulte https://firebase.google.com/ docs / cloud-messaging / concept-options # notificaciones_y_mensajes_datos


0

Hay dos tipos de mensajes: mensajes de notificación y mensajes de datos. Si solo envía un mensaje de datos, es decir, sin objeto de notificación en su cadena de mensaje. Se invocará cuando su aplicación esté en segundo plano.


0

Comprueba la respuesta de @Mahesh Kavathiya. Para mi caso, en el código del servidor solo tiene este:

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

Necesita cambiar a:

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

Luego, en caso de que la aplicación en segundo plano, la intención de actividad predeterminada adicional obtenga "datos"

¡Buena suerte!


-1

Simplemente anule el método OnCreate de FirebaseMessagingService. Se llama cuando su aplicación está en segundo plano:

public override void OnCreate()
{
    // your code
    base.OnCreate();
}

Esta respuesta podría ser más útil si pudiera agregar una explicación y vincularla a alguna documentación. ¿Puede decirnos cómo se supone que esto ayudará?
kilokahn

@kilokahn ¿Puedes explicarme lo que no entiendes? el método indicado debe insertarse en el código que forma parte de la pregunta y responde completamente la pregunta. El código es para Xamarin, pero simplemente puede convertir en Java.
Renzo Ciot

AFAIK La documentación oficial ( firebase.google.com/docs/cloud-messaging/android/client ) no habla de anular OnCreate en un servicio que extiende FirebaseMessagingService; si tiene acceso a la documentación que sí lo tiene, ¿tal vez pueda compartir un enlace? Además, según su respuesta, no está claro cómo anular onCreate resuelve el problema de que no se llame a onMessageReceived cuando se hace clic en la notificación, de ahí la solicitud de más información.
kilokahn

La documentación no menciona la anulación del método OnCreate, pero funciona porque lo estoy usando en producción. El código que desea insertar en el método onMessageReceived y que obviamente sirve para realizar algunas operaciones en segundo plano se puede realizar en OnCreate.
Renzo Ciot

En ese caso, desarrollar el hecho de que de alguna manera funcionó para usted puede ser más útil que simplemente enumerar la solución. Además, es probable que el comportamiento indocumentado deje de funcionar arbitrariamente con las actualizaciones, y alguien que las use debe estar preparado para modificar su código cuando lo haga. Este descargo de responsabilidad debe ser introducido.
kilokahn

-1

Hay 2 tipos de notificaciones push de Firebase :

1- Mensaje de notificación (Mostrar mensaje) -> - 1.1 Si elige esta variante, el sistema operativo creará una notificación si la aplicación está en segundo plano y pasará los datos en el intent. Entonces depende del cliente manejar estos datos.

- 1.2 Si la aplicación está en primer plano, entonces la notificación se recibirá a través callback-functionde FirebaseMessagingServicey depende del cliente manejarla.

2- Mensajes de datos (hasta 4k datos) -> Estos mensajes se utilizan para enviar solo datos al cliente (en silencio) y depende del cliente manejarlos en ambos casos en segundo plano / fondo a través de la función de devolución de llamada en FirebaseMessagingService

Esto está de acuerdo con los documentos oficiales: https://firebase.google.com/docs/cloud-messaging/concept-options

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.