android - receive - handle intent firebase




Firebase onMessageReceived não é chamado quando o app está em segundo plano (16)

Apenas chame isso no método onCreate da sua MainActivity:

 @Override
public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }



           onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}

Estou trabalhando com o Firebase e testando o envio de notificações ao meu aplicativo do meu servidor enquanto o aplicativo está em segundo plano. A notificação é enviada com sucesso, ela até aparece no centro de notificações do dispositivo, mas quando a notificação é exibida ou mesmo se eu clicar nela, o método onMessageReceived dentro do meu FCMessagingService nunca é chamado.

Quando testei isso enquanto meu aplicativo estava em primeiro plano, o método onMessageReceived foi chamado e tudo funcionou bem. O problema ocorre quando o aplicativo está sendo executado em segundo plano.

Isso é um comportamento pretendido ou há uma maneira de corrigir isso?

Aqui está o meu FBMessagingService:

import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class FBMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i("PVL", "MESSAGE RECEIVED!!");
        if (remoteMessage.getNotification().getBody() != null) {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getNotification().getBody());
        } else {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getData().get("message"));
        }
    }
}

Basta substituir o método OnCreate do FirebaseMessagingService. É chamado quando seu aplicativo está em segundo plano:

public override void OnCreate()
{
    // your code
    base.OnCreate();
}

Esse método handleIntent () foi depreciado, portanto, a manipulação de uma notificação pode ser feita conforme abaixo:

  1. Estado do primeiro plano: o clique da notificação irá para a atividade da intenção pendente que você está fornecendo ao criar uma notificação de forma gramatical, como geralmente criada com carga de dados da notificação.

  2. Background / Killed State - Aqui, o próprio sistema cria uma notificação com base na carga útil da notificação e, ao clicar nessa notificação, você será levado para a atividade de inicialização do aplicativo, onde poderá buscar facilmente os dados do Intent em qualquer um dos seus métodos de ciclo de vida.


Eu estava tendo o mesmo problema e fiz um pouco mais sobre isso. Quando o aplicativo está em segundo plano, uma mensagem de notificação é enviada para a bandeja do sistema, MAS uma mensagem de dados é enviada para onMessageReceived()
Consulte https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3
e https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java

Para garantir que a mensagem que você está enviando, os documentos dizem: " Use seu servidor de aplicativos e API do servidor FCM: defina apenas a chave de dados. Pode ser recolhível ou não recolhível " .
Consulte https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages


Eu tive esse problema (o aplicativo não deseja abrir a notificação se o aplicativo estiver em segundo plano ou fechado), e o problema for um click_action inválido no corpo da notificação, tente removê-lo ou alterá-lo para algo válido.


Eu tive o mesmo problema. É mais fácil usar a 'mensagem de dados' em vez da 'notificação'. A mensagem de dados sempre carrega a classe onMessageReceived.

Nessa classe você pode fazer sua própria notificação com o construtor de notificações.

Exemplo:

 @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        sendNotification(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"));
    }

    private void sendNotification(String messageTitle,String messageBody) {
        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_UPDATE_CURRENT);

        long[] pattern = {500,500,500,500,500};

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

        NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setVibrate(pattern)
                .setLights(Color.BLUE,1,1)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

Existem dois tipos de mensagens: mensagens de notificação e mensagens de dados. Se você enviar apenas uma mensagem de dados, isto é, sem objeto de notificação em sua sequência de mensagens. Ele seria invocado quando seu aplicativo estivesse em segundo plano.


Isso está funcionando conforme o esperado, as mensagens de notificação são entregues ao seu retorno de chamada onMessageReceived somente quando seu aplicativo está em primeiro plano. Se o seu aplicativo estiver em segundo plano ou fechado, uma mensagem de notificação será mostrada no centro de notificações, e todos os dados dessa mensagem serão transmitidos para a intenção que é lançada como resultado do usuário tocar na notificação.

Você pode especificar um click_action para indicar a intenção que deve ser iniciada quando a notificação é tocada pelo usuário. A atividade principal é usada se nenhum click_action for especificado.

