Firebase onMessageReceived nie jest wywoływany, gdy aplikacja działa w tle


232

Pracuję z Firebase i testuję wysyłanie powiadomień do mojej aplikacji z mojego serwera, gdy aplikacja jest w tle. Powiadomienie jest wysyłane pomyślnie, pojawia się nawet w centrum powiadomień urządzenia, ale kiedy pojawia się powiadomienie lub nawet po kliknięciu, metoda onMessageReceived w mojej usłudze FCMessagingService nigdy nie jest wywoływana.

Kiedy przetestowałem to, gdy moja aplikacja była na pierwszym planie, wywołano metodę onMessageReceived i wszystko działało dobrze. Problem występuje, gdy aplikacja działa w tle.

Czy to jest zamierzone zachowanie, czy jest sposób, aby to naprawić?

Oto moja usługa 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"));
        }
    }
}

Gdzie oprócz kodu json jest twój kod onTokenRefresh ? Czy ukończyłeś konfigurację Androida ?
Kato

4
Co masz na myśli powiadomienie? Ponadto mój kod onTokenRefresh znajduje się w mojej usłudze FirebaseInstanceID.
Cyogenos

Czy możesz opublikować przykładowy ładunek, który wysyłasz?
AL.


Możesz także sprawdzić ten wątek stackoverflow.com/questions/39046270/…
Md. Sajedul Karim

Odpowiedzi:


144

Działa to zgodnie z przeznaczeniem, powiadomienia są dostarczane do wywołania zwrotnego onMessageReceived tylko wtedy, gdy aplikacja jest na pierwszym planie. Jeśli aplikacja znajduje się w tle lub jest zamknięta, w centrum powiadomień jest wyświetlana wiadomość z powiadomieniem, a wszelkie dane z tej wiadomości są przekazywane do celu, który jest uruchamiany w wyniku stuknięcia powiadomienia przez użytkownika.

Możesz określić kliknięcie, aby wskazać zamiar, który powinien zostać uruchomiony po stuknięciu powiadomienia przez użytkownika. Główna aktywność jest używana, jeśli nie określono aktywności kliknięcia.

Po uruchomieniu zamiaru możesz użyć

getIntent().getExtras();

aby pobrać Zestaw, który zawierałby wszelkie dane wysłane wraz z powiadomieniem.

Więcej informacji na temat powiadomienia można znaleźć w dokumentacji .


6
Czy istnieje sposób, aby ustawić, click_actionkiedy korzystam z konsoli powiadomień Firebase?
Nii Laryea

6
ok, ale co, jeśli aplikacja zostanie zabita (brak pierwszego planu lub tła)?
michalu,

3
Ale jak wyłączyć powiadomienia o odrzuceniu przez użytkownika? Ponieważ jeśli użytkownik go odrzuci, oznacza to, że wszystkie dane zostaną pominięte ... Tak?
Aleksey Timoshchenko

4
Poprawny! Dlatego podczas wysyłania powiadomień do Androida danymi towarzyszącymi powinny być dane, które zwiększają komfort powiadomień. Nie powinny to być dane krytyczne dla aplikacji, używaj komunikatów danych dla danych potrzebnych aplikacji, nawet jeśli użytkownik odrzuci powiadomienie.
Arthur Thompson,

3
To nie jest do końca poprawne. Jeśli wiadomość zawiera tylko dane, a nie ładunek powiadomienia, wiadomość ZAWSZE zostanie dostarczona do onMessageReceive, jeśli aplikacja jest na pierwszym planie, czy nie.
JacksOnF1re

125

Usuń notificationpole całkowicie z żądania serwera. Wysyłaj tylkodata i obsługuj, w onMessageReceived()przeciwnym razie onMessageReceived()nie zostanie uruchomione, gdy aplikacja będzie działała w tle lub zostanie zabita.

Nie zapomnij podać "priority": "high"pola we wniosku o powiadomienie. Zgodnie z dokumentacją: wiadomości danych są wysyłane z normalnym priorytetem, więc nie docierają natychmiast; może to być również problem.

Oto, co wysyłam z serwera

{
  "data":{
    "id": 1,
    "missedRequests": 5
    "addAnyDataHere": 123
  },
  "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......",
  "priority": "high"
}

