Cordova-plugin-firebase: (Android) Cliquez sur la notification ne déclenche pas le rappel NotificationOpen

Créé le 21 sept. 2016  ·  28Commentaires  ·  Source: arnesson/cordova-plugin-firebase

Cordoue 6.3.1
Plugin Firebase Phonegap 0.1.12
Appareil : LG G5 avec Android 6.0.1

Voici le code que j'utilise :
`var app = {
// Constructeur d'applications
initialiser : fonction () {
this.bindEvents();
},
// Lier les écouteurs d'événement
//
// Lier tous les événements requis au démarrage. Les événements communs sont :
// 'load', 'deviceready', 'offline' et 'online'.
bindEvents : fonction () {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// Gestionnaire d'événements prêt pour l'appareil
//
// La portée de 'this' est l'événement. Pour appeler le 'receivedEvent'
// fonction, nous devons explicitement appeler 'app.receivedEvent(...);'
onDeviceReady : fonction () {
console.log ("Estamos et onDeviceReady");
if (navigator.connection.type == Connection.NONE) {
navigator.notification.alert('Se requiere conexión a Internet');
} autre {
window.FirebasePlugin.onNotificationOpen (fonction (notification) {
console.log(notification);
navigator.notification.alert ("Recibido");
}, fonction (erreur) {
console.log(erreur);
});
}
},

} ;
app.initialize();`

Je reçois des notifications dans la barre d'état système dans toutes les situations : application en arrière-plan, au premier plan et fermée et lorsque je clique sur notification, l'application est ouverte dans les trois cas mais le rappel n'est pas déclenché.

Y a-t-il quelque chose qui ne va pas dans le code ?

Merci d'avance.

Commentaire le plus utile

J'ai réécrit l'ensemble onNotificationOpen gestion de

  • La notification arrive avec le client au premier plan, la notification ouverte et onNotificationOpen est appelé dans le client actuel (sans rechargement)
  • La notification arrive avec le client en arrière-plan, la notification ouverte et le client sont mis au premier plan et onNotificationOpen est appelé avec le client actuel (sans rechargement)

La seule chose qui reste est que la notification soit livrée immédiatement au client sans avoir besoin d'être ouverte, si cela est possible (je ne l'ai pas encore examiné).

Je suis un peu un noob Android, donc il peut y avoir des améliorations qui peuvent être apportées, mais cela semble fonctionner correctement, alors j'ai pensé que je partagerais.

OnNotificationOpe nReceiver:onReceive appelle maintenant simplement

FirebasePlugin.onBroadcastReceive(context, intent);

FirebasePlugin modifié comme suit

  • supprimer WeakReference de callbackContext
  • ajouter la méthode onBroadcastReceive, transmet les données d'intention à onNotificationOpen
  • ajouter la méthode onNewIntent, transmet les données d'intention à onNotificationOpen
  • ancienne version restaurée de onNotificationOpen et modifiée comme suit

    • ligne WeakReference supprimée

    • Modifiez les rappels pour utiliser un PluginResult et appelez setKeepCallback(true) sur le résultat pour empêcher la suppression du rappel après le premier appel

    private static CallbackContext callbackContext;
    // ...
    private void registerOnNotificationOpen(final CallbackContext callbackContext) {
        FirebasePlugin.callbackContext = callbackContext;
    }

    // called when in foreground
    public static void onBroadcastReceive(Context context, Intent intent) {
        Log.d("FirebasePlugin", "onBroadcastReceive");
        Bundle data = intent.getExtras();
        FirebasePlugin.onNotificationOpen(data);
    }

    // called when in background
    <strong i="32">@Override</strong>
    public void onNewIntent(Intent intent) {
        Log.d(TAG, "new intent " + intent);
        super.onNewIntent(intent);
        FirebasePlugin.onNotificationOpen(intent.getExtras());
    }

    public static void onNotificationOpen(Bundle bundle) {
        if (FirebasePlugin.callbackContext == null ) {
            Log.d("FirebasePlugin", "no callback context, onNotificationOpen ignored");
            return;
        }
        if (callbackContext != null && bundle != null) {
            JSONObject json = new JSONObject();
            Set<String> keys = bundle.keySet();
            for (String key : keys) {
                try {
                    json.put(key, bundle.get(key));
                } catch (JSONException e) {
                    Log.d("FirebasePlugin", "onNotificationOpen: json exception");
                    PluginResult result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
                    result.setKeepCallback(true);
                    callbackContext.sendPluginResult(result);
                    return;
                }
            }
            Log.d("FirebasePlugin", "onNotificationOpen: send notification to javascript");
            PluginResult result = new PluginResult(PluginResult.Status.OK, json);
            result.setKeepCallback(true);
            callbackContext.sendPluginResult(result);
        }
    }

