Cordova-plugin-firebase: (Android) Hacer clic en la notificación no se activa en la devolución de llamada de NotificationOpen

Creado en 21 sept. 2016  ·  28Comentarios  ·  Fuente: arnesson/cordova-plugin-firebase

Córdoba 6.3.1
Complemento de base de fuego de Phonegap 0.1.12
Dispositivo: LG G5 con Android 6.0.1

Este es el código que estoy usando:
`var app = {
// Constructor de aplicaciones
inicializar: función () {
this.bindEvents ();
},
// Vincular oyentes de eventos
//
// Vincula los eventos necesarios al inicio. Los eventos comunes son:
// 'cargar', 'dispositivo listo', 'sin conexión' y 'en línea'.
bindEvents: function () {
document.addEventListener ('dispositivo listo', this.onDeviceReady, falso);
},
// controlador de eventos listo para el dispositivo
//
// El alcance de 'esto' es el evento. Para llamar al 'evento recibido'
// función, debemos llamar explícitamente a 'app.receivedEvent (...);'
onDeviceReady: function () {
console.log ("Estamos en onDeviceReady");
if (navigator.connection.type == Connection.NONE) {
navigator.notification.alert ('Se requiere conexión a Internet');
} demás {
window.FirebasePlugin.onNotificationOpen (función (notificación) {
console.log (notificación);
navigator.notification.alert ("Recibido");
}, función (error) {
console.log (error);
});
}
},

};
app.initialize (); `

Recibo notificaciones en la bandeja del sistema en todas las situaciones: aplicación en segundo plano, primer plano y cerrada y cuando hago clic en la notificación, la aplicación está abierta en los tres casos pero la devolución de llamada no se activa.

¿Hay algún error en el código?

Gracias por adelantado.

Comentario más útil

He reescrito todo el manejo de onNotificationOpen y lo tengo casi funcionando como esperaba, que es:

  • La notificación llega con el cliente en primer plano, se abre la notificación y se llama a onNotificationOpen en el cliente actual (sin recargar)
  • La notificación llega con el cliente en segundo plano, la notificación abierta y el cliente se pone en primer plano y se llama a onNotificationOpen con el cliente actual (sin recargar)

Lo único que queda es que la notificación se entregue inmediatamente al cliente sin necesidad de abrirla, si eso es posible (aún no lo he investigado).

Soy un poco novato en Android, por lo que puede haber algunas mejoras que se pueden hacer, pero parece que funciona bien, así que pensé en compartirlo.

OnNotificationOpe nReceiver: onReceive ahora simplemente llama

FirebasePlugin.onBroadcastReceive(context, intent);

Se cambió FirebasePlugin siguiente manera

  • eliminar WeakReference de callbackContext
  • agregar el método onBroadcastReceive, pasa los datos de la intención a onNotificationOpen
  • add onNewIntent método, pasa los datos de la intención a onNotificationOpen
  • restauró la versión anterior de onNotificationOpen y la cambió de la siguiente manera

    • eliminada la línea WeakReference

    • Cambie las devoluciones de llamada para usar un PluginResult y llame a setKeepCallback (true) en el resultado para evitar que la devolución de llamada se elimine después de la primera llamada

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

Todos 28 comentarios

mismo problema, en Android llegan notificaciones pero dentro de la aplicación no se llama a la devolución de llamada.
v. 0.1.12

@voidbrain @Kibukita , por favor, pruebe la última versión del repositorio. Intenté mejorar la notificación abierta. Gracias.

@BugsBunnyBR Intenté actualizar a la última versión del repositorio y lo probé. En Android, todavía no se ejecuta onNotificationOpen.

@superheroben , ¿podría proporcionar un repositorio con una muestra de cómo está llamando al código del complemento? ¿Cómo envías las notificaciones? Probé con mensajes temáticos.

El mismo problema aqui.
Se llama a la devolución de llamada getInstanceId (), llega la notificación, pero nunca se llama a onNotificationOpen ().

