Icono de notificación con el nuevo sistema Firebase Cloud Messaging

132

Ayer, Google presentó en Google I / O el nuevo sistema de notificación basado en la nueva Firebase. Probé este nuevo FCM (Firebase Cloud Messaging) con el ejemplo en Github.

El ícono de la notificación es siempre el ic_launcher a pesar de que he declarado un sorteo específico

Por qué ? Aquí debajo el código oficial para manejar el mensaje

public class AppFirebaseMessagingService extends FirebaseMessagingService {

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // If the application is in the foreground handle both data and notification messages here.
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
        sendNotification(remoteMessage);
    }
    // [END receive_message]

    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param remoteMessage FCM RemoteMessage received.
     */
    private void sendNotification(RemoteMessage remoteMessage) {

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

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

// this is a my insertion looking for a solution
        int icon = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? R.drawable.myicon: R.mipmap.myicon;
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(icon)
                .setContentTitle(remoteMessage.getFrom())
                .setContentText(remoteMessage.getNotification().getBody())
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

}
marco
fuente
firebase no tiene nada que ver con cómo USTED está creando la notificación, proporcione una imagen de lo que está viendo
tyczj
1
exacto. este código viene directamente de Firebase y el método sendNotification () es exactamente el mismo para cualquier notificación. Este código funciona bien con GCM, pero con FCM no. siempre permanece ic_launcher, utilizando la nueva interfaz web para enviar mensajes
marco
se establece el pequeño icono pero no el icono grande, a menos que usted está enviando un empujón con la etiqueta de la notificación en la carga útil de empuje no tiene nada que ver con la FCM
tyczj
¿Muestra su icono de notificación personalizada cuando la aplicación está en primer plano? Funciona para mi. Sin embargo, cuando la aplicación está en segundo plano, debe usar algún tipo de controlador FCM predeterminado, ya que se ignoran todas las configuraciones de notificación (icono, sonido, luces, vibración, etc. no se pueden personalizar).
shinypenguin

Respuestas:

267

Desafortunadamente, esta fue una limitación de las notificaciones de Firebase en SDK 9.0.0-9.6.1. Cuando la aplicación está en segundo plano, el icono del iniciador se usa desde el manifiesto (con el tinte requerido de Android) para los mensajes enviados desde la consola.

Sin embargo, con SDK 9.8.0, puede anular el valor predeterminado. En su AndroidManifest.xml puede configurar los siguientes campos para personalizar el icono y el color:

<meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/notification_icon" />
<meta-data android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/google_blue" />

Tenga en cuenta que si la aplicación está en primer plano (o se envía un mensaje de datos) puede usar completamente su propia lógica para personalizar la pantalla. También siempre puede personalizar el icono si envía el mensaje desde las API HTTP / XMPP.

Ian Barber
fuente
1
@ Ian Barber: ¿algún plan en Google para cambiar este comportamiento en el futuro cercano?
skylve
1
El equipo es consciente del problema y está trabajando en una solución.
Arthur Thompson
1
¿Algún avance en esto? pensé en preguntar porque hubo circunstancias en que un ingeniero de Google simplemente olvidó presionar el parche.
CQM
77
Ah, lo tengo para trabajar con 9.8.0. Para ayudar a otros, recuerde que el icono de su barra de estado debe cumplir con los requisitos: developer.android.com/guide/practices/ui_guidelines/… . El mío no lo hizo y, por lo tanto, la base de fuego simplemente se predetermina al cuadrado blanco estándar en lugar de usar el icono especificado en el manifiesto.
zaifrun
3
Si prueba esto y encuentra que el icono es más pequeño que otras notificaciones, asegúrese de estar usando un vector dibujable (y no un png). Eso lo resolvió para mí.
Riper
35

Use una implementación de servidor para enviar mensajes a su cliente y use el tipo de datos de mensajes en lugar del tipo de notificación de mensajes.

Esto lo ayudará a obtener una devolución de llamada onMessageReceivedindependientemente de si su aplicación está en segundo plano o en primer plano y luego puede generar su notificación personalizada

geekoraul
fuente
2
Esta es la solución sugerida en los documentos de Firebase también, puede mostrar la notificación de la manera que prefiera si confía en la inserción de datos en lugar de la notificación.
racs
1
si de acuerdo. Esto debe ser marcado como una respuesta correcta. o mi respuesta a continuación :)
Developine
3
No, no es factible para las personas que necesitan mantener la compatibilidad con otros clientes / versiones heredadas que esperan una notificación.
Gabor
Tenemos aplicaciones en producción que ya esperan un tipo de notificación de inserción y hemos extendido ese componente (complejo) de back-end para agregar datos para nuevos clientes. Pero no podemos eliminar el soporte para versiones heredadas de nuestra aplicación.
Gabor
Oh estoy de acuerdo Ese es otro problema. Sugeriría leer los documentos a fondo antes de integrar. También para probar a fondo antes de lanzar a producción. El problema podría haberse evitado si la aplicación se hubiera probado mucho antes del lanzamiento. De todos modos, tenías algo que aprender.
geekoraul
9

atm están trabajando en ese tema https://github.com/firebase/quickstart-android/issues/4

cuando envía una notificación desde la consola de Firebase, usa el ícono de su aplicación de manera predeterminada, y el sistema Android activará ese ícono en blanco cuando esté en la barra de notificaciones.

Si no está satisfecho con ese resultado, debe implementar FirebaseMessagingService y crear las notificaciones manualmente cuando reciba un mensaje. Estamos trabajando en una forma de mejorar esto, pero por ahora esa es la única manera.

editar: con SDK 9.8.0 agregar a AndroidManifest.xml