Tous les 28 commentaires

même problème, sur Android, les notifications arrivent mais dans l'application, aucun rappel n'est appelé.
v. 0.1.12

@voidbrain @Kibukita s'il vous plaît, testez la dernière version du repo. J'ai essayé d'améliorer la notification ouverte. Merci.

@BugsBunnyBR Je viens d'essayer de mettre à jour vers la dernière version du

@superheroben , pourriez-vous fournir un dépôt avec un exemple de la façon dont vous appelez le code du plugin ? Comment envoyez-vous les notifications ? J'ai testé avec des messages de sujet.

Même problème ici.
Le rappel getInstanceId() est appelé, la notification arrive, mais onNotificationOpen() n'est jamais appelé.

Code client :

if (window.FirebasePlugin)
{
  window.FirebasePlugin.getInstanceId(
    function(token) {
        thiss.saveToken(token);
    }, 
    function(error) {
        console.log(error);
    }
  );

  window.FirebasePlugin.onNotificationOpen(
    function(notification) {                  
      alert("Yeah!!!");                  
    }, 
    function(error) {
      alert("Error!");
      console.error(error);
    }
  );

  window.FirebasePlugin.grantPermission();
}

Ma structure de données de notification :

(
    [to] => (device token)
    [notification] => Array
        (
            [title] => Title
            [text] => Test message
            [sound] => default
            [vibrate] => 1
            [badge] => 2
        )
)

Mon code côté serveur (PHP) :

$jsonData = json_encode($data);

$ch     = curl_init("https://fcm.googleapis.com/fcm/send");
$header = array(
    'Content-Type: application/json',
    "Authorization: key=".MY_GCM_API_KEY
);

curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, true);
curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);

$result = curl_exec($ch);
curl_close($ch);

Travailler sur Cordova Android 5.2.2. L'appareil utilisé pour tester fonctionne sous Android 4.4.2. Plugin version 0.1.12.

@arivanbastos , avez-vous essayé de pointer vers le référentiel github ?

L'installation à partir de github a partiellement résolu le problème. Merci.

cordova plugin remove cordova-plugin-firebase
cordova plugin add https://github.com/arnesson/cordova-plugin-firebase/

Désormais, le rappel onNotificationOpen() est appelé lorsque l'application est en arrière-plan.
Lorsque l'application est au premier plan, plutôt que la documentation ne le dit, la notification arrive et onNotificationOpen() n'est pas appelé :

L'application est au premier plan :
L'utilisateur reçoit les données de notification dans le rappel JavaScript sans aucune notification sur l'appareil lui-même (c'est le comportement normal des notifications push, c'est à vous, le développeur, d'informer l'utilisateur)

Si vous envoyez un push de type "notification" (sans corps de données), la notification ne devrait pas s'afficher lorsque l'application est au premier plan.

Désolé, je n'ai pas compris. Dois-je simplement ajouter une section « données » à mes données de notification ?

(
    [to] => (device token)
    [notification] => Array
        (
            [title] => Title
            [text] => Test message
        )
    [data] => Array
        (
            [test] => 1
        )
)

Cela n'a pas résolu le problème.

Renommer la section « notification » par « données » fait planter l'application (« l'application s'est arrêtée ») lorsque la notification arrive :

(
    [to] => (device token)
    [data] => Array
        (
            [title] => Title
            [text] => Test message
        )
)

https://firebase.google.com/docs/cloud-messaging/android/receive
Ici, il est très bien décrit.
Votre notification va à la barre d'état système si l'application est en arrière-plan et à onMessageReceived() si l'application est au premier plan.
Si votre message contient des données, celles-ci sont toujours transmises à onMessageReceived().

Je pense qu'il y a un problème dans l'implémentation de onMessageReceived().
Quand je regarde le code que j'interprète est le suivant:

  • extraire des données
  • créer une notification avec NotificationBuilder
  • notifier via NotificationManager