Możesz więc otrzymać swoje dane w onMessageReceived(RemoteMessage message)ten sposób .... powiedzmy, że muszę dostać identyfikator

Object obj = message.getData().get("id");
        if (obj != null) {
            int id = Integer.valueOf(obj.toString());
        }

9
Przekonałem się, że jeśli wyślę tylko wiadomość danych, aplikacja usunięta z menedżera zadań nie będzie mogła uzyskać powiadomienia. Czy jest to zamierzone zachowanie?
Prabhjot Singh

2
To było rozwiązanie dla mnie, aby otrzymywać wiadomości w tle!
Ray Hulha,

5
W aplikacji Oreo po zabiciu aplikacji funkcja onMessageReceived nie jest wywoływana. mam tylko ładunek z danymi. masz jakąkolwiek aktualizację?
Samir Mangroliya

2
Działa jak marzenie!
ssk

3
Bardzo cię kocham za tę odpowiedź: p
Ahmad Arslan

63

ta metoda handleIntent () została uznana za przestarzałą, więc obsługę powiadomienia można wykonać w następujący sposób:

  1. Stan pierwszego planu: Kliknięcie powiadomienia spowoduje przejście do oczekującej aktywności Intent, którą podajesz podczas tworzenia powiadomienia pro gramatycznie, ponieważ generalnie jest ono tworzone z ładunkiem danych powiadomienia.

  2. Tło / stan zabity - tutaj sam system tworzy powiadomienie na podstawie ładunku powiadomienia, a kliknięcie tego powiadomienia przeniesie Cię do działania uruchamiania aplikacji, w którym możesz łatwo pobrać dane zamiaru dowolną z metod cyklu życia.


Dziękuję Ci!!! Straciłem kilka dni na tym problemie i ten mnie uratował.
Igor Janković

naprawdę idealne rozwiązanie!
EduXavier

4
Zajmuję się logiką wyświetlania powiadomień w handleIntent (zamiar zamierzony), jednak gdy aplikacja jest w tle, wyświetlane są 2 powiadomienia, jedno utworzone przeze mnie i inne domyślnie zawierające całą wiadomość z powiadomienia.
Joyson

5
Wspaniale, ale nie widzę żadnego zastosowania OnMessageReceivedw tym przypadku!
Alaa AbuZarifa

8
Mam com.google.firebase: firebase-messaging: 11.6.2 & handleIntent jest teraz gotowy. Sprawdź stackoverflow.com/questions/47308155/…
Ronak Poriya

31

Oto bardziej jasne pojęcia na temat komunikatu bazy ogniowej. Znalazłem to od ich zespołu wsparcia.

Firebase ma trzy typy wiadomości :

Powiadomienia : Powiadomienie działa w tle lub na pierwszym planie. Gdy aplikacja działa w tle, powiadomienia są dostarczane na tacę systemową. Jeśli aplikacja jest na pierwszym planie, wiadomości są obsługiwane przez onMessageReceived()lub didReceiveRemoteNotificationoddzwaniane. Są to tak zwane komunikaty displayowe.

Wiadomości danych : na platformie Android wiadomości danych mogą działać w tle i na pierwszym planie. Komunikat danych będzie obsługiwany przez onMessageReceived (). Uwaga dotycząca konkretnej platformy brzmiałaby następująco: na Androidzie ładunek danych można odzyskać w celu, który posłużył do uruchomienia Twojej aktywności. Aby rozwinąć, jeśli tak "click_action":"launch_Activity_1", możesz odzyskać ten zamiar getIntent()tylko z Activity_1.

Wiadomości zawierające zarówno powiadomienia, jak i dane : w tle aplikacje odbierają ładunek powiadomień na pasku powiadomień i obsługują ładunek danych tylko wtedy, gdy użytkownik stuknie powiadomienie. Na pierwszym planie aplikacja otrzymuje obiekt wiadomości z dostępnymi obiema ładunkami. Po drugie, parametr klikalności jest często używany w treści powiadomienia, a nie w danych. Jeśli zostanie użyty wewnątrz ładunku danych, ten parametr będzie traktowany jako niestandardowa para klucz-wartość i dlatego konieczne będzie zaimplementowanie niestandardowej logiki, aby działał zgodnie z przeznaczeniem.

