Firebase onMessageReceived pas appelé quand app en arrière-plan

je travaille avec Firebase et teste en envoyant des notifications à mon application depuis mon serveur alors que l'application est à l'arrière-plan. La notification est envoyée avec succès, elle apparaît même sur le centre de notification de l'appareil, mais lorsque la notification apparaît ou même si je clique sur elle, la méthode onMessageReceived à l'intérieur de mon FCMessagingService n'est jamais appelée.

lorsque j'ai testé ceci alors que mon application était au premier plan, la méthode onmessagereception a été appelée et tout a bien fonctionné. Le problème se produit lorsque l'application tourne en arrière-plan.

ce comportement est-il prévu, ou y a-t-il un moyen de le corriger?

Voici mon service Fbmessaging:

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"));
        }
    }
}
146
demandé sur Frank van Puffelen 2016-05-21 06:06:27

23 réponses

cela fonctionne comme prévu, les messages de notification sont livrés à votre onmessagereceived callback que lorsque votre application est à l'avant-plan. Si votre application est en arrière-plan ou fermée, alors un message de notification est affiché dans le centre de notification, et toutes les données de ce message est passé à l'intention qui est lancé à la suite de l'utilisateur tapant sur la notification.

Vous pouvez spécifier une click_action pour indiquer l'intention cela devrait être lancé lorsque la notification est captée par l'utilisateur. L'activité principale est utilisée si aucun click_action est spécifié.

lorsque l'intention est lancée, vous pouvez utiliser le

getIntent().getExtras();

pour récupérer un Ensemble qui comprendrait toutes les données envoyées avec le message de notification.

pour plus de détails sur le message de notification, voir docs .

88
répondu Arthur Thompson 2016-11-23 14:24:26

SOLUTION DÉPRÉCIÉE:

j'ai une solution parfaite pour cela:

vous devez effectuer 2 étapes simples:

  1. Mise à niveau de votre firebase à la version de la compilation com.google.firebase:firebase-messaging:10.2.1
  2. Remplacer handleIntent(Intent intent) méthode dans votre FirebaseMessagingService de la classe.

handleIntent() méthode est appelé chaque fois si app est en premier plan, en arrière plan ou tué état.

59
répondu manas.abrol 2018-10-03 08:02:15

Supprimer notification champ complètement de votre demande de serveur. Envoyer seulement data et le manipuler dans onMessageReceived() sinon votre onMessageReceived() ne sera pas déclenché quand app est en arrière-plan ou tué.

n'oubliez pas d'inclure le champ "priority": "high" dans votre demande de notification. Selon la documentation: les messages de données sont envoyés avec une priorité normale, donc ils n'arriveront pas instantanément; il pourrait également être le problème.

voici ce que j'envoie du serveur

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

pour que vous puissiez recevoir vos données dans onMessageReceived(RemoteMessage message) comme ceci....disons que je dois obtenir une carte d'identité

Object obj = message.getData().get("id");
        if (obj != null) {
            int id = Integer.valueOf(obj.toString());
        }
50
répondu Zohab Ali 2018-05-28 12:43:21

j'ai eu le même problème. Il est plus facile d'utiliser le "message de données" au lieu de la "notification". Le message de données charge toujours la classe onMessageReceived.

dans cette catégorie, vous pouvez faire votre propre déclaration avec le constructeur de notification.

exemple:

 @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());
    }
24
répondu Koot 2016-05-26 21:29:20

Voici des concepts plus clairs sur le message firebase. Je l'ai trouvé dans leur équipe de soutien.

Firebase a trois types de message :

messages de Notification : le message de Notification fonctionne sur l'arrière-plan ou les connaissances nouvelles. Quand app est en arrière-plan, les messages de Notification sont livrés au plateau du système. Si l'application est au premier plan, les messages sont traités par onMessageReceived() ou didReceiveRemoteNotification rappel. Il s'agit essentiellement de ce qu'on appelle des messages D'affichage.

messages de données : sur la plate-forme Android, les messages de données peuvent fonctionner sur l'arrière-plan et l'avant-plan. Le message de données sera traité par onMessageReceived(). Une note spécifique à la plate-forme ici serait: sur Android, la charge utile de données peut être récupérée dans l'intention utilisée pour lancer votre activité. Pour élaborer, si vous avez "click_action":"launch_Activity_1" , vous pouvez récupérer cette intention par getIntent() de seulement Activity_1 .

Messages avec à la fois notification et charges utiles de données : en arrière-plan, les applications reçoivent la charge utile de notification dans le bac de notification, et ne traitent la charge utile de données que lorsque l'utilisateur tape sur la notification. Au premier plan, votre application reçoit un objet message avec les deux charges utiles disponibles. Deuxièmement, le paramètre click_action est souvent utilisé dans la charge de notification et non dans la charge de données. Si utilisé dans les données charge utile, ce paramètre serait traité comme une paire de valeurs clé personnalisée et donc vous auriez besoin d'implémenter une logique personnalisée pour qu'elle fonctionne comme prévu.