NotificationManager.notify(id, notification) publie la notification à afficher dans la barre d'état.

Cependant, pour moi, cela semble être prévu que chaque fois que je reçois un message de FCM, une notification s'affiche dans la barre d'état.
Je ne vois aucune vérification si l'application est au premier plan et je ne vois aucun appel au rappel. Je ne suis pas un développeur Android, donc je me trompe peut-être, mais le comportement décrit correspond à cela.

OK, j'ai trouvé le morceau de code qui appelle le rappel.
Avec le dernier commit de BugsBunnyBR, il y a eu un changement dans OnNotificationOpenReceiver qui explique qu'arivanbastos obtient son rappel exécuté lorsqu'il pointe vers le référentiel github.

Mais quand même, la notification n'est envoyée (au OnNotificationOpenReceiver et au NotificationManager) que s'il y a un texte ou un titre (dans la notification ou dans les données). Cela signifie qu'il n'est pas possible d'envoyer des données à votre application sans que la notification soit envoyée au NotificationManager qui l'affiche dans la barre d'état.

@arivanbastos
Je t'ai dit quelque chose de mal. Désolé pour ça.
Avez-vous essayé de pointer vers cette version du référentiel ?

@packowitz et @robertarnesson . Ok, mon implémentation essaiera TOUJOURS* d'afficher la notification. Ou la notification affichée automatiquement par Firebase ou la version à l'intérieur de onMessageReceived sera affichée.
Le rappel onNotificationOpen sera appelé lorsque onMessageReceived est appelé ou lorsque la notification a des corps de données et de notification en même temps. Dans mon pr qui a introduit le onNotificationOpen j'ai essayé d'expliquer que les notifications push de type Notification ne déclencheraient pas le rappel. La recommandation est de toujours inclure un corps de données et un corps de notification, afin que le plugin puisse détecter et déclencher le rappel.

Je sais que toujours afficher la notification n'est pas le comportement de notification standard de Firebase.

La plupart des développeurs d'applications Android souhaitent que leur notification s'affiche dans la barre d'état système, même si l'application est au premier plan. Je sais qu'il y a des cas, dans des applications de chat comme, que ce comportement n'est pas une bonne chose.
Lorsque j'ai développé la fonction de notification Android, je ne me souciais pas des besoins des applications de chat ou de la conformité à Firebase.

Ce qu'on peut faire c'est :
1) Développez un indicateur à définir lorsque l'application est ouverte en disant « hé, je veux que vous affichiez la notification même lorsque l'application est ouverte » et utilisez-le pour contrôler le comportement. Il n'aurait pas besoin d'être conservé dans un stockage si l'application définissait toujours le drapeau lors de l'ouverture.

2) Il suffit de commenter cette ligne et de désactiver la notification lorsque l'application est au premier plan.

_Toujours_ -> Si le plugin trouve un "texte" ou un "titre" dans le corps de notification.

@BugsBunnyBR J'aime l'idée d'avoir un drapeau pour choisir le comportement.
Je découplerais le NotificationManager du OnNotificationOpenReceiver rappelant votre rappel JS. Ma recommandation est d'introduire une vérification, s'il y a des données dans le message et si c'est le cas, appelez le rappel avec les données.
Pour la notification ce serait bien d'avoir le drapeau.
Merci.

@BugsBunnyBR Je viens de tester pour basculer vers le référentiel github et j'ai
Mais le rappel fonctionne maintenant ;)

Idem ici, pour moi la version 0.1.13 provoque le redémarrage de mon application juste au moment où elle est au premier plan. La version 0.1.12 fonctionne très bien.

Les notifications ne fonctionnent tout simplement pas de manière sensée dans la version repo. Je pense que la raison en est que si onNotificationOpen est appelé avant qu'une notification ne soit ouverte, elle est ignorée.

https://github.com/arnesson/cordova-plugin-firebase/blob/master/src/android/FirebasePlugin.java#L123

Dans registerOnNotificationOpen il n'enregistre le rappel que SI il y a un notificationBundle attente

De plus, la raison pour laquelle l'application semble se recharger si elle est déjà ouverte est dans OnNotificationOpenReceiver il est dit explicitement

launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);

