Firebase (FCM): abre la actividad y pasa datos al hacer clic en notificación. android

Debería haber una implementación clara de cómo trabajar con las notificaciones y los datos de Firebase. Leo muchas respuestas pero parece que no puedo hacer que funcione. aquí están mis pasos:

1.) Estoy pasando notificaciones y datos a Android en PHP y parece estar bien:

$msg = array ( "body" => $body, "title" => $title, "sound" => "mySound" ); $data = array ( "user_id" => $res_id, "date" => $date, "hal_id" => $hal_id, "M_view" => $M_view ); $fields = array ( 'registration_ids' => $registrationIds, 'notification' => $msg, 'data' => $data ); $headers = array ( 'Authorization: key='.API_ACCESS_KEY, 'Content-Type: application/json' ); $ch = curl_init(); curl_setopt( $ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/send' ); curl_setopt( $ch,CURLOPT_POST, true ); curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers ); curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true ); curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false ); curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) ); $result = curl_exec($ch ); curl_close( $ch ); 

2.) cuando la notificación y los datos se reciben en Android, muestran una notificación. Cuando hago clic en esta notificación, se abre la aplicación. Pero no puedo encontrar la manera de manejar los datos cuando se abre la aplicación. Hay algunas diferencias cuando la aplicación está en primer plano y en segundo plano. El código que tengo ahora es el siguiente:

 public class MyFirebaseMessagingService extends FirebaseMessagingService { private static final String TAG = "MyFirebaseMsgService"; @Override public void onMessageReceived(RemoteMessage remoteMessage) { String user_id = "0"; String date = "0"; String cal_id = "0"; String M_view = "0"; if (remoteMessage.getData().size() > 0) { Log.d(TAG, "Message data payload: " + remoteMessage.getData()); user_id = remoteMessage.getData().get("user_id"); date = remoteMessage.getData().get("date"); hal_id = remoteMessage.getData().get("hal_id"); M_view = remoteMessage.getData().get("M_view"); } //Calling method to generate notification sendNotification(remoteMessage.getNotification().getBody(), user_id, date, hal_id, M_view); } private void sendNotification(String messageBody, String user_id, String date, String hal_id, String M_view) { Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtra("fcm_notification", "Y"); intent.putExtra("user_id", user_id); intent.putExtra("date", date); intent.putExtra("hal_id", hal_id); intent.putExtra("M_view", M_view); int uniqueInt = (int) (System.currentTimeMillis() & 0xff); PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), uniqueInt, intent, PendingIntent.FLAG_UPDATE_CURRENT); Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this); notificationBuilder.setSmallIcon(R.drawable.ic_launcher) .setContentText(messageBody) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(0, notificationBuilder.build()); }} 

3.) Cuando uso el código de arriba y cuando hago clic en Notificación, todo lo que hace abre la aplicación si está en segundo plano. Si la aplicación está en primer plano y luego en la notificación, haga clic en simplemente descarta la notificación. Sin embargo, deseo recibir datos y abrir una Actividad específica en ambos escenarios (fondo y primer plano). Tengo en MainActivity el siguiente código, pero no puedo obtener datos. fcm_notification, date, hal_id devuelve null.

 public class MainActivity extends Activity { UserFunctions userFunctions; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); setIntent(intent); Intent intent_o = getIntent(); } @Override protected void onResume() { super.onResume(); userFunctions = new UserFunctions(); if(userFunctions.isUserLoggedIn(getApplicationContext())){ Intent intent_o = getIntent(); String fcm_notification = intent_o.getStringExtra("fcm_notification") ; String user_id = intent_o.getStringExtra("user_id"); String date = intent_o.getStringExtra("date"); String hal_id = intent_o.getStringExtra("hal_id"); String M_view = intent_o.getStringExtra("M_view"); Intent intent = new Intent(this, JobList.class); // THIS RETURNS NULL, user_id = null System.out.print("FCM" + user_id); startActivity(intent); finish(); }else{ // user is not logged in show login screen Intent login = new Intent(this, LoginActivity.class); startActivity(login); // Closing dashboard screen finish(); } }} 

SI alguien puede dirigir o aconsejar cómo puedo recuperar datos en MainActivity.java de Firebase en cualquier escenario (en primer plano o en segundo plano) eso sería fantástico.

Entonces, primero, voy a poner los detalles mencionados en los documentos de Manejo de mensajes .

En el resumen en la fila Ambos , muestra que cuando la aplicación está en primer plano , la carga se manejará en su onMessageReceived() .

Para abrir la actividad de onMessageReceived() , debe verificar si los datos que necesita están en la carga, si lo hace, llame a su actividad específica y luego pase todos los demás detalles que necesita a través de la intención.

Ahora, si la aplicación está en segundo plano , se menciona en los documentos que la bandeja del sistema de Android recibe la notificación y que la carga de data se puede recuperar de los extras de la intención.

Solo agregué los detalles de mi respuesta aquí, que prácticamente da la statement de documentos y un enlace a una muestra:

Manejar mensajes de notificación en una aplicación de fondo

Cuando su aplicación está en segundo plano, Android dirige los mensajes de notificación a la bandeja del sistema. Un usuario toca la notificación abre el iniciador de aplicaciones de forma predeterminada.

Esto incluye mensajes que contienen tanto la carga de datos como la notificación (y todos los mensajes enviados desde la consola de Notificaciones). En estos casos, la notificación se entrega a la bandeja del sistema del dispositivo, y la carga útil de datos se entrega en los extras de la actividad de su iniciador.

Creo que esta respuesta de @ArthurThompson lo explica muy bien:

Cuando envía un mensaje de notificación con una carga de datos (notificación y datos) y la aplicación está en segundo plano, puede recuperar los datos de los extras de la intención que se inicia como resultado de que el usuario toque la notificación.

De la muestra de FCM que inicia la actividad principal cuando se toca la notificación:

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

Después de probar todas las respuestas y los blogs encontraron una solución. si alguien necesita, por favor use este video como referencia

https://www.youtube.com/watch?v=hi8IPLNq59o

ADEMÁS del video para agregar intenciones en MyFirebaseMessagingService:

 public class MyFirebaseMessagingService extends FirebaseMessagingService { private static final String TAG = "MyFirebaseMsgService"; @Override public void onMessageReceived(RemoteMessage remoteMessage) { String user_id = "0"; String date = "0"; String hal_id = "0"; String M_view = "0"; if (remoteMessage.getData().size() > 0) { Log.d(TAG, "Message data payload: " + remoteMessage.getData()); user_id = remoteMessage.getData().get("user_id"); date = remoteMessage.getData().get("date"); cal_id = remoteMessage.getData().get("hal_id"); M_view = remoteMessage.getData().get("M_view"); } String click_action = remoteMessage.getNotification().getClickAction(); //Calling method to generate notification sendNotification(remoteMessage.getNotification().getBody(), remoteMessage.getNotification().getTitle(), user_id, date, hal_id, M_view, click_action); } private void sendNotification(String messageBody, String messageTitle, String user_id, String date, String hal_id, String M_view, String click_action) { Intent intent = new Intent(click_action); intent.putExtra("user_id", user_id); intent.putExtra("date", date); intent.putExtra("hal_id", hal_id); intent.putExtra("M_view", M_view); PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT); Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this); notificationBuilder.setSmallIcon(R.drawable.ic_launcher) .setContentTitle(messageTitle) .setContentText(messageBody) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.notify(0, notificationBuilder.build()); }} 

y en la nueva actividad NotificationReceive en onCreate o onResume agrega esto

  notification_Y_N = (TextView) findViewById(R.id.notification_Y_N); user_id_text = (TextView) findViewById(R.id.user_id_text); Intent intent_o = getIntent(); String user_id = intent_o.getStringExtra("user_id"); String date = intent_o.getStringExtra("date"); String hal_id = intent_o.getStringExtra("hal_id"); String M_view = intent_o.getStringExtra("M_view"); notification_Y_N.setText(date); user_id_text.setText(hal_id); 

Para invocar el método onMessageReceived() , deberá usar otro método para enviar notificaciones (como crear una API web para enviar notificaciones). Luego usándolo,

elimine la carga de notificación de sus mensajes de FCM para que la carga de datos se entregue al método onMessageReceived() .

Cuando su aplicación está en segundo plano, la carga útil de datos se entrega al método onMessageReceived solo si no hay una carga de notificación.

En caso de que existan ambas cargas, el sistema maneja automáticamente la parte de notificación (bandeja del sistema) y su aplicación recibe la carga de datos en los extras de la actividad del iniciador (después de que el usuario toque la notificación).

Para obtener más información, consulte los siguientes enlaces:

  • ¿Por qué está pasando esto? ¿Cómo? ¿Cómo manejar las notificaciones push?
  • Respuesta original por kws. Dale un voto positivo.

No necesita implementar sendNotification y onMessageReceived usted mismo.

Al enviar:

 $data = array ( "user_id" => $res_id //whatever fields you want to include ); $msg = array ( "body" => $body, "title" => $title, "data" => $data // more fields ); 

lado de Android (en su MainACtivity :

 private void handleIntent(Intent intent) { String user_id= intent.getStringExtra("user_id"); if(user_id!= null) Log.d(TAG, user_id); } 

y por supuesto:

 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handleIntent(intent); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); handleIntent(getIntent()); } 

cualquier campo que coloque en los data será enviado a su intención extra .