Ponadto zalecam użycie metody onMessageReceived (patrz Komunikat danych) w celu wyodrębnienia pakietu danych. Z twojej logiki sprawdziłem obiekt pakietu i nie znalazłem oczekiwanej zawartości danych. Oto odniesienie do podobnego przypadku, który może zapewnić większą przejrzystość.

Po stronie serwera powiadomienie firebase powinno mieć następujący format :

Strona serwera powinna wysłać obiekt „powiadomienia” . Brak obiektu „powiadomienia” w mojej TargetActivitywiadomości nie został użyty getIntent().

Poprawny format wiadomości podano poniżej:

{
 "data": {
  "body": "here is body",
  "title": "Title"
 },
"notification": {
  "body": "here is body",
  "title": "Title",
  "click_action": "YOUR_ACTION"
 },
 "to": "ffEseX6vwcM:APA91bF8m7wOF MY FCM ID 07j1aPUb"
}

Oto bardziej jasne pojęcia na temat komunikatu bazy ogniowej. Znalazłem to od ich zespołu wsparcia.

Aby uzyskać więcej informacji odwiedź mój ten wątek i ten wątek


3
warto wspomnieć, że „wiadomości danych” nie będą odbierane, jeśli urządzenie znajduje się w trybie głębokiego drzemki (wprowadzone w Androidzie 7.0). bądź ostrożny z nimi!
Sameer J

30

Miałem ten sam problem. Łatwiej jest używać „komunikatu danych” zamiast „powiadomienia”. Komunikat danych zawsze ładuje klasę onMessageReceived.

W tej klasie możesz dokonać własnego powiadomienia za pomocą narzędzia do tworzenia powiadomień.

Przykład:

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

7
Dzięki .. Zmieniłem kod serwera i używam „danych” zamiast „powiadomienia”, a teraz działa idealnie,
Mahesh Kavathiya,

5
@ Uruchom to tylko wtedy, gdy aplikacja jest na pierwszym planie, a nie w tle. czy możesz mi pomóc uruchomić to zdarzenie w obu przypadkach?
Anant Shah,

@AnantShah jak wygląda twój test POST na serwerze Firebase?
Koot

3
Istnieją trzy możliwe przypadki. 1) Aplikacja na pierwszym planie. 2) Aplikacja w tle. 3) Aplikacja nie działa. Jak mówisz, komunikat „dane” zostanie odebrany w pierwszych dwóch przypadkach, ale nie w trzecim przypadku, gdy aplikacja nie jest uruchomiona. Aby uwzględnić wszystkie trzy przypadki, musisz ustawić pole „powiadomienia” w wiadomości. (Również dobry pomysł, jeśli chcesz obsługiwać klientów iOS i Android)
Steve Moseley

1
Nawet jeśli aplikacja nie jest uruchomiona, nadal otrzymuję komunikat z serwera o otrzymanej funkcji. Zgadzam się z tobą, że lepiej jest używać „powiadomienia”, jeśli chcesz również wspierać iOS.
Koot

21

Zgodnie z dokumentacją Firebase Cloud Messaging - jeśli Aktywność jest na pierwszym planie, onMessageReceived zostanie wywołany. Jeśli Aktywność znajduje się w tle lub jest zamknięta, w centrum powiadomień wyświetlana jest wiadomość z powiadomieniem o aktywności programu uruchamiającego aplikacje. Możesz zadzwonić do niestandardowej aktywności po kliknięciu powiadomienia, jeśli aplikacja działa w tle, dzwoniąc do interfejsu usługi spoczynkowej w celu wysłania wiadomości do bazy ogniowej jako:

URL- https://fcm.googleapis.com/fcm/send

Metoda typu - POST

Header- Content-Type:application/json
Authorization:key=your api key

Nadwozie / Ładowność:

{ "notification": {
    "title": "Your Title",
    "text": "Your Text",
     "click_action": "OPEN_ACTIVITY_1" // should match to your intent filter
  },
    "data": {
    "keyname": "any value " //you can get this data as extras in your activity and this data is optional
    },
  "to" : "to_id(firebase refreshedToken)"
} 

Dzięki temu w swojej aplikacji możesz dodać poniższy kod w swojej działalności, aby się nazywać:

<intent-filter>
                <action android:name="OPEN_ACTIVITY_1" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