https://github.com/arnesson/cordova-plugin-firebase/blob/master/src/android/OnNotificationOpenReceiver.java#L17

ce qui force le client à recharger, là où le notificationBundle est disponible lorsque le rappel onNotificationOpen est enregistré afin que le client reçoive alors la notification.

J'ai réécrit l'ensemble onNotificationOpen gestion de

  • La notification arrive avec le client au premier plan, la notification ouverte et onNotificationOpen est appelé dans le client actuel (sans rechargement)
  • La notification arrive avec le client en arrière-plan, la notification ouverte et le client sont mis au premier plan et onNotificationOpen est appelé avec le client actuel (sans rechargement)

La seule chose qui reste est que la notification soit livrée immédiatement au client sans avoir besoin d'être ouverte, si cela est possible (je ne l'ai pas encore examiné).

Je suis un peu un noob Android, donc il peut y avoir des améliorations qui peuvent être apportées, mais cela semble fonctionner correctement, alors j'ai pensé que je partagerais.

OnNotificationOpe nReceiver:onReceive appelle maintenant simplement

FirebasePlugin.onBroadcastReceive(context, intent);

FirebasePlugin modifié comme suit

  • supprimer WeakReference de callbackContext
  • ajouter la méthode onBroadcastReceive, transmet les données d'intention à onNotificationOpen
  • ajouter la méthode onNewIntent, transmet les données d'intention à onNotificationOpen
  • ancienne version restaurée de onNotificationOpen et modifiée comme suit

    • ligne WeakReference supprimée

    • Modifiez les rappels pour utiliser un PluginResult et appelez setKeepCallback(true) sur le résultat pour empêcher la suppression du rappel après le premier appel

    private static CallbackContext callbackContext;
    // ...
    private void registerOnNotificationOpen(final CallbackContext callbackContext) {
        FirebasePlugin.callbackContext = callbackContext;
    }

    // called when in foreground
    public static void onBroadcastReceive(Context context, Intent intent) {
        Log.d("FirebasePlugin", "onBroadcastReceive");
        Bundle data = intent.getExtras();
        FirebasePlugin.onNotificationOpen(data);
    }

    // called when in background
    <strong i="32">@Override</strong>
    public void onNewIntent(Intent intent) {
        Log.d(TAG, "new intent " + intent);
        super.onNewIntent(intent);
        FirebasePlugin.onNotificationOpen(intent.getExtras());
    }

    public static void onNotificationOpen(Bundle bundle) {
        if (FirebasePlugin.callbackContext == null ) {
            Log.d("FirebasePlugin", "no callback context, onNotificationOpen ignored");
            return;
        }
        if (callbackContext != null && bundle != null) {
            JSONObject json = new JSONObject();
            Set<String> keys = bundle.keySet();
            for (String key : keys) {
                try {
                    json.put(key, bundle.get(key));
                } catch (JSONException e) {
                    Log.d("FirebasePlugin", "onNotificationOpen: json exception");
                    PluginResult result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
                    result.setKeepCallback(true);
                    callbackContext.sendPluginResult(result);
                    return;
                }
            }
            Log.d("FirebasePlugin", "onNotificationOpen: send notification to javascript");
            PluginResult result = new PluginResult(PluginResult.Status.OK, json);
            result.setKeepCallback(true);
            callbackContext.sendPluginResult(result);
        }
    }

Humm... J'ai remarqué que les notifications ne sont pas envoyées (à l'appareil) lorsque le client n'est pas en cours d'exécution (a été tué).

Essayez d'ouvrir une notification présentée par firebase directement et voyez le comportement. Je suppose qu'ils redémarrent l'activité principale qui, à mon avis, est le bon comportement.

Désolé pour le retard. J'ai essayé avec 0.1.13 mais mon application est redémarrée après l'ouverture de la notification.

des nouvelles ?

Je ne parviens pas à obtenir de succès de rappel onNotificationOpen ou à échouer sur Android en utilisant 0.1.17. Ni l'envoi via l'API ou l'interface graphique avec une charge utile ne fonctionne. Aucune suggestion?

Pourquoi ne créons-nous pas une pull request avec ce code publié par @Mehuge ? Cela fonctionne comme un charme sur Android pour moi.

J'ai dû mettre à jour onNewIntent dans FirebasePlugin pour filtrer les intentions de lancement normales, donc mon code onNewIntent ressemble maintenant à ceci