Quando a intenção é lançada você pode usar o

getIntent().getExtras();

para recuperar um Conjunto que incluiria todos os dados enviados junto com a mensagem de notificação.

Para mais informações sobre a mensagem de notificação, consulte os docs .


O ponto que merece destaque é que você precisa usar a mensagem de dados - chave de dados apenas - para obter o manipulador onMessageReceived chamado mesmo quando o aplicativo estiver em segundo plano. Você não deve ter nenhuma outra chave de mensagem de notificação em sua carga, caso contrário, o manipulador não será acionado se o aplicativo estiver em segundo plano.

É mencionado (mas não tão enfatizado na documentação do FCM) aqui:

https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

Use seu servidor de aplicativos e a API do servidor FCM: defina somente a chave de dados . Pode ser dobrável ou não dobrável.


Por padrão, o Launcher Activity em seu aplicativo será iniciado quando seu aplicativo estiver em segundo plano e você clicar na notificação. Se você tiver alguma parte de dados com sua notificação, poderá manipulá-la na mesma atividade, conforme a seguir.

if(getIntent().getExtras()! = null){
  //do your stuff
}else{
  //do that you normally do
}

Se o aplicativo estiver no fundo Base de fogo por padrão, notificação de manuseio Mas se quisermos nossa notificação personalizada, temos que mudar o lado do nosso servidor, que é responsável por enviar nossos dados personalizados (carga útil de dados)

Remova a carga de notificação completamente da sua solicitação do servidor. Envie apenas dados e processe-os em onMessageReceived (), caso contrário, seu onMessageReceived não será acionado quando o aplicativo estiver em segundo plano ou inativo.

Agora, seu formato de código do lado do servidor é semelhante,

{
  "collapse_key": "CHAT_MESSAGE_CONTACT",
  "data": {
    "loc_key": "CHAT_MESSAGE_CONTACT",
    "loc_args": ["John Doe", "Contact Exchange"],
    "text": "John Doe shared a contact in the group Contact Exchange",
    "custom": {
      "chat_id": 241233,
      "msg_id": 123
    },
    "badge": 1,
    "sound": "sound1.mp3",
    "mute": true
  }
}

NOTA : veja esta linha no código acima
"text": "John Doe compartilhou um contato no grupo Contact Exchange" em Data payload, você deve usar o parâmetro "text" em vez dos parâmetros "body" ou "message" para a descrição da mensagem ou qualquer coisa que você queira usar.

onMessageReceived ()

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.e(TAG, "From: " + remoteMessage.getData().toString());

        if (remoteMessage == null)
            return;

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
           /* Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());*/
            Log.e(TAG, "Data Payload: " + remoteMessage);

            try {

                Map<String, String> params = remoteMessage.getData();
                JSONObject json = new JSONObject(params);
                Log.e("JSON_OBJECT", json.toString());


                Log.e(TAG, "onMessageReceived: " + json.toString());

                handleDataMessage(json);
            } catch (Exception e) {
                Log.e(TAG, "Exception: " + e.getMessage());
            }
        }
    }

Se o aplicativo estiver no modo de segundo plano ou inativo (morto) e você clicar em Notificação , deverá verificar a carga útil no LaunchScreen (no meu caso, a tela de inicialização é MainActivity.java).

Então, em MainActivity.java em onCreate check for Extras :

    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("MainActivity: ", "Key: " + key + " Value: " + value);
        }
    }

Substituir o método handleIntent do FirebaseMessageService funciona para mim.

aqui o código em C # (Xamarin)

public override void HandleIntent(Intent intent)
{
    try
    {
        if (intent.Extras != null)
        {
            var builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            foreach (string key in intent.Extras.KeySet())
            {
                builder.AddData(key, intent.Extras.Get(key).ToString());
            }

            this.OnMessageReceived(builder.Build());
        }
        else
        {
            base.HandleIntent(intent);
        }
    }
    catch (Exception)
    {
        base.HandleIntent(intent);
    }
}

