71 votes

Notifications FCM Firebase click_action payload

J'essaie d'ouvrir une activité particulière lorsque l'utilisateur clique sur la notification alors que l'application est en arrière-plan. Dans les documents, j'ai compris que click_action doit être ajouté dans la charge utile et un filtre d'intention dans l'application pour le gérer. Mais, comment ajouter click_action dans les Notifications Firebase via la Console Firebase ? Je suis ouvert à toute autre solution. Merci à l'avance.

75voto

Bozic Nebojsa Points 1937

Si votre application est en arrière-plan, Firebase ne déclenchera pas onMessageReceived(). Pourquoi..... ? Je n'en ai aucune idée. Dans cette situation, je ne vois pas l'intérêt d'implémenter FirebaseMessagingService.

Selon la documentation, si vous voulez traiter l'arrivée d'un message en arrière-plan, vous devez envoyer 'click_action' avec votre message. Mais ce n'est pas possible si vous envoyez le message à partir de la console Firebase, seulement via l'API Firebase. Cela signifie que vous devrez construire votre propre "console" afin de permettre aux personnes chargées du marketing de l'utiliser. Cela rend donc la console Firebase tout à fait inutile !

Il y a une très bonne idée, prometteuse, derrière ce nouvel outil, mais elle est mal exécutée.

Je suppose que nous devrons attendre les nouvelles versions et les améliorations/réparations !

2 votes

J'espère que la notification de Firebase obtiendra bientôt la fonctionnalité Payload, sinon il ne sert à rien de passer à la console Firebase comme vous l'avez dit.

0 votes

Mis en œuvre en utilisant quelque chose comme la méthode @diidu. Merci à tous pour les réponses.

1 votes

Comment pouvons-nous gérer cette charge utile dans le cas d'un push provenant du serveur ?

68voto

maddesa Points 121

Pour autant que je sache, il n'est pas possible à ce stade de définir l'action du clic dans la console.

Bien qu'il ne s'agisse pas d'une réponse stricte à la question de savoir comment obtenir le paramètre click_action dans la console, vous pouvez utiliser curl comme alternative :

curl --header "Authorization: key=<YOUR_KEY_GOES_HERE>" --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send  -d "{\"to\":\"/topics/news\",\"notification\": {\"title\": \"Click Action Message\",\"text\": \"Sample message\",\"click_action\":\"OPEN_ACTIVITY_1\"}}"

Il s'agit d'un moyen simple de tester le mappage click_action. Elle nécessite un filtre d'intention comme celui spécifié dans la documentation du FCM :

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

Cette méthode utilise également les thèmes pour définir l'audience. Pour que cela fonctionne, vous devez vous abonner à un sujet appelé "actualités".

FirebaseMessaging.getInstance().subscribeToTopic("news");

Même s'il faut plusieurs heures pour voir un sujet nouvellement créé dans la console, vous pouvez toujours lui envoyer des messages par le biais des apis FCM.

N'oubliez pas non plus que cela ne fonctionne que si l'application est en arrière-plan. Si elle est au premier plan, vous devrez implémenter une extension de FirebaseMessagingService. Dans la méthode onMessageReceived, vous devrez naviguer manuellement vers votre cible click_action :

    @Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    //This will give you the topic string from curl request (/topics/news)
    Log.d(TAG, "From: " + remoteMessage.getFrom());
    //This will give you the Text property in the curl request(Sample Message): 
    Log.d(TAG, "Notification Message Body: " + remoteMessage.getNotification().getBody());
    //This is where you get your click_action 
    Log.d(TAG, "Notification Click Action: " + remoteMessage.getNotification().getClickAction());
    //put code here to navigate based on click_action
}

Comme je l'ai dit, pour l'instant, je ne trouve pas de moyen d'accéder aux propriétés des charges utiles de notification via la console, mais j'ai pensé que cette solution pourrait être utile.

0 votes

Actuellement, il n'est pas possible de définir les propriétés des charges utiles de notification par le biais de la console. Si cela est important pour vous, veuillez écrire au support Firebase : firebase.google.com/support/contact/bugs-features