Gdzie miałbym stworzyć zamiar i pozwolić mu otworzyć określone działanie? Wiem, że rejestruje to zamiar OPEN_ACTIVITY_1 w manifeście, ale gdzie tak naprawdę to nazywam?
Cyogenos


Czy powinniśmy wywoływać aktywność z filtrów zamiarów? Lub uruchomić go ręcznie onMessageReceived?
CoolMind

14

Metoda onMessageReceived (RemoteMessage remoteMessage) wywoływana w oparciu o następujące przypadki.

  • Odpowiedź FCM Z powiadomieniem i blokiem danych :
{
  
"to": "device token list",
  "notification": {
    "body": "Body of Your Notification",
    "title": "Title of Your Notification"
  },
  "data": {
    "body": "Body of Your Notification in Data",
    "title": "Title of Your Notification in Title",
    "key_1": "Value for key_1",
    "image_url": "www.abc.com/xyz.jpeg",
    "key_2": "Value for key_2"
  }
}
  1. Aplikacja na pierwszym planie:

Wywołano onMessageReceived (RemoteMessage remoteMessage) , pokazuje LargeIcon i BigPicture na pasku powiadomień. Możemy odczytać treść zarówno z powiadomienia, jak i bloku danych

  1. Aplikacja w tle:

Nie wywołano onMessageReceived (RemoteMessage remoteMessage) , taca systemowa otrzyma komunikat i odczyta treść i tytuł z bloku powiadomień oraz wyświetli domyślną wiadomość i tytuł na pasku powiadomień.

  • Odpowiedź FCM Tylko z blokiem danych :

W takim przypadku usunięcie bloków powiadomień z json

{
  
"to": "device token list",
  "data": {
    "body": "Body of Your Notification in Data",
    "title": "Title of Your Notification in Title",
    "key_1": "Value for key_1",
    "image_url": "www.abc.com/xyz.jpeg",
    "key_2": "Value for key_2"
  }
}

Rozwiązanie do wywoływania onMessageReceived ()

  1. Aplikacja na pierwszym planie:

Wywołano onMessageReceived (RemoteMessage remoteMessage) , pokazuje LargeIcon i BigPicture na pasku powiadomień. Możemy odczytać treść zarówno z powiadomienia, jak i bloku danych

  1. Aplikacja w tle:

Wywołano onMessageReceived (RemoteMessage remoteMessage) , taca systemowa nie otrzyma komunikatu, ponieważ klucz powiadomienia nie jest w odpowiedzi. Pokazuje LargeIcon i BigPicture na pasku powiadomień

Kod

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


}

Link referencyjny:

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


Najważniejszą częścią dla osób cierpiących na problem z tłem jest usunięcie właściwości „powiadomienie” z JSON wysyłanego przez serwer. to rozwiązuje problem. Wielkie dzięki.
Ramy M. Mousa

13

Mam ten sam problem. Jeśli aplikacja jest na pierwszym planie - uruchamia moją usługę w tle, w której mogę aktualizować bazę danych na podstawie typu powiadomienia. Ale aplikacja przechodzi w tło - domyślna usługa powiadomień zadba o to, aby pokazać powiadomienie użytkownikowi.

Oto moje rozwiązanie do identyfikacji aplikacji w tle i uruchomienia usługi w tle,

public class FirebaseBackgroundService extends WakefulBroadcastReceiver {

  private static final String TAG = "FirebaseService";

  @Override
  public void onReceive(Context context, Intent intent) {
    Log.d(TAG, "I'm in!!!");

    if (intent.getExtras() != null) {
      for (String key : intent.getExtras().keySet()) {
        Object value = intent.getExtras().get(key);
        Log.e("FirebaseDataReceiver", "Key: " + key + " Value: " + value);
        if(key.equalsIgnoreCase("gcm.notification.body") && value != null) {
          Bundle bundle = new Bundle();
          Intent backgroundIntent = new Intent(context, BackgroundSyncJobService.class);
          bundle.putString("push_message", value + "");
          backgroundIntent.putExtras(bundle);
          context.startService(backgroundIntent);
        }
      }
    }
  }
}

W pliku manifest.xml

<receiver android:exported="true" android:name=".FirebaseBackgroundService" android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </receiver>

Przetestowałem to rozwiązanie w najnowszej wersji Androida 8.0. Dzięki