<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/my_favorite_pic"/>
Jan Hartwig
fuente
cómo mostrar la bandeja de notificaciones de iconos personalizados en malvavisco
Harsha
6

Mi solución es similar a la de ATom, pero más fácil de implementar. No necesita crear una clase que sombree FirebaseMessagingService por completo, solo puede anular el método que recibe la Intención (que es público, al menos en la versión 9.6.1) y tomar la información que se mostrará de los extras. La parte "hacky" es que el nombre del método está realmente ofuscado y cambiará cada vez que actualice Firebase sdk a una nueva versión, pero puede buscarlo rápidamente inspeccionando FirebaseMessagingService con Android Studio y buscando un método público que requiera Una intención como único parámetro. En la versión 9.6.1 se llama zzm. Así es como se ve mi servicio:

public class MyNotificationService extends FirebaseMessagingService {

    public void onMessageReceived(RemoteMessage remoteMessage) {
        // do nothing
    }

    @Override
    public void zzm(Intent intent) {
        Intent launchIntent = new Intent(this, SplashScreenActivity.class);
        launchIntent.setAction(Intent.ACTION_MAIN);
        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* R    equest code */, launchIntent,
                PendingIntent.FLAG_ONE_SHOT);
        Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),
                R.mipmap.ic_launcher);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_notification)
                .setLargeIcon(rawBitmap)
                .setContentTitle(intent.getStringExtra("gcm.notification.title"))
                .setContentText(intent.getStringExtra("gcm.notification.body"))
                .setAutoCancel(true)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager)     getSystemService(Context.NOTIFICATION_SERVICE);

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
}
Carlo Conserva
fuente
gcm.notification.title for key name es 100% seguro para todas las versiones?
pedroooo
3

Simplemente configure targetSdkVersion en 19. El ícono de notificación será de color. Luego espera a que Firebase solucione este problema.

rattisuk
fuente
77
: D Wow, entonces, ¿dónde está la lista de efectos secundarios?
Eugen Pechanec
@EugenPechanec sí, la compensación es que es posible que no pueda usar alguna API que esté disponible en 20+
benleung
3

También hay una forma fea pero funcional. Descompile FirebaseMessagingService.class y modifique su comportamiento. Luego, coloque la clase en el paquete correcto en su aplicación y dex úsela en lugar de la clase en la propia biblioteca de mensajes. Es bastante fácil y funciona.

Hay un método:

private void zzo(Intent intent) {
    Bundle bundle = intent.getExtras();
    bundle.remove("android.support.content.wakelockid");
    if (zza.zzac(bundle)) {  // true if msg is notification sent from FirebaseConsole
        if (!zza.zzdc((Context)this)) { // true if app is on foreground
            zza.zzer((Context)this).zzas(bundle); // create notification
            return;
        }
        // parse notification data to allow use it in onMessageReceived whe app is on foreground
        if (FirebaseMessagingService.zzav(bundle)) {
            zzb.zzo((Context)this, intent);
        }
    }
    this.onMessageReceived(new RemoteMessage(bundle));
}

Este código es de la versión 9.4.0, el método tendrá diferentes nombres en diferentes versiones debido a la ofuscación.

Átomo
fuente
3

si su aplicación está en segundo plano, el icono de notificación se establecerá en el método de recepción de mensajes, pero si su aplicación está en primer plano, el icono de notificación será el que definió en el manifiesto

ingrese la descripción de la imagen aquí

arroyo
fuente
2

Estoy activando mis notificaciones desde la consola FCM y a través de HTTP / JSON ... con el mismo resultado.

Puedo manejar el título, mensaje completo, pero el ícono siempre es un círculo blanco predeterminado:

Captura de pantalla de notificaciones

En lugar de mi icono personalizado en el código (setSmallIcon o setSmallIcon) o el icono predeterminado de la aplicación:

 Intent intent = new Intent(this, MainActivity.class);
    // use System.currentTimeMillis() to have a unique ID for the pending intent
    PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);

    if (Build.VERSION.SDK_INT < 16) {
        Notification n  = new Notification.Builder(this)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pIntent)
                .setAutoCancel(true).getNotification();
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //notificationManager.notify(0, n);
        notificationManager.notify(id, n);
    } else {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

        Notification n  = new Notification.Builder(this)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setLargeIcon(bm)
                .setContentIntent(pIntent)
                .setAutoCancel(true).build();

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //notificationManager.notify(0, n);
        notificationManager.notify(id, n);
    }
Gonzalo
fuente
1
¡Entendido! mis etiquetas <service> están fuera de la etiqueta <application> en AndroidManifest.xml Aquí calculo la respuesta stackoverflow.com/a/37352142/6366150
Gonzalo
Solo funciona con la aplicación en primer plano ejecutándose ... en segundo plano sigue teniendo el mismo comportamiento anterior
Gonzalo
cuando la aplicación en primer plano ese ícono de notificación personalizada está funcionando bien, pero en el fondo de la aplicación aparece el ícono cuadrado blanco, por favor
ayúdenme
1

escribe esto

<meta-data 
         android:name="com.google.firebase.messaging.default_notification_icon"
         android:resource="@drawable/ic_notification" />

justo abajo <application.....>

ingrese la descripción de la imagen aquí

dmarquina
fuente
0

Pensé que agregaría una respuesta a esta, ya que mi problema era simple pero difícil de notar. En particular, había copiado / pegado un elemento de metadatos existente al crear mi com.google.firebase.messaging.default_notification_icon, que usaba una android:valueetiqueta para especificar su valor. Esto no funcionará para el icono de notificación, y una vez que lo cambié a android:resourcetodo funcionó como se esperaba.

Charles A.
fuente
Lo mismo va para la default_notification_colormeta, tiene que ser un android:resource- ajuste que android:valueno va a funcionar
flochtililoch