0 votes

@Diego Giorgini A déposé une demande de fonctionnalité auprès de Firebase. Merci pour le lien.

2 votes

OPEN_ACTIVITY_1 - est-il possible d'avoir un joker. Par exemple, tous les messages commençant par "my_firebase_event_" seraient admissibles à l'intention de mon lanceur.

38voto

Maxime Ancelin Points 436

Vous pouvez gérer toutes vos actions en fonction de votre message dans onMessageReceived() dans votre service étendant FirebaseMessagingService. Pour ce faire, vous devez envoyer un message contenant exclusivement des données, en utilisant par exemple Client REST avancé dans Chrome . Ensuite, vous envoyez un POST à https://fcm.googleapis.com/fcm/send en utilisant dans "Raw headers" :

Content-Type : application/json Autorisation : key=YOUR_PERSONAL_FIREBASE_WEB_API_KEY

Et un message json dans le champ "Raw payload".

Attention, s'il y a le champ "notification" dans votre json, votre message ne sera jamais reçu lorsque l'application en arrière plan dans onMessageReceived(), même s'il y a un champ de données ! Par exemple, en faisant cela, le message ne fonctionne que si l'application est au premier plan :

{
    "condition": " 'Symulti' in topics || 'SymultiLite' in topics",
    "priority" : "normal",
    "time_to_live" : 0,
    "notification" : {
        "body" : "new Symulti update !",
        "title" : "new Symulti update !",
        "icon" : "ic_notif_symulti"
    },
    "data" : {
        "id" : 1,
        "text" : "new Symulti update !"
    }
}

Afin de recevoir votre message dans tous les cas dans onMessageReceived(), il suffit de supprimer le champ "notification" de votre json !

Exemple :

{
    "condition": " 'Symulti' in topics || 'SymultiLite' in topics",
    "priority" : "normal",
    "time_to_live" : 0,,
    "data" : {
        "id" : 1,
        "text" : "new Symulti update !",
        "link" : "href://www.symulti.com"
    }
}

et dans votre FirebaseMessagingService :

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
      String message = "";
      obj = remoteMessage.getData().get("text");
      if (obj != null) {
        try {
          message = obj.toString();
        } catch (Exception e) {
          message = "";
          e.printStackTrace();
        }
      }

      String link = "";
      obj = remoteMessage.getData().get("link");
      if (obj != null) {
        try {
          link = (String) obj;
        } catch (Exception e) {
          link = "";
          e.printStackTrace();
        }
      }

      Intent intent;
      PendingIntent pendingIntent;
      if (link.equals("")) { // Simply run your activity
        intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
      } else { // open a link
        String url = "";
        if (!link.equals("")) {
          intent = new Intent(Intent.ACTION_VIEW);
          intent.setData(Uri.parse(link));
          intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        }
      }
      pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
          PendingIntent.FLAG_ONE_SHOT);

      NotificationCompat.Builder notificationBuilder = null;

      try {
        notificationBuilder = new NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.ic_notif_symulti)          // don't need to pass icon with your message if it's already in your app !
            .setContentTitle(URLDecoder.decode(getString(R.string.app_name), "UTF-8"))
            .setContentText(URLDecoder.decode(message, "UTF-8"))
            .setAutoCancel(true)
            .setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
            .setContentIntent(pendingIntent);
        } catch (UnsupportedEncodingException e) {
          e.printStackTrace();
        }

        if (notificationBuilder != null) {
          NotificationManager notificationManager =
              (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
          notificationManager.notify(id, notificationBuilder.build());
        } else {
          Log.d(TAG, "error NotificationManager");
        }
      }
    }
}

Profitez-en !

3 votes

Cela devrait être la réponse acceptée, onMessageReceived est appelé à la fois en avant-plan et en arrière-plan. Merci !

0 votes

Supprimer l'application des récents, sans callback ni notification dans la barre d'état système.

2 votes

Vous m'avez sauvé la mise. Aucune de ces réponses n'a été expliquée aussi bien que celle-ci.

20voto

diidu Points 1636