e isso é o código em Java

public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }

            onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}

Tente isto:

 private void sendNotification(Bitmap bitmap,  String title, String 
    message, PendingIntent resultPendingIntent) {

    NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
    style.bigPicture(bitmap);

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

    NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    String NOTIFICATION_CHANNEL_ID = mContext.getString(R.string.default_notification_channel_id);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);

        notificationManager.createNotificationChannel(notificationChannel);
    }
    Bitmap iconLarge = BitmapFactory.decodeResource(mContext.getResources(),
            R.drawable.mdmlogo);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.drawable.mdmlogo)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(defaultSound)
            .setContentText(message)
            .setContentIntent(resultPendingIntent)
            .setStyle(style)
            .setLargeIcon(iconLarge)
            .setWhen(System.currentTimeMillis())
            .setPriority(Notification.PRIORITY_MAX)
            .setChannelId(NOTIFICATION_CHANNEL_ID);


    notificationManager.notify(1, notificationBuilder.build());


}

de acordo com a solução do t3h Exi gostaria de postar o código limpo aqui. Basta colocá-lo em MyFirebaseMessagingService e tudo funciona bem se o aplicativo estiver em modo de segundo plano. Você precisa pelo menos compilar com.google.firebase: firebase-messaging: 10.2.1

public void handleIntent(Intent intent) {
    try {
        if (intent.getExtras() != null) {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            for (String key : intent.getExtras().keySet()) {
            builder.addData(key, intent.getExtras().get(key).toString());
        }
            onMessageReceived(builder.build());
        } else {
            super.handleIntent(intent);
        }
    } catch (Exception e) {
        super.handleIntent(intent);
    }
}

O método onMessageReceived (RemoteMessage remoteMessage) é chamado com base nos casos a seguir.

  • Resposta do FCM Com notificação e bloqueio de dados :

{" para ": "lista de tokens do dispositivo", " notificação ": {"corpo": "Corpo da sua notificação", "título": "Título da sua notificação"}, " dados ": {"corpo": "Corpo da sua notificação nos dados "," título ":" Título da sua notificação no título "," key_1 ":" Valor para a chave_1 "," image_url ":" www.abc.com/xyz.jpeg "," key_2 ": "Valor para key_2"}}

  1. App em primeiro plano:

onMessageReceived (RemoteMessage remoteMessage) chamado, mostra LargeIcon e BigPicture na barra de notificação. Podemos ler o conteúdo tanto da notificação quanto do bloco de dados

  1. App em segundo plano:

onMessageReceived (RemoteMessage remoteMessage) não chamado, a bandeja do sistema receberá a mensagem e lerá o corpo e o título do bloco de notificação e mostrará a mensagem e o título padrão na barra de notificação.

  • Resposta do FCM Com apenas o bloco de dados :

Nesse caso, removendo blocos de não- notificação do json

{" para ": "lista de tokens do dispositivo", " dados ": {"corpo": "Corpo da sua notificação nos dados", "título": "Título da sua notificação no título", "key_1": "Valor da chave_1 "," image_url ":" www.abc.com/xyz.jpeg "," key_2 ":" Valor para key_2 "}}

  1. App em primeiro plano:

onMessageReceived (RemoteMessage remoteMessage) chamado, mostra LargeIcon e BigPicture na barra de notificação. Podemos ler o conteúdo tanto da notificação quanto do bloco de dados

  1. App em segundo plano:

onMessageReceived (RemoteMessage remoteMessage) chamado, a bandeja do sistema não receberá a mensagem porque a chave de notificação não está na resposta. Mostra LargeIcon e BigPicture na barra de notificação

Código

if (getIntent().getExtras() != null) {
           // Call your NotificationActivity here..
            Intent intent = new Intent(MainActivity.this, NotificationActivity.class);
            startActivity(intent);
        }

Link de referência:

https://firebase.google.com/docs/cloud-messaging/android/receive





firebase-cloud-messaging