jak korzystać z tej klasy FirebaseBackgroundService? @Nagendra Badiganti

gdzie używać tego kodu klasa publiczna FirebaseBackgroundService rozszerza WakefulBroadcastReceiver @Nagendra Badiganti

utwórz klasę usługi w swoim pakiecie i zarejestruj się w pliku manifest.xml. Upewnij się, że masz filtr powiadomień. Ponieważ usługa uruchamia się dla każdego powiadomienia GCM.
Nagendra Badiganti

firebase.google.com/docs/cloud-messaging/android/… Idę za tym linkiem, muszę dodać tę klasę, aby otrzymywać powiadomienia. po prostu wysyłam pierwszą wiadomość z bazy ogniowej. Mówi, że została ukończona, ale nie otrzymała powiadomienia @Nagendra Badiganti

1
WakefulBroadcastReceiverjest przestarzałe od poziomu API 26.1.0.
Minoru

12

Jeśli aplikacja jest w trybie tła lub nieaktywne (zabity), i kliknij na powiadamianiu , należy sprawdzić, czy ładunek w LaunchScreen (w moim ekranie przypadek Launch MainActivity.java).

Więc w MainActivity.java na onCreate sprawdź Dodatki :

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

Jak mogę uzyskać tytuł powiadomienia, treść i dane?
Md.Tarikul Islam

1
Dzięki, to jest odpowiedź. @ Md.Tarikul Islam za pomocą onMessageReceived (), jak wspomniano w tym pytaniu.
felixwcf

7

Zastąp dla mnie handleIntentMetodę FirebaseMessageServiceprac.

tutaj kod w 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);
    }
}

i to jest Kod w Javie

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

Funkcja handleIntent () jest ostateczna
Ettore,

@Ettore Jak mogę wywołać funkcję handleIntent?
Hiroto,

Metoda jest wywoływana, gdy otrzymasz wiadomość od Firebase, ale nie możesz jej przesłonić, ponieważ metoda została uznana za ostateczną. (Firebase 11.6.0)
Ettore,

5

Domyślnie aplikacja Aktywność uruchamiania w tobie zostanie uruchomiona, gdy aplikacja będzie działała w tle i klikniesz powiadomienie, jeśli masz część danych z powiadomieniem, możesz obsłużyć ją w tej samej czynności w następujący sposób,

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

Jeśli nawiguję z mainActivity, w jaki sposób będzie działać powrót do konkretnej aktywności?
Mac_Play

@Uzair getIntent (). GetExtras () zawsze staje się zerowy, czy masz jakieś inne rozwiązanie? Kiedy aplikacja zaczyna się w tle, metoda onMessageReceived nie wywołuje
user2025187

3

Jeśli aplikacja jest domyślnie w tle powiadomienie Fire-base obsługuje powiadomienie. Ale jeśli chcemy niestandardowego powiadomienia, musimy zmienić stronę serwera, która jest odpowiedzialna za wysyłanie niestandardowych danych (ładunek danych)

Całkowicie usuń ładunek powiadomienia z żądania serwera. Wysyłaj tylko dane i obsługuj je w onMessageReceived (), w przeciwnym razie twoja onMessageReceived nie zostanie uruchomiona, gdy aplikacja będzie działała w tle lub zostanie zabita.

teraz format kodu po stronie serwera wygląda,

{
  "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
  }
}

UWAGA : patrz ten wiersz w powyższym kodzie
„tekst”: „John Doe udostępnił kontakt w grupie Wymiana kontaktów” w ładunku danych należy użyć parametru „tekst” zamiast parametrów „treść” lub „wiadomość” do opisu wiadomości lub cokolwiek innego chcę użyć tekstu.

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

2

Po prostu wywołaj to w metodzie onCreate MainActivity:

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

Jeśli nawiguję z mainActivity, w jaki sposób będzie działać powrót do konkretnej aktywności?
Mac_Play

2

zgodnie z rozwiązaniem z t3h Exi chciałbym opublikować tutaj czysty kod. Wystarczy umieścić go w MyFirebaseMessagingService i wszystko działa dobrze, jeśli aplikacja jest w trybie tła. Musisz przynajmniej skompilować com.google.firebase: firebase-messaging: 10.2.1

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

