Ícone de notificação com o novo sistema Firebase Cloud Messaging

132

Ontem, o Google apresentou no Google I / O o novo sistema de notificação baseado no novo Firebase. Eu tentei esse novo FCM (Firebase Cloud Messaging) com o exemplo no Github.

O ícone da notificação é sempre o ic_launcher, apesar de eu ter declarado um drawable específico

Por quê ? Aqui abaixo o código oficial para lidar com a mensagem

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
fonte
firebase tem nada a ver com a forma como você está criando a notificação, por favor fornecer uma imagem, como o que você está vendo
tyczj
1
exato. esse código vem diretamente do Firebase e o método sendNotification () é exatamente o mesmo para qualquer notificação. Esse código funciona bem com o GCM, mas com o FCM no. ela permanece sempre ic_launcher, usando a nova interface web para enviar mensagens
marco
você definir o ícone pequeno, mas não o ícone grande, a menos que você está enviando um empurrão com a tag notificação na carga de pressão não tem nada a ver com FCM
tyczj
Ele mostra seu ícone de notificação personalizado quando o aplicativo está em primeiro plano? Isso funciona para mim. No entanto, quando o aplicativo está em segundo plano, ele deve usar algum tipo de manipulador FCM padrão, pois todas as configurações de notificação são ignoradas (ícone, som, luzes, vibração etc. não podem ser personalizados).
Brightpenguin 19/05/19

Respostas:

267

Infelizmente, essa foi uma limitação das notificações do Firebase no SDK 9.0.0-9.6.1. Quando o aplicativo está em segundo plano, o ícone do iniciador é usado no manifesto (com a coloração necessária do Android) para mensagens enviadas do console.

No entanto, com o SDK 9.8.0, você pode substituir o padrão! No seu AndroidManifest.xml, você pode definir os seguintes campos para personalizar o ícone e a cor:

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

Observe que, se o aplicativo estiver em primeiro plano (ou uma mensagem de dados for enviada), você poderá usar completamente sua própria lógica para personalizar a exibição. Você também pode sempre personalizar o ícone se estiver enviando a mensagem das APIs HTTP / XMPP.

Ian Barber
fonte
1
@ Ian Barber: algum plano do Google para mudar esse comportamento no futuro próximo?
Skylve #
1
A equipe está ciente do problema e está trabalhando em uma correção.
Arthur Thompson
1
alguma atualização disso? pensei em perguntar porque houve circunstâncias em que um engenheiro do Google simplesmente esqueceu de empurrar o patch.
CQM
7
Ah, eu consegui trabalhar com a 9.8.0. Para ajudar outras pessoas, lembre-se de que o ícone da barra de status deve atender aos requisitos: developer.android.com/guide/practices/ui_guidelines/… . O meu não foi, portanto, o firebase apenas padronizou para o quadrado branco padrão em vez de usar o ícone especificado no manifesto.
zaifrun
3
Se você tentar isso e achar que o ícone é menor que outras notificações, verifique se está usando um desenho vetorial (e não um png). Isso resolveu para mim.
maduras
35

Use uma implementação de servidor para enviar mensagens ao seu cliente e use o tipo de dados de mensagens em vez do tipo de notificação de mensagens.

Isso ajudará você a obter um retorno de chamada onMessageReceivedindependentemente de seu aplicativo estar em segundo plano ou em primeiro plano, e você poderá gerar sua notificação personalizada.

geekoraul
fonte
2
Essa é a solução sugerida nos documentos do Firebase também. Você pode mostrar a notificação da maneira que preferir, se confiar no envio de dados em vez da notificação.
corre
1
sim, concordo. isso deve ser marcado como uma resposta correta. ou minha resposta abaixo :)
Developine
3
Não, não é viável para pessoas que precisam manter a compatibilidade com outros clientes / versões herdadas que esperam uma notificação.
Gabor
Temos aplicativos em produção que já esperam um tipo de notificação por push e estendemos esse componente de back-end (complexo) para adicionar dados para novos clientes. Mas não podemos remover o suporte para versões herdadas do nosso aplicativo.
Gabor
Oh, eu concordo. Esse é outro problema. Eu sugiro ler os documentos completamente antes de integrar. Também para testar minuciosamente antes de liberar para produção. O problema poderia ter sido evitado se o aplicativo fosse testado bem antes do lançamento. Enfim, você tinha algo a aprender.
geekoraul
9