Codigo del cliente:

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

Mi estructura de datos de notificación:

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

Mi código del lado del servidor (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);

Trabajando en Cordova Android 5.2.2. El dispositivo utilizado para la prueba ejecuta Android 4.4.2. Versión del complemento 0.1.12.

@arivanbastos , ¿ha intentado apuntar al repositorio de github?

La instalación desde github resolvió parcialmente el problema. Gracias.

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

Ahora se llama a la devolución de llamada onNotificationOpen () cuando la aplicación está en segundo plano.
Cuando la aplicación está en primer plano, en lugar de lo que dice la documentación, llega la notificación y no se llama a onNotificationOpen ():

La aplicación está en primer plano:
El usuario recibe los datos de notificación en la devolución de llamada de JavaScript sin ninguna notificación en el dispositivo (este es el comportamiento normal de las notificaciones push, depende de usted, el desarrollador, notificar al usuario)

Si envía un mensaje push del tipo "notificación" (sin un cuerpo de datos), la notificación no debería mostrarse cuando la aplicación esté en primer plano.

Lo siento, no entendí. ¿Debo simplemente agregar una sección de "datos" a mis datos de notificación?

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

Esto no solucionó el problema.

Cambiar el nombre de la sección "notificación" por "datos" hace que la aplicación se bloquee ("La aplicación se ha detenido") cuando llega la notificación:

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

https://firebase.google.com/docs/cloud-messaging/android/receive
Aquí se describe muy bien.
Su notificación va a la bandeja del sistema si la aplicación está en segundo plano y a onMessageReceived () si la aplicación está en primer plano.
Si su mensaje contiene datos, estos siempre se pasan a onMessageReceived ().

Creo que hay un problema en la implementación de onMessageReceived ().
Cuando miro el código que interpreto es el siguiente:

  • extraer datos
  • crear una notificación con NotificationBuilder
  • notificar a través de NotificationManager

NotificationManager.notify (id, notificación) publica la notificación que se mostrará en la barra de estado.

Sin embargo, para mí esto parece ser de esperar que cada vez que reciba un mensaje de FCM se muestre una notificación en la barra de estado.
No veo ninguna verificación si la aplicación está en primer plano y no veo ninguna llamada a la devolución de llamada. No soy un desarrollador de Android, así que tal vez esté equivocado, pero el comportamiento descrito se ajusta a eso.

OK, encontré el fragmento de código que llama a la devolución de llamada.
Con la última confirmación de BugsBunnyBR hubo un cambio en OnNotificationOpenReceiver que explica que arivanbastos obtiene su devolución de llamada ejecutada cuando apunta al repositorio de github.

Pero aún así, la notificación solo se envía (a OnNotificationOpenReceiver y NotificationManager) si hay un texto o un título (en la notificación o en los datos). Eso significa que no es posible enviar datos a su aplicación sin recibir la notificación enviada al NotificationManager que lo muestra en la barra de estado.

@arivanbastos
Te dije algo mal. Lo siento por eso.
¿Ha intentado apuntar a esta versión de repositorio?

@packowitz y @robertarnesson . Ok, mi implementación SIEMPRE * intentará mostrar la notificación. O se mostrará la notificación automática de Firebase o la compilación dentro de onMessageReceived .
La devolución onNotificationOpen llamada onMessageReceived o cuando la notificación tenga cuerpos de datos y notificación al mismo tiempo. En mi pr que introdujo el onNotificationOpen traté de explicar que las notificaciones push del tipo Notificación no dispararían la devolución de llamada. La recomendación es incluir siempre un cuerpo de datos y un cuerpo de notificación, para que el complemento pueda detectar y activar la devolución de llamada.

Lo sé, mostrar siempre la notificación no es el comportamiento de notificación estándar de Firebase.