Próbuję zaimplementować twoje rozwiązanie, ale metoda handleIntent () jest ostateczna w mojej wersji SDK (SDK 27), więc nie mogę zastąpić jej w mojej usłudze ...
matdev 15.01.2018

Tak, ale to nie moja wina ani żaden powód, aby dać -1 !!! Bardzo arogancki. Działa, dopóki Firebase 11.4.2, a następnie Google go zmieniło (sprawiło, że ta metoda jest ostateczna). Teraz musisz zaprogramować własne rozwiązanie z powiadomieniem.
Frank

Nie dałem -1, ale +1!
matdev

Zapisujesz moją pracę: P
amitabha2715

2

Spróbuj tego:

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

handleIntent nie jest już używany w bazie ogniowej: 11.8.0 i wyższej.
Shihab Uddin

1

Miałem ten problem (aplikacja nie chce się otwierać po kliknięciu powiadomienia, jeśli aplikacja jest w tle lub jest zamknięta), a problem był nieprawidłowy click_actionw ciele powiadomień, spróbuj usunąć lub zmienić go na coś ważnego.


1

Punktem, który zasługuje na wyróżnienie, jest to, że musisz użyć komunikatu danych - tylko klucz danych - - aby uzyskać wywołanie onMessageReceived, nawet gdy aplikacja jest w tle. Twój ładunek nie powinien mieć żadnego innego klucza powiadomienia, w przeciwnym razie program obsługi nie zostanie uruchomiony, jeśli aplikacja będzie działać w tle.

Jest wspomniany (ale nie tak podkreślony w dokumentacji FCM) tutaj:

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

Użyj serwera aplikacji i interfejsu API serwera FCM: Ustaw tylko klucz danych . Może być składany lub nierozkładalny.


1

Backend, z którym pracuję, używa komunikatów powiadomień, a nie danych. Więc po przeczytaniu wszystkich odpowiedzi próbowałem odzyskać dodatki z pakietu zamiarów, które przychodzą do rozpoczętej działalności. Ale bez względu na to, które klucze próbowałem odzyskaćgetIntent().getExtras(); , wartość była zawsze pusta.

Jednak w końcu znalazłem sposób na wysyłanie danych za pomocą powiadomień i odzyskanie ich z zamiarem.

Kluczem tutaj jest dodanie ładunku danych do komunikatu powiadomienia.

Przykład:

{
    "data": {
        "message": "message_body",
        "title": "message_title"
    },
    "notification": {
        "body": "test body",
        "title": "test title"
    },
    "to": "E4An.."
}

Po wykonaniu tej czynności będziesz w stanie uzyskać informacje w ten sposób:

intent.getExtras().getString("title") będzie message_title

i intent.getExtras().getString("message") będziemessage_body

Odniesienie


1

Jeśli twój problem jest związany z wyświetlaniem dużego obrazu, tj. Jeśli wysyłasz powiadomienie wypychane z obrazem z konsoli firebase i wyświetla ono obraz tylko wtedy, gdy aplikacja jest na pierwszym planie. Rozwiązaniem tego problemu jest wysłanie wiadomości push z samym polem danych. Coś takiego:

{ "data": { "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg", "message": "Firebase Push Message Using API" "AnotherActivity": "True" }, "to" : "device id Or Device token" }

straciłeś przecinek przed „AnotherActivity”. Mój Android wibruje, ale tak naprawdę nic się nie pokazuje (bez tekstu, bez obrazu, bez wypychania).
jekaby

1

Gdy wiadomość zostanie odebrana, a aplikacja jest w tle, powiadomienie zostanie wysłane do dodatkowej grupy docelowej głównej działalności.

Możesz sprawdzić dodatkową wartość w funkcji oncreate () lub onresume () głównej aktywności.

Możesz sprawdzić pola takie jak dane, tabela itp. (Te określone w powiadomieniu)

na przykład wysłałem używając danych jako klucza

public void onResume(){
    super.onResume();
    if (getIntent().getStringExtra("data")!=null){
            fromnotification=true;
            Intent i = new Intent(MainActivity.this, Activity2.class);
            i.putExtra("notification","notification");
            startActivity(i);
        }

}

0

Miałem ten sam problem i pogłębiłem tę sprawę. Gdy aplikacja jest w tle, powiadomienie jest wysyłane do zasobnika systemowego, ALE wiadomość z danymi jest wysyłana do onMessageReceived()
Patrz https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3
i https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java