atm eles estão trabalhando nessa questão https://github.com/firebase/quickstart-android/issues/4

quando você envia uma notificação a partir do console do Firebase, usa o ícone do aplicativo por padrão e o sistema Android torna esse ícone totalmente branco quando está na barra de notificação.

Se você não estiver satisfeito com esse resultado, implemente o FirebaseMessagingService e crie as notificações manualmente quando receber uma mensagem. Estamos trabalhando em uma maneira de melhorar isso, mas por enquanto essa é a única maneira.

edit: com o SDK 9.8.0, adicione ao AndroidManifest.xml

<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/my_favorite_pic"/>
Jan Hartwig
fonte
Como exibir personalizado ícone da bandeja de notificação no marshmallow
Harsha
6

Minha solução é semelhante à da ATom, mas mais fácil de implementar. Você não precisa criar uma classe que oculte completamente o FirebaseMessagingService, basta substituir o método que recebe o Intent (que é público, pelo menos na versão 9.6.1) e obter as informações a serem exibidas nos extras. A parte "hacky" é que o nome do método é realmente ofuscado e muda sempre que você atualizar o Firebase sdk para uma nova versão, mas você pode procurá-lo rapidamente inspecionando o FirebaseMessagingService com Android Studio e procurando um método público que utilize um Intent como o único parâmetro. Na versão 9.6.1, é chamado zzm. Veja como meu serviço se parece:

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
fonte
gcm.notification.title para o nome da chave é 100% seguro para todas as versões?
pedroooo
3

Basta definir targetSdkVersion como 19. O ícone de notificação será colorido. Aguarde o Firebase para corrigir esse problema.

rattisuk
fonte
7
: D Uau, então, onde está a lista de efeitos colaterais?
Eugen Pechanec
@EugenPechanec sim, o problema é que talvez você não consiga usar alguma API disponível em mais de 20 anos
benleung
3

Há também uma maneira feia, mas funcional. Descompile o FirebaseMessagingService.class e modifique seu comportamento. Em seguida, basta colocar a classe no pacote certo no seu aplicativo e dex usá-lo em vez da classe na própria biblioteca de mensagens. É bem fácil e funcional.

Existe um 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 é da versão 9.4.0, o método terá nomes diferentes em versões diferentes por causa da ofuscação.

Átomo
fonte
3

se o seu aplicativo estiver em segundo plano, o ícone de notificação será definido no método Receive da mensagem, mas se o aplicativo estiver em primeiro plano, o ícone de notificação será o que você definiu no manifesto

insira a descrição da imagem aqui

Ribeiro
fonte
2

Estou acionando minhas notificações do console do FCM e por meio de HTTP / JSON ... com o mesmo resultado.

Consigo lidar com o título, com a mensagem completa, mas o ícone é sempre um círculo branco padrão:

Captura de tela da notificação

Em vez do meu ícone personalizado no código (setSmallIcon ou setSmallIcon) ou no ícone padrão do aplicativo:

 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
fonte
1
Entendi! Meu <serviço> marcas estão fora da tag <application> em AndroidManifest.xml Aqui i quente a resposta stackoverflow.com/a/37352142/6366150
Gonzalo
Só funciona com primeiro plano aplicativo em execução ... no fundo ainda obter o mesmo comportamento anterior
Gonzalo
quando o aplicativo no forground que custume ícone de notificação está chegando nd funcionando bem, mas no fundo aplicativo recebendo ícone quadrado branco ajuda por favor me
Harsha
1

escreva isso

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

logo abaixo <application.....>

insira a descrição da imagem aqui

dmarquina
fonte
0

Pensei em acrescentar uma resposta a essa, já que meu problema era simples, mas difícil de notar. Em particular, eu copiei / colei um elemento de metadados existente ao criar meu com.google.firebase.messaging.default_notification_icon, que usou uma android:valuetag para especificar seu valor. Isso não funcionará para o ícone de notificação e, depois que eu o mudei, android:resourcetudo funcionou conforme o esperado.

Charles A.
fonte
O mesmo vale para a default_notification_colormeta, ela precisa ser uma android:resourceconfiguração - pois android:valuenão funcionará
flochtililoch 14/01