La mayoría de los desarrolladores de aplicaciones de Android quieren que su notificación se muestre en la bandeja del sistema incluso si la aplicación está en primer plano. Sé que hay casos, en aplicaciones de chat similares, en los que este comportamiento no es bueno.
Cuando desarrollé la función de notificación de Android, no me importaban las necesidades de las aplicaciones de chat o cumplir con Firebase.

Lo que se puede hacer es:
1) Desarrolle una bandera para que se establezca cuando la aplicación esté abierta que diga "hey, quiero que muestre la notificación incluso cuando la aplicación esté abierta" y úsela para controlar el comportamiento. No sería necesario conservarlo en ningún almacenamiento si la aplicación siempre establece la bandera al abrir.

2) Simplemente comente esta línea y desactive la notificación cuando la aplicación esté en primer plano.

_Siempre_ -> Si el complemento encuentra un "texto" o "título" en el cuerpo de la notificación.

@BugsBunnyBR Me gusta la idea de tener una bandera para elegir el comportamiento.
Desacoplaría el NotificationManager del OnNotificationOpenReceiver llamando a su devolución de llamada JS. Mi recomendación es introducir una verificación, si hay datos en el mensaje y, de ser así, llamar a la devolución de llamada con los datos.
Para la notificación sería bueno tener la bandera.
Gracias.

@BugsBunnyBR Acabo de probar para cambiar al repositorio de github y descubrí que al tocar una notificación se reinicia mi aplicación incluso si ya se está ejecutando. Sucede incluso cuando la aplicación está en primer plano y toco la notificación.
Pero la devolución de llamada funciona ahora;)

Lo mismo aquí, para mí la versión 0.1.13 está provocando que mi aplicación se reinicie justo cuando está en primer plano. La versión 0.1.12 está funcionando bien.

Las notificaciones simplemente no funcionan de manera sensata en la versión de repositorio. La razón es que creo que si se llama a onNotificationOpen antes de que se abra una notificación, se ignora.

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

En registerOnNotificationOpen solo registra la devolución de llamada SI hay un notificationBundle esperando

Además, la razón por la que la aplicación parece recargarse si ya está abierta es en OnNotificationOpenReceiver que dice explícitamente

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

lo que obliga al cliente a recargar, donde el notificationBundle está disponible cuando se registra la devolución onNotificationOpen llamada

He reescrito todo el manejo de onNotificationOpen y lo tengo casi funcionando como esperaba, que es:

  • La notificación llega con el cliente en primer plano, se abre la notificación y se llama a onNotificationOpen en el cliente actual (sin recargar)
  • La notificación llega con el cliente en segundo plano, la notificación abierta y el cliente se pone en primer plano y se llama a onNotificationOpen con el cliente actual (sin recargar)

Lo único que queda es que la notificación se entregue inmediatamente al cliente sin necesidad de abrirla, si eso es posible (aún no lo he investigado).

Soy un poco novato en Android, por lo que puede haber algunas mejoras que se pueden hacer, pero parece que funciona bien, así que pensé en compartirlo.

OnNotificationOpe nReceiver: onReceive ahora simplemente llama

FirebasePlugin.onBroadcastReceive(context, intent);

Se cambió FirebasePlugin siguiente manera

  • eliminar WeakReference de callbackContext
  • agregar el método onBroadcastReceive, pasa los datos de la intención a onNotificationOpen
  • add onNewIntent método, pasa los datos de la intención a onNotificationOpen
  • restauró la versión anterior de onNotificationOpen y la cambió de la siguiente manera

    • eliminada la línea WeakReference

    • Cambie las devoluciones de llamada para usar un PluginResult y llame a setKeepCallback (true) en el resultado para evitar que la devolución de llamada se elimine después de la primera llamada

    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 ... He notado que las notificaciones no se envían (al dispositivo) cuando el cliente no se está ejecutando (se ha eliminado).