Aby upewnić się, że wysyłana wiadomość, dokumenty mówią: „ Użyj serwera aplikacji i interfejsu API serwera FCM: Ustaw tylko klucz danych. Może być zwijany lub nieodwracalny.
Zobacz https://firebase.google.com/ docs / cloud-messaging / concept-options # notifications_and_data_messages


0

Istnieją dwa rodzaje wiadomości: powiadomienia i komunikaty danych. Jeśli wysyłasz tylko wiadomość danych, to znaczy, że w ciągu wiadomości nie ma obiektu powiadomienia. Zostanie wywołany, gdy aplikacja będzie działać w tle.


0

Sprawdź odpowiedź @Mahesh Kavathiya. W moim przypadku w kodzie serwera jest tylko tak:

{
"notification": {
  "body": "here is body",
  "title": "Title",
 },
 "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
}

Musisz zmienić na:

{
 "data": {
  "body": "here is body",
  "title": "Title",
  "click_action": "YOUR_ACTION"
 },
"notification": {
  "body": "here is body",
  "title": "Title"
 },
 "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
}

Następnie, w przypadku aplikacji w tle, domyślna zamiar działania dodatkowo otrzyma „dane”

Powodzenia!


-1

Po prostu zastąp metodę OnCreate FirebaseMessagingService. Jest wywoływany, gdy aplikacja jest w tle:

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

Ta odpowiedź może być bardziej przydatna, jeśli możesz dodać wyjaśnienie i link do dokumentacji. Czy możesz nam powiedzieć, jak to ma pomóc?
kilokahn

@kilokahn Czy możesz mi wyjaśnić, czego nie rozumiesz? wskazana metoda musi zostać wstawiona do kodu, który jest częścią pytania i w pełni odpowiada na pytanie. Kod dotyczy Xamarina, ale możesz po prostu przekonwertować w Javie.
Renzo Ciot

AFAIK Oficjalna dokumentacja ( firebase.google.com/docs/cloud-messaging/android/client ) nie mówi o nadpisywaniu OnCreate w usłudze rozszerzającej FirebaseMessagingService - jeśli masz dostęp do dokumentacji, która ma, może możesz udostępnić link? Z odpowiedzi nie wynika również, w jaki sposób zastąpienie funkcji onCreate rozwiązuje problem braku wywołania funkcji onMessageReceived po kliknięciu powiadomienia - stąd prośba o dodatkowe informacje.
kilokahn

Dokumentacja nie wspomina o zastąpieniu metody OnCreate, ale działa, ponieważ używam jej w środowisku produkcyjnym. Kod, który chcesz wstawić do metody onMessageReceived i który oczywiście służy do wykonywania niektórych operacji w tle, można wykonać na OnCreate.
Renzo Ciot

W takim przypadku wyjaśnienie, że jakoś to zadziałało, może okazać się bardziej pomocne niż tylko podanie rozwiązania. Ponadto nieudokumentowane zachowanie może arbitralnie przestać działać z aktualizacjami, a osoba korzystająca z nich musi być przygotowana do przerobienia swojego kodu, gdy to zrobi. Zastrzeżenie to należy złożyć.
kilokahn

-1

Istnieją 2 rodzaje z Firebase push-powiadomień:

1- Komunikat powiadomienia (Wyświetl komunikat) -> - 1.1 Jeśli wybierzesz ten wariant, system operacyjny utworzy dla siebie powiadomienie, jeśli aplikacja jest w tle, i przekaże dane dointent . Następnie klient musi zająć się tymi danymi.

- 1,2 Jeśli aplikacja jest w pierwszym planie następnie zgłoszeniu zostanie ona odebrana przez callback-functionwFirebaseMessagingService i to do klienta, aby go obsłużyć.

2- Wiadomości z danymi (do 4k danych) -> Te wiadomości są używane do wysyłania tylko danych do klienta (po cichu) i do klienta należy obsługa danych w obu przypadkach w tle / na pierwszym planie za pomocą funkcji wywołania zwrotnego w FirebaseMessagingService

Jest to zgodne z oficjalnymi dokumentami: https://firebase.google.com/docs/cloud-messaging/concept-options

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.