en outre, je vous recommande d'utiliser la méthode onMessageReceived (voir message de données) pour extraire le faisceau de données. D'après votre logique, j'ai vérifié l'objet bundle et je n'ai pas trouvé le contenu des données attendues. Voici une référence à un cas similaire qui pourrait apporter plus de clarté.

pour plus d'informations visitez mon ce fil

20
répondu Md. Sajedul Karim 2017-05-23 12:34:37

selon la documentation de messagerie Cloud de Firebase-si L'activité est au premier plan, alors onMessageReceived sera appelé. Si L'activité est en arrière-plan ou fermée, alors le message de notification est affiché dans le centre de notification pour l'activité de lanceur d'applications. Vous pouvez appeler votre activité personnalisée en cliquant sur notification si votre application est en arrière-plan en appelant l'api rest service pour la messagerie firebase comme:

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

Type de méthode-POST

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

Corps / Charge Utile:

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

Et c'est dans votre application, vous pouvez ajouter le code ci-dessous dans votre activité d'être appelé:

<intent-filter>
                <action android:name="OPEN_ACTIVITY_1" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
17
répondu Ankit Adlakha 2016-06-02 18:01:40

si app est en mode arrière-plan ou inactif(tué), et vous cliquez sur sur Notification , vous devez vérifier la charge utile dans LaunchScreen(dans mon cas, l'écran de lancement est MainActivity.Java.)

MainActivity.java sur onCreate vérifier Extras :

    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("MainActivity: ", "Key: " + key + " Value: " + value);
        }
    }
11
répondu Gent Berani 2017-01-19 10:03:57

remplace la méthode handleIntent de la méthode FirebaseMessageService fonctionne pour moi.

ici le code dans 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);
    }
}

et c'est le Code dans 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);
    }
}
8
répondu t3h Exi 2017-11-29 15:58:01

j'ai eu le même problème. Si l'application est de premier plan - il déclenche mon service de fond où je peux mettre à jour ma base de données basée sur le type de notification. Mais, l'application va à l'arrière-plan - le service de notification par défaut sera pris soin de montrer la notification à l'utilisateur.

voici ma solution pour identifier l'application en arrière-plan et déclencher votre service d'arrière-plan,

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

dans le manifeste.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>

testé cette solution dans la dernière version android 8.0. Merci

6
répondu Nagendra Badiganti 2017-11-20 12:35:56

par défaut le activité de lanceur dans votre application sera lancé lorsque votre application est en arrière-plan et vous cliquez sur la notification, si vous avez une partie de données avec votre notification, vous pouvez la gérer dans la même activité comme suit,

if(getIntent().getExtras()! = null){
  //do your stuff
}else{
  //do that you normally do
}
5
répondu Uzair 2016-06-18 05:34:04

j'ai implémenté cette façon facile d'envoyer des messages même si l'application est fermée, en arrière-plan et en avant-plan aussi. J'utilisais auparavant la console firebase mais je ne reçois que des messages, pas des images et des données personnalisées.

pour envoyer ces données personnalisées avec image, vous pouvez utiliser un outil appelé AdvancedREST Client , c'est une extension chrome, et envoyer un message avec les paramètres suivants:

Rest client tool Link: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

utilisez cette url:- https://fcm.googleapis.com/fcm/send Content-Type:application/json Authorization:key=Your Server key From or Authorization key (voir ci-dessous ref)

{ "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" 
}
Vous pouvez obtenir la clé D'autorisation

en visitant Google developers console et en cliquant sur le bouton" informations D'identification " dans le menu de gauche de votre projet. Parmi les clés API listées, la clé du serveur sera votre clé d'autorisation.

et vous devez mettre tokenID du récepteur dans la section to de votre requête POST envoyée en utilisant L'API.

et ce morceau de code android //message contiendra le message Push

String message = remoteMessage.getData().get("message1");

//imageUri will contain URL of the image to be displayed with Notification
String imageUri = remoteMessage.getData().get("image");

//If the key AnotherActivity has  value as True then when the user taps on notification, in the app AnotherActivity will be opened.
//If the key AnotherActivity has  value as False then when the user taps on notification, in the app MainActivity2 will be opened.
String TrueOrFlase = remoteMessage.getData().get("AnotherActivity");

//To get a Bitmap image from the URL received
bitmap = getBitmapfromUrl(imageUri);

sendNotification(message, bitmap, TrueOrFlase);
5
répondu Syed Danish Haider 2016-11-24 14:36:19

appelez cela dans la méthode onCreate de votre activité principale:

if (getIntent().getExtras() != null) {
           // Call your NotificationActivity here..
            Intent intent = new Intent(MainActivity.this, NotificationActivity.class);
            startActivity(intent);
        }
2
répondu Shekhar 2016-12-07 06:59:14

