Icona di notifica con il nuovo sistema di messaggistica Firebase Cloud


132

Ieri Google ha presentato a Google I / O il nuovo sistema di notifica basato sul nuovo Firebase. Ho provato questo nuovo FCM (Firebase Cloud Messaging) con l'esempio su Github.

L'icona della notifica è sempre ic_launcher nonostante abbia dichiarato un disegno specifico

Perché ? Di seguito il codice ufficiale per la gestione del messaggio

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

}

firebase non ha nulla a che fare con il modo in cui stai creando la notifica, ti preghiamo di fornire un'immagine di ciò che stai vedendo
tyczj

1
esigere. questo codice proviene direttamente da Firebase e il metodo sendNotification () è esattamente lo stesso per qualsiasi notifica. Questo codice funziona bene con GCM, ma con FCM n. rimane sempre ic_launcher, usando la nuova interfaccia web per inviare messaggi
marco

imposti l'icona piccola ma non quella grande, a meno che tu non stia inviando una push con il tag di notifica nel payload push non ha nulla a che fare con FCM
tyczj

Mostra l'icona di notifica personalizzata quando l'app è in primo piano? Per me va bene. Tuttavia, quando l'app è in background, deve utilizzare una sorta di gestore FCM predefinito, poiché tutte le impostazioni di notifica vengono ignorate (icona, suono, luci, vibrazione, ecc. Non possono essere personalizzati).
shinypenguin,

Risposte:


267

Sfortunatamente questa era una limitazione delle notifiche Firebase in SDK 9.0.0-9.6.1. Quando l'app è in background, l'icona di avvio viene utilizzata dal manifest (con la colorazione Android necessaria) per i messaggi inviati dalla console.

Con SDK 9.8.0, tuttavia, è possibile ignorare l'impostazione predefinita! Nel tuo AndroidManifest.xml puoi impostare i seguenti campi per personalizzare l'icona e il colore:

<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" />

Tieni presente che se l'app è in primo piano (o viene inviato un messaggio di dati) puoi utilizzare completamente la tua logica per personalizzare il display. Puoi anche personalizzare sempre l'icona se invii il messaggio dalle API HTTP / XMPP.


1
@Ian Barber: hai intenzione di cambiare questo comportamento in Google nel prossimo futuro?
skylve

1
Il team è a conoscenza del problema e sta lavorando a una soluzione.
Arthur Thompson,

1
Qualche aggiornamento a questo proposito? pensavo che avrei chiesto perché ci sono state circostanze in cui un ingegnere di Google ha semplicemente dimenticato di spingere la patch.
CQM,

7
Ah, ho capito che funziona con 9.8.0. Per aiutare gli altri, ricorda che l'icona della barra di stato deve essere conforme ai requisiti: developer.android.com/guide/practices/ui_guidelines/… . Il mio non lo ha fatto e, pertanto, Firebase ha come impostazione predefinita il bianco standard invece di utilizzare l'icona specificata nel manifest.
zaifrun,

3
Se ti capita di provare questo e scopri che l'icona è più piccola di altre notifiche, assicurati di utilizzare un disegno vettoriale (e non un png). Questo mi ha risolto.
Riper

35

Utilizzare un'implementazione del server per inviare messaggi al client e utilizzare il tipo di dati dei messaggi anziché il tipo di notifica dei messaggi.

Questo ti aiuterà a ottenere una richiamata onMessageReceivedindipendentemente dal fatto che l'app sia in background o in primo piano e puoi quindi generare la tua notifica personalizzata


2
Questa è la soluzione suggerita anche nei documenti di Firebase, puoi mostrare la notifica nel modo che preferisci se fai affidamento sul push di dati anziché sulla notifica.
corse

1
si, daccordo. questo dovrebbe essere contrassegnato come una risposta corretta. o la mia risposta qui sotto :)
Developine

3
No, non è possibile per le persone che devono mantenere la compatibilità con altri client / versioni legacy che prevedono una notifica.
Gabor,

Abbiamo in produzione app che prevedono già un tipo di notifica push e abbiamo esteso quel componente (complesso) di backend per aggiungere dati per i nuovi clienti. Ma non possiamo rimuovere il supporto per le versioni legacy della nostra app.
Gabor,