<strong i="6">@Override</strong>
public void onNewIntent(Intent intent) {
  Log.d(TAG, "new intent " + intent);
  super.onNewIntent(intent);
  Bundle data = intent.getExtras();
  if (data != null) {
    String id = data.getString("id");
    if (null != id) {
      FirebasePlugin.handleNotificationBundle(data);
    } else {
      Log.d(TAG, "Not a notification intent, ignored");
    }
  }
}

Je n'en suis pas entièrement satisfait. Cela fonctionne en recherchant une propriété id dans le groupe d'intentions que mon code serveur envoie toujours. Il ne semble pas y avoir quoi que ce soit que GCM ou FBM ajoutent de manière fiable au groupe qui puisse être utilisé pour identifier l'intention en tant que notification/message. Parfois, nous ajoutons des propriétés google (si nous ouvrons une notification à partir de la barre d'état système), mais pour les messages et les notifications envoyés directement au client lorsqu'il est au premier plan, il n'y a rien d'autre que les données du message qui vous indiquent qu'il s'agit d'une intention de lancement à cause d'une notification, du moins que j'ai pu voir.

Il y a probablement une meilleure façon de gérer cela.

@Mehuge, cela vous dérangerait-il de créer des résumés avec tous les fichiers que vous avez ?

Ok ici c'est https://gist.github.com/Mehuge/374ee24d9e18a6c7ccc171d3e521b7ad

Notez cependant qu'il y a quelques éléments spécifiques à notre application. J'ai fini par déplacer le code dans notre projet parce que je le modifiais tellement. Avec le recul, j'aurais probablement dû bifurquer le plugin et le modifier de cette façon, mais à ce stade, j'étais très en retard et j'en avais assez de tout cela, alors j'ai pris le chemin le plus rapide pour faire fonctionner quelque chose. Les bits personnalisés sont assez évidents, ils devraient donc être assez faciles à exclure.

Notez également que la façon dont j'ai implémenté le plugin, il doit savoir quand le client est en pause (ou plus précisément pas en pause) afin qu'il puisse décider s'il faut créer une notification ou livrer le message directement. Vous pouvez ou non avoir besoin de cette fonctionnalité, mais dans notre cas, nous ne voulions pas que les notifications envoyées lorsque le client était au premier plan pour créer des notifications Android, mais soient plutôt livrées directement au client à gérer. Pour informer le plugin de l'état de pause du client, ajoutez le code suivant à votre activité principale.

<strong i="9">@Override</strong>
protected void onResume() {
    FirebasePlugin.setPaused(false);
    super.onResume();
}

<strong i="10">@Override</strong>
protected void onPause() {
    FirebasePlugin.setPaused(true);
    super.onPause();
}

Il existe un autre problème auquel vous devrez peut-être faire face, à savoir si une notification arrive en arrière-plan mais que l'utilisateur lance l'application directement plutôt qu'en ouvrant la notification Android, vous devrez peut-être gérer cela d'une manière ou d'une autre. Dans le cas de nos applications, je pourrais simplement effacer toutes les notifications non ouvertes. Votre situation peut être différente.

Je ne suis pas entièrement satisfait du résultat final, certaines des touches supplémentaires ajoutées par exemple étaient expérimentales et ne sont pas réellement utilisées, je n'ai tout simplement pas eu le temps de les supprimer.

Serait intéressé par tout commentaire ou suggestion d'amélioration ou signalant des défauts. Je serais particulièrement intéressé à trouver un moyen de mieux détecter une intention de lancement avec une charge utile GCM à partir d'un lancement normal. J'ai trouvé que les propriétés Google ne sont ajoutées que dans certaines circonstances. De plus, mes tentatives de détection des différents types de notifications (is_push, is_notify, broadcast) ne fonctionnent pas vraiment.

voir #108

Pour moi, je pourrais résoudre en faisant la demande comme ceci:

{
  "registration_ids": [...tokens],
  "notification" : {
        "title": "Notf title",
        "body": "Notification body"
     },
     "data": {
        "click_action": "/call/dwEugLJ9PTVdcFb064CX"
     }
}

Mais je devais prendre le click_action comme paramètre et faire la redirection manuellement (j'utilisais cordova avec l'application React).

Cette page vous a été utile?
0 / 5 - 0 notes