d'après la solution de t3h Exi, je voudrais afficher le code propre ici. Il suffit de le mettre dans MyFirebaseMessagingService et tout fonctionne bien si l'application est en mode background. Vous devez au moins compiler com.Google.firebase: firebase-messagerie: 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);
    }
}
2
répondu Frank 2017-10-26 12:58:50

si app est en arrière-plan Fire-base par défaut traitement de notification mais si nous voulons à notre notification personnalisée que nous devons changer notre côté serveur, qui est responsable d'envoyer nos données personnalisées (charge de données)

supprimez complètement la charge utile de notification de votre requête serveur. Envoyez seulement des données et manipulez-les dans onMessageReceived() sinon votre onmessagereceived ne sera pas déclenché quand app est en arrière-plan ou tué.

maintenant,votre format de code côté serveur ressemblant à,

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

NOTE : voir cette ligne dans le code ci-dessus

"texte": "John Doe a partagé un contact dans L'échange de Contact de groupe" dans la charge utile de données, vous devez utiliser le paramètre " text "au lieu des paramètres" body "ou" message " pour la description du message ou tout ce que vous voulez utiliser le texte.

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
répondu Hiren 2017-12-07 09:51:45

essayez ceci:

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);
    }
}
2
répondu user3587828 2018-03-21 05:46:37

j'ai eu ce problème(app ne veut pas s'ouvrir sur le clic de notification si app est en arrière-plan ou fermé), et le problème était un click_action invalide dans le corps de notification, essayer de le supprimer ou de le changer à quelque chose de VALIDE.

1
répondu Octavian Lari 2016-05-23 14:11:18

j'avais le même problème et j'ai creusé un peu plus là-dessus. Lorsque l'application est à l'arrière-plan, un message de notification est envoyé au plateau du système, mais un message de données est envoyé à onMessageReceived()

Voir https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3

et https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java

pour s'assurer que le message que vous envoyez, les docs disent, " utilisez votre API de serveur app et de serveur FCM: définissez la clé de données seulement. Peut être pliable ou non-réductible.

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

1
répondu Eric B. 2016-07-19 19:47:21

le point qui mérite d'être souligné est que vous devez utiliser le message de données - clé de données seulement - pour obtenir onMessageReceived handler appelé même lorsque l'application est en arrière-plan. Vous ne devriez pas avoir d'autre clé de message de notification dans votre charge utile, sinon le gestionnaire ne sera pas déclenché si l'application est en arrière-plan.

il est mentionné (mais non souligné dans la documentation de la FCM) ici:

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

utilisez L'API de votre serveur app et de votre serveur FCM: définissez la clé de données seulement . Peut être soit pliable, soit non pliable.

1
répondu n_y 2016-09-18 11:24:25

le backend avec lequel je travaille utilise les messages de Notification et non les messages de données. Donc après avoir lu toutes les réponses j'ai essayé de récupérer les extras du paquet de l'intention qui vient à l'activité lancée. Mais peu importe les clés que j'ai essayé de récupérer à partir de getIntent().getExtras(); , la valeur était toujours nulle.

cependant, j'ai finalement trouvé un moyen d'envoyer des données en utilisant messages de Notification et de le récupérer à partir de la intention.

la clé ici est d'ajouter le data payload au message de Notification.

exemple:

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

après avoir fait cela, vous pourrez obtenir vos informations de cette façon:

intent.getExtras().getString("title") sera message_title

et intent.getExtras().getString("message") sera message_body

référence

1
répondu Vito Valov 2016-11-24 22:27:04

si votre problème est lié à l'affichage D'une grande Image, c'est-à-dire si vous envoyez une notification push avec une image de la console firebase et qu'elle n'affiche l'image que si l'application se trouve au premier plan. La solution pour ce problème est d'envoyer un message push avec seulement le champ de données. Quelque chose comme ceci:

{ "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" }
1
répondu Arun 2017-02-28 16:38:07

il existe deux types de messages: les messages de notification et les messages de données. Si vous n'envoyez que des messages de données, c'est-à-dire sans objet de notification dans votre chaîne de messages. Il serait invoquée lorsque votre application en arrière-plan.

0
répondu Shongsu 2016-08-17 15:18:27

lorsque le message est reçu et que votre application est en arrière-plan, la notification est envoyée à l'intention extras de l'activité principale.

Vous pouvez vérifier la valeur supplémentaire dans le oncreate() ou onresume (), fonction de l'activité principale.

vous pouvez vérifier les champs comme data, table etc (celui spécifié dans la notification)

par exemple, j'ai envoyé en utilisant des données comme la clé

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
répondu Sanjeev S 2018-06-28 09:23:39

remplace juste la méthode OnCreate de FirebaseMessagingService. Il est appelé lorsque votre application est en arrière-plan:

public override void OnCreate()
{
    // your code
    base.OnCreate();
}
-2
répondu Renzo Ciot 2018-06-01 14:55:29