Oh sono d'accordo. Questo è un altro problema. Suggerirei di leggere attentamente i documenti prima di integrarli. Anche per testare accuratamente prima di rilasciare alla produzione. Il problema avrebbe potuto essere evitato se l'app fosse stata testata molto prima del lancio. Comunque, hai avuto qualcosa da imparare.
geekoraul,

9

atm stanno lavorando su quel problema https://github.com/firebase/quickstart-android/issues/4

quando si invia una notifica dalla console di Firebase viene utilizzata l'icona dell'app per impostazione predefinita e il sistema Android diventerà tale icona bianca fissa nella barra di notifica.

Se non sei soddisfatto di questo risultato, devi implementare FirebaseMessagingService e creare manualmente le notifiche quando ricevi un messaggio. Stiamo lavorando a un modo per migliorare questo, ma per ora è l'unico modo.

modifica: con SDK 9.8.0 aggiungi ad AndroidManifest.xml

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

come visualizzare il vassoio di notifica delle icone personalizzate in marshmallow
Harsha,

6

La mia soluzione è simile a quella di ATom, ma più facile da implementare. Non è necessario creare una classe che oscuri completamente FirebaseMessagingService, puoi semplicemente ignorare il metodo che riceve l'Intento (che è pubblico, almeno nella versione 9.6.1) e prendere le informazioni da visualizzare dagli extra. La parte "hacky" è che il nome del metodo è effettivamente offuscato e cambierà ogni volta che aggiorni Firebase SDK a una nuova versione, ma puoi cercarlo rapidamente ispezionando FirebaseMessagingService con Android Studio e cercando un metodo pubblico che richieda un Intento come unico parametro. Nella versione 9.6.1 si chiama zzm. Ecco come appare il mio servizio:

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

gcm.notification.title per il nome della chiave è sicuro al 100% per tutte le versioni?
pedroooo,

3

Basta impostare targetSdkVersion su 19. L'icona di notifica sarà colorata. Quindi attendi che Firebase risolva questo problema.


7
: D Wow, allora dov'è la lista degli effetti collaterali?
Eugen Pechanec,

@EugenPechanec sì, il compromesso è che potresti non essere in grado di utilizzare alcune API disponibili su 20+
benleung

3

C'è anche un modo brutto ma funzionante. Decompilare FirebaseMessagingService.class e modificarne il comportamento. Quindi basta inserire la classe nel pacchetto giusto nella tua app e dex usarla al posto della classe nella stessa libreria di messaggistica. È abbastanza facile e funzionante.

C'è un metodo:

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

Questo codice è dalla versione 9.4.0, il metodo avrà nomi diversi in versione diversa a causa dell'offuscamento.


3

se la tua app è in background l'icona di notifica sarà impostata sul metodo Ricezione messaggio ma se l'app è in primo piano l'icona di notifica sarà quella che hai definito su manifest

inserisci qui la descrizione dell'immagine


2

Sto attivando le mie notifiche dalla console FCM e tramite HTTP / JSON ... con lo stesso risultato.

Posso gestire il titolo, il messaggio completo, ma l'icona è sempre un cerchio bianco predefinito:

Schermata di notifica

Invece della mia icona personalizzata nel codice (setSmallIcon o setSmallIcon) o icona predefinita dall'app:

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

1
Fatto! i miei tag <service> sono fuori dal tag <application> in AndroidManifest.xml Qui ho caldo la risposta stackoverflow.com/a/37352142/6366150
Gonzalo

Funziona solo con l'app in primo piano in esecuzione ... in background continua a ottenere lo stesso comportamento precedente
Gonzalo

quando l'app in primo piano quell'icona di notifica personalizzata sta arrivando e funziona bene ma sullo sfondo dell'app ottenere l'icona quadrata bianca per favore aiutatemi
Harsha

1

Scrivi questo

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

proprio in basso <application.....>

inserisci qui la descrizione dell'immagine


0

Ho pensato di aggiungere una risposta a questo, poiché il mio problema era semplice ma difficile da notare. In particolare, durante la creazione di my avevo copiato / incollato un elemento meta-dati esistente com.google.firebase.messaging.default_notification_icon, che utilizzava un android:valuetag per specificarne il valore. Questo non funzionerà per l'icona di notifica e una volta che l'ho cambiato in android:resourcetutto ha funzionato come previsto.


Lo stesso vale per il default_notification_colormeta, deve essere android:resourceun'impostazione, poiché android:valuenon funzionerà
flochtililoch il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.