Il s'agit d'une solution de contournement qui contient également quelques informations supplémentaires :

Puisque les notifications sont traitées différemment selon l'état de l'application (avant-plan/arrière-plan/non lancé), j'ai vu que la meilleure façon d'implémenter une classe d'aide où l'activité sélectionnée est lancée en fonction des données personnalisées envoyées dans le message de notification.

  • lorsque l'application est au premier plan, utilisez la classe d'aide dans onMessageReceived.
  • lorsque l'application est en arrière-plan, utilisez la classe d'aide pour gérer l'intention dans le onNewIntent de l'activité principale (vérifiez les données personnalisées spécifiques).
  • lorsque l'application n'est pas en cours d'exécution, utilisez la classe d'aide pour gérer l'intention dans le onCreate de l'activité principale (appelez getIntent pour l'intention).

De cette façon, vous n'avez pas besoin du filtre click_action ou intent qui lui est spécifique. De plus, vous n'écrivez le code qu'une seule fois et vous pouvez lancer n'importe quelle activité assez facilement.

Ainsi, les données personnalisées minimales ressembleraient à ceci :

Key: run_activity
Value: com.mypackage.myactivity

Et le code pour le gérer :

if (intent.hasExtra("run_activity")) {
    handleFirebaseNotificationIntent(intent);
}

private void handleFirebaseNotificationIntent(Intent intent){
    String className = intent.getStringExtra("run_activity");
    startSelectedActivity(className, intent.getExtras());
}

private void startSelectedActivity(String className, Bundle extras){
    Class cls;
    try {
        cls = Class.forName(className);
    }catch(ClassNotFoundException e){
        ...
    }
    Intent i = new Intent(context, cls);

    if (i != null) {
        i.putExtras(extras);
        this.startActivity(i);
    } 
}

C'est le code pour les deux derniers cas, startSelectedActivity serait appelé également à partir de onMessageReceived (premier cas).

La limitation est que toutes les données dans les extras d'intention sont des chaînes de caractères, donc vous devrez peut-être gérer cela d'une manière ou d'une autre dans l'activité elle-même. De plus, il s'agit d'une simplification, vous n'avez probablement pas envie de changer l'activité/la vue d'une application qui est au premier plan sans avertir votre utilisateur.

0 votes

Je ne comprends pas la phrase du 3ème point : " when the app is not launched use the helper class for handling the intent in main activity's onCreate (call getIntent for the intent). ". Je veux dire, si l'application n'est pas active, comment pouvez-vous y répondre ?

0 votes

L'intention lance l'application et onCreate est appelé. Il faudrait peut-être dire "lorsque l'application n'est pas en cours d'exécution". Je l'ai modifié.

1 votes

Sachez qu'après l'activation de Proguard dans votre version, le nom de la classe sera obscurci. Il est donc préférable d'utiliser le mappage clé-activité. C'est-à-dire if (className == "someName") { lunchSomeActivity() }

20voto

gagan bhutani Points 127

Il ressort clairement de la documentation de Firebase que votre onMessageReceived ne fonctionnera pas lorsque l'application est en arrière-plan.

Lorsque votre application est en arrière-plan et que vous cliquez sur votre notification, votre lanceur par défaut sera lancé. Pour lancer l'activité de votre choix, vous devez spécifier click_action dans les données utiles de votre notification.

$noti = array
    (
    'icon' => 'new',
    'title' => 'title',
    'body' => 'new msg',
    'click_action' => 'your activity name comes here'
); 

Et dans votre android.manifest fichier

Ajoutez le code suivant à l'endroit où vous avez enregistré votre activité

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

1 votes

C'est utile pour moi. Maintenant je peux ouvrir mon application quand je clique sur la notification push, une page par défaut est ouverte. Mais maintenant je veux ouvrir une page particulière quand je clique sur la notification push. voir ma question ici stackoverflow.com/questions/44797486/

0 votes

Vous pouvez nommer votre action comme vous le souhaitez, il n'est pas nécessaire que ce soit le nom de votre activité

1 votes

Ce n'est pas un nom d'activité, c'est le nom de l'action dans intent-filter

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X