Intente abrir una notificación presentada por firebase directamente y vea el comportamiento. Supongo que reinician la actividad principal, que creo que es el comportamiento correcto.

Pido disculpas por la demora. Intenté con 0.1.13 pero mi aplicación se reinicia después de que se abre la notificación.

hay noticias ?

No puedo obtener ninguna devolución de llamada de onNotificationOpen exitosa o fallar en Android usando 0.1.17. No funciona el envío a través de la API o la GUI con una carga útil. ¿Alguna sugerencia?

¿Por qué no creamos una solicitud de extracción con ese código publicado por @Mehuge ? Funciona como un encanto en Android para mí.

Tuve que actualizar onNewIntent en FirebasePlugin para filtrar las intenciones de inicio normales, por lo que mi código onNewIntent ahora se ve así

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

No estoy del todo contento con eso. Funciona buscando una propiedad de identificación en el paquete de intenciones que siempre envía el código de mi servidor. No parece haber nada que GCM o FBM agreguen de manera confiable al paquete que se pueda usar para identificar la intención como una notificación / mensaje. A veces se agregan algunas propiedades de Google (si estamos abriendo una notificación desde la bandeja) pero para los mensajes y notificaciones entregados directamente al cliente cuando están en primer plano, no hay nada más que los datos en el mensaje que le dicen que es una intención de lanzamiento. debido a una notificación, al menos eso pude ver.

Probablemente haya una mejor manera de manejar esto.

@Mehuge, ¿te importaría crear gists con todos los archivos que tienes?

Ok, aquí está https://gist.github.com/Mehuge/374ee24d9e18a6c7ccc171d3e521b7ad

Sin embargo, tenga en cuenta que hay algunos bits que son específicos de nuestra aplicación. Terminé moviendo el código a nuestro proyecto porque lo estaba cambiando mucho. En retrospectiva, probablemente debería haber bifurcado el complemento y modificarlo de esa manera, pero en este punto, estaba muy retrasado y bastante harto de todo, así que tomé la ruta más rápida para hacer que algo funcionara. Los bits personalizados son bastante obvios, por lo que deberían ser bastante fáciles de excluir.

Tenga en cuenta también que la forma en que implementé el complemento, necesita saber cuándo el cliente está en pausa (o más específicamente, no en pausa) para que pueda decidir si crear una notificación o entregar el mensaje directamente. Es posible que necesite o no esa funcionalidad, pero en nuestro caso, no queríamos que las notificaciones que se enviaran cuando el cliente estaba en primer plano crearan notificaciones de Android, sino que se entregaran directamente al cliente para que las manejara. Para informar al complemento del estado de pausa del cliente, agregue el siguiente código a su actividad principal.

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

Hay otro problema con el que puede tener que lidiar, que es si llega una notificación mientras está en segundo plano, pero el usuario inicia la aplicación directamente en lugar de abrir la notificación de Android, es posible que deba lidiar con eso de alguna manera. En el caso de nuestras aplicaciones, podría borrar las notificaciones sin abrir. Tu situación puede ser diferente.

No estoy del todo satisfecho con el resultado final, algunas de las claves adicionales agregadas, por ejemplo, eran experimentales y en realidad no se están utilizando, simplemente no he podido eliminarlas.

Estaría interesado en cualquier comentario o mejora sugerida o en señalar cualquier defecto. Me interesaría particularmente encontrar una manera de detectar mejor una intención de lanzamiento con una carga útil de GCM de un lanzamiento normal. Encontré que las propiedades de Google solo se agregan en algunas circunstancias. Además, mis intentos de detectar los diferentes tipos de notificaciones (is_push, is_notify, broadcast) no funcionan realmente.

ver # 108

Para mí, podría resolver hacer la solicitud de esta manera:

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

Pero tuve que tomar click_action como parámetro y hacer la redirección manualmente (estaba usando cordova con la aplicación react).

¿Fue útil esta página
0 / 5 - 0 calificaciones