Jak obsługiwać powiadomienia, gdy aplikacja działa w tle w Firebase


426

Oto mój manifest

    <service android:name=".fcm.PshycoFirebaseMessagingServices">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

    <service android:name=".fcm.PshycoFirebaseInstanceIDService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

Gdy aplikacja jest w tle i nadchodzi powiadomienie, pojawia się domyślne powiadomienie i nie uruchamia mojego kodu onMessageReceived.

Oto mój onMessageReceivedkod. Wywołuje to, jeśli moja aplikacja działa na pierwszym planie, a nie gdy aplikacja działa w tle. Jak uruchomić ten kod, gdy aplikacja również działa w tle?

// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // 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.
    data = remoteMessage.getData();
    String title = remoteMessage.getNotification().getTitle();
    String message = remoteMessage.getNotification().getBody();
    String imageUrl = (String) data.get("image");
    String action = (String) data.get("action");
    Log.i(TAG, "onMessageReceived: title : "+title);
    Log.i(TAG, "onMessageReceived: message : "+message);
    Log.i(TAG, "onMessageReceived: imageUrl : "+imageUrl);
    Log.i(TAG, "onMessageReceived: action : "+action);

    if (imageUrl == null) {
        sendNotification(title,message,action);
    } else {
        new BigPictureNotification(this,title,message,imageUrl,action);
    }
}
// [END receive_message]

1
Jest napisany w zastępczej próbce onMessageReceived () , mówi druga linia komentarza Not getting messages here? See why this may be: goo.gl/39bRNJ . Rozwiązanie, podobnie jak poniższe odpowiedzi, można znaleźć w dokumentacji Wiadomości z ładunkami zarówno powiadomień, jak i danych
fllo

Krótko mówiąc, aby obudzić zabitą aplikację, należy zawsze wysyłać powiadomienie z obiektem danych, aby wywołać moduł obsługi klasy usługi powiadamiania FirebaseMessagingService.onMessageReceived () w aplikacji. Spróbuj także wysłać go nie z konsoli Firebase, ale opublikować go z innego miejsca (np. Usługa testowania online).
Zon

1
to rozwiązanie działało dla mnie stackoverflow.com/a/44150822/6632278 mam nadzieję, że pomoże. Powodzenia
Tony Barajas

what ".fcm." PshycoFirebaseMessagingServices jest w twoim zamyśle? Dostaję błąd, że klasa nie została znaleziona .. i nigdzie nie znalazłem, jaka jest ta pierwsza część parametru.
Éder Rocha Bezerra

Odpowiedzi:


660

1. Dlaczego tak się dzieje?

Istnieją dwa rodzaje komunikatów w FCM (Firebase Cloud Messaging):

  1. Wyświetlaj wiadomości : te komunikaty wywołują onMessageReceived()oddzwonienie tylko wtedy, gdy aplikacja jest na pierwszym planie
  2. Wiadomości danych : te wiadomości wyzwalają onMessageReceived()oddzwanianie, nawet jeśli aplikacja jest na pierwszym planie / w tle / zabita

UWAGA: Zespół Firebase nie opracował jeszcze interfejsu do wysyłania data-messagesna twoje urządzenia. Powinieneś użyć swojego serwera do wysyłania tego typu!



2. Jak to zrobić?

Aby to osiągnąć, musisz wykonać POSTżądanie na następujący adres URL:

POST https://fcm.googleapis.com/fcm/send

Nagłówki

  • Legenda: Content-Type , Wartość: application/json
  • Legenda: Authorization , Wartość: key=<your-server-key>

Treść za pomocą tematów

{
    "to": "/topics/my_topic",
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     }
}

Lub jeśli chcesz wysłać go do określonych urządzeń

{
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     },
    "registration_ids": ["{device-token}","{device2-token}","{device3-token}"]
}


UWAGA: Upewnij się, że nie dodajesz klucza JSON notification
UWAGA: Aby uzyskać klucz serwera, możesz go znaleźć w konsoli Firebase:Your project -> settings -> Project settings -> Cloud messaging -> Server Key

3. Jak obsługiwać powiadomienie push?

Oto jak radzisz sobie z otrzymaną wiadomością:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String myCustomKey = data.get("my_custom_key");

     // Manage data
}

4
Możesz wysłać klucze „dane” i „powiadomienie” w tym samym powiadomieniu, wykonując następujące czynności stackoverflow.com/a/42279260/2734021 :)
Daniel S.

15
Firebase team have not developed a UI to send data-messages to your devices, yet.Czy zmieniło się to w ubiegłym roku?
Hankrecords,

2
@Antonio In oreo po zabiciu aplikacji, onMessageReceived nie jest wywoływany. mam tylko ładunek z danymi. masz jakąkolwiek aktualizację?
Samir Mangroliya

63
Gdy aplikacja jest w tle onMessageReceived, nie zostaje wywołana i jest to poważny problem w FCM !!! Zaktualizuj również swoją odpowiedź.
Muhammad Babar,

2
Cóż, dla mnie wygląda na to, że dzieje się tak na niektórych urządzeniach z Androidem. Spędziłem godziny myśląc, że to prawdziwy problem, ale potem okazało się niczym. Więc radzę przetestować to na różnych urządzeniach. Nawet przetestowałem to na maszynie wirtualnej i dostałem powiadomienie, nawet gdy aplikacja została zabita. Mówię to tylko, aby oszczędzić komuś czas.
Tarek-Dev

158

Aby utworzyć bibliotekę firebase do wywoływania funkcji onMessageReceived () w następujących przypadkach

  1. Aplikacja na pierwszym planie
  2. Aplikacja w tle
  3. Aplikacja została zabita

nie wolno umieszczać klucza JSON „powiadomienie” w żądaniu API bazy ogniowej, ale zamiast tego należy użyć „danych”, patrz poniżej.

Następująca wiadomość nie wywoła funkcji onMessageReceived (), gdy aplikacja jest w tle lub została zabita, i nie można dostosować powiadomienia.

{
   "to": "/topics/journal",
   "notification": {
   "title" : "title",
   "text": "data!",
   "icon": "ic_notification"
    }
}

ale zamiast tego będzie to działać

{
  "to": "/topics/dev_journal",
   "data": {
       "text":"text",
       "title":"",
       "line1":"Journal",
       "line2":"刊物"
   }
} 

Zasadniczo wiadomość jest wysyłana w argumencie RemoteMessage wraz z obiektem danych jako Map, a następnie możesz zarządzać powiadomieniem w onMessageReceived jak we fragmencie tutaj

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();

     //you can get your text message here.
     String text= data.get("text");


     NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
        // optional, this is to make beautiful icon
             .setLargeIcon(BitmapFactory.decodeResource(
                                    getResources(), R.mipmap.ic_launcher))  
        .setSmallIcon(smallIcon)  //mandatory
      .......
    /*You can read more on notification here:
    https://developer.android.com/training/notify-user/build-notification.html
    https://www.youtube.com/watch?v=-iog_fmm6mE
    */
}

1
Czy można to osiągnąć za pomocą konsoli Firebase?
koder

@koder, niestety konsola Firebase nie obsługuje tego, musisz użyć narzędzia do wysłania żądania wiadomości post do bazy firebase, takiej jak curl lub listonosz (wtyczka chrome), interfejs API wiadomości firebase, zapoznaj się z dokumentem tutaj - firebase.google.com/docs / cloud-messaging / http-server-ref
Teerakiat Chitawattanarat

1
tego szukałem ponad dzień ... Dziękuję bardzo, że działało idealnie. i byłoby lepiej, gdybyś wyjaśnił, w jaki sposób można obsługiwać pary kluczowych par danych w funkcji onMessageReceived (), aby rozpocząć działanie z tymi wartościami.
Boopathi T

25
Twoja metoda działa poprawnie, gdy aplikacja działa w tle, jednak gdy aplikacja zostanie zabita, nie otrzymuję danych
Sanzhar,

8
Ten sam problem z Sanzhar. Jeśli aplikacja zostanie zabita, nie otrzymam żadnej wiadomości.
Giacomo M,

104

Wydaje mi się, że wszystkie odpowiedzi są niekompletne, ale wszystkie zawierają coś, co jest potrzebne do przetworzenia powiadomienia zawierającego dane, gdy aplikacja jest w tle.

Wykonaj następujące kroki, aby móc przetwarzać powiadomienia, gdy aplikacja będzie działać w tle.

1. Dodaj taki filtr intencji:

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

do działania, które chcesz przetworzyć dane powiadomienia.

  1. Wysyłaj powiadomienia w następnym formacie:

    { 
     "notification" : {
            "click_action" : ".MainActivity", 
            "body" : "new Symulti update !", 
            "title" : "new Symulti update !", 
            "icon" : "ic_notif_symulti" }, 
     "data": { ... },
     "to" : "c9Vaa3ReGdk:APA91bH-AuXgg3lDN2WMcBrNhJZoFtYF9" }

Kluczem jest tutaj dodać

"click_action" : ".MainActivity"

gdzie .MainActivity jest działaniem z filtrem intencji dodanym w kroku 1.

  1. Uzyskaj informacje o „danych” z powiadomienia w „onCreate” .MainActivity ”:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //get notification data info
        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
           //bundle must contain all info sent in "data" field of the notification
        }
    }

I to powinno być wszystko, co musisz zrobić. Mam nadzieję, że to komuś pomoże :)


5
To powinna być poprawna odpowiedź. Żaden dokument nie mówi nic o wymaganiu aktywności kliknięcia ORAZ filtru zamiaru, aby powiadomienie pojawiło się nawet w zasobniku. Oba są wymagane.
airowe

@airowe nie są wymagane do wyświetlenia powiadomienia
AlwaysConfused

Mam zarówno bloki danych, jak i powiadomienia, ale nie jestem w stanie odbierać danych w aktywności?
Ashwani,

3
Po prostu nie rozumiem, dlaczego nie jest to akceptowana odpowiedź. Bez aktywności click to po prostu nie zadziała. Uratowałem mój dzień
Arun Shankar

4
Dzięki za wsparcie @ArunShankar. Odpowiedź na zaakceptowaną odpowiedź padła 7 miesięcy przed moją i jest to dobra odpowiedź. Nie rozumiem, dlaczego nikt nie mówi o aktywności kliknięć i dlatego dodałem swoją odpowiedź. Bardzo się cieszę, że jest on bardzo przydatny dla wielu ludzi i właśnie to ma znaczenie na koniec dnia :)
Daniel S.

42

Zgodnie z dokumentacją bazy ogniowej w wysyłaniu za pomocą bazy ogniowej , istnieje 2 rodzaje ładunku:

  1. dane

    Ten parametr określa niestandardowe pary klucz-wartość ładunku wiadomości. Aplikacja klienta jest odpowiedzialna za przetwarzanie wiadomości danych. Wiadomości danych mają tylko niestandardowe pary klucz-wartość.

  2. powiadomienie

    Ten parametr określa wstępnie zdefiniowane, widoczne dla użytkownika pary klucz-wartość ładunku powiadomienia. FCM automatycznie wyświetla komunikat do urządzeń użytkowników końcowych w imieniu aplikacji klienckiej. Powiadomienia mają wstępnie zdefiniowany zestaw kluczy widocznych dla użytkownika.

Gdy jesteś na pierwszym planie, możesz pobrać dane do FCM za pomocą onMessageReceived () , możesz pobrać dane z ładunku danych .

data = remoteMessage.getData();
String customData = (String) data.get("customData");

Gdy jesteś w tle, FCM wyświetla powiadomienie w zasobniku systemowym na podstawie informacji z ładunku powiadomienia . Tytuł, wiadomość i ikona użyte do powiadomienia na pasku zadań pochodzą z ładunku powiadomienia .

{
  "notification": {
        "title" : "title",
        "body"  : "body text",
        "icon"  : "ic_notification",
        "click_action" : "OPEN_ACTIVITY_1"
       }
}

To powiadomienie jest używane, gdy chcesz automatycznie wyświetlać powiadomienia na pasku zadań, gdy aplikacja jest w tle. Aby otrzymywać dane powiadomień, gdy aplikacja jest w tle, należy dodać kliknięcie aktywności wewnątrz ładunku powiadomienia .

Jeśli chcesz otworzyć aplikację i wykonać określone działanie [w tle], ustaw kliknięcie aktywności w ładunku powiadomienia i zamapuj go na filtr celowy w działaniu, które chcesz uruchomić. Na przykład ustaw parametr kliknij aktywności na OPEN_ACTIVITY_1, aby wyzwolić filtr celowy, taki jak poniżej:

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

Umieść ten filtr intencji na swoim manifeście, w jednym z tagów aktywności. Po kliknięciu powiadomienia otworzy się aplikacja i przejdziesz bezpośrednio do czynności, którą zdefiniujesz za pomocą kliknięcia, w tym przypadku „OPEN_ACTIVTY_1”. Wewnątrz tej aktywności możesz uzyskać dane poprzez:

Bundle b = getIntent().getExtras();
String someData = b.getString("someData");

Korzystam z FCM dla mojej aplikacji na Androida i używam obu ładunków. Oto przykład JSON, którego używam:

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification",
    "click_action" : "OPEN_ACTIVITY_1"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}

„Umieść ten filtr intencji na swoim manifeście, wewnątrz tagu aplikacji.” nie można umieścić filtru zamiaru wewnątrz tagu aplikacji.
Kyrylo Zapylaiev

Twoje JSON nie pokazuje, dokąd idzie klawisz klikalności.
Josh

to nie jest poprawna odpowiedź? co to jest akcja kliknięcia n gdzie to się dzieje? ktoś powinien głosować lub to wyczyścić
rana

1
@ KyryloZapylaiev Po prostu poprawiam i aktualizuję odpowiedź: „Umieść ten filtr intencji na swoim manifeście, wewnątrz jednego z tagów aktywności”.
Dika

1
@Josh zaktualizowany i sformatowany. możesz to jeszcze raz sprawdzić
Dika

32

Według dokumentów

Obsługa wiadomości w aplikacji w tle

Gdy aplikacja działa w tle, system Android przekierowuje powiadomienia do paska zadań. Stuknięcie powiadomienia przez użytkownika domyślnie otwiera program uruchamiający aplikacje.

Obejmuje to wiadomości zawierające zarówno powiadomienia, jak i ładunek danych. W takich przypadkach powiadomienie jest dostarczane na tacę systemową urządzenia, a ładunek danych jest dostarczany jako dodatek do celu działania programu uruchamiającego.

Jeśli chcesz otworzyć aplikację i wykonać konkretną akcję, ustaw opcję Click kliknij opcję w powiadomieniu i przypisz ją do filtru zamiarów w Działaniu, które chcesz uruchomić. Na przykład ustaw parametr kliknij aktywności na OPEN_ACTIVITY_1, aby wyzwolić filtr celowy, taki jak poniżej:

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

Edytować :

Na podstawie tego wątku :

Nie można ustawić ładunku klikalności za pomocą konsoli Firebase. Możesz spróbować przetestować za pomocą polecenia curl lub niestandardowego serwera HTTP

curl --header "Authorization: key=<YOUR_KEY_GOES_HERE>" 
     --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send  
     -d "{\"to\":\"/topics/news\",\"notification\": 
         {\"title\": \"Click Action Message\",\"text\": \"Sample message\",
            \"click_action\":\"OPEN_ACTIVITY_1\"}}"

1
masz rację. przeczytałem dokumenty. ale jestem zdezorientowany, gdzie umieścić to w moim manifeście? muszę uruchomić kod na onMessageReceived w tym pliku Java, więc w tym celu, co powinienem zrobić?
Parth Patel

Nie można ustawić aplikacji tak, aby automatycznie wywoływała komunikat „Wiadomość”, gdy jest w tle. Zamiast tego musisz obsłużyć otrzymane zamiary i wezwać program obsługi do wywołania go. Być może najlepiej jest zaimplementować osobną klasę / metodę wywoływaną zarówno przez onMessageReveiced, jak i przez zamierzoną obsługę. Dodałem moduł obsługi do elementu onNewIntent głównej czynności i działa on dla mnie dobrze.
diidu

za późno, aby odpowiedzieć na pytania @Pathath Patel, ale może to pomoże komuś z tymi samymi problemami, spójrz na moją odpowiedź tutaj stackoverflow.com/a/42279260/2734021
Daniel S.

gdzie musiałem umieścić tę akcję? dla mojej działalności lub usługi Firebasemessage?
Mahdi

** w przypadku wielokrotnego przekierowywania powiadomień nie działa? przykład: jeśli mam trzy zawiadomienie od FCM w tle przy użyciu „click_action” Pierwsze zawiadomienie przekierowany pomyślnie, a następnie 2 zgłoszenie kliknij przekierowanie aktywność nie działa
prasanthMurugan

24

Działa od lipca 2019 r

Android compileSdkVersion 28, buildToolsVersion 28.0.3 i powiadamianie firebase: 19.0.1

Po wielu godzinach analizowania wszystkich innych pytań i odpowiedzi StackOverflow oraz próbowania niezliczonych przestarzałych rozwiązań, to rozwiązanie udało się wyświetlić powiadomienia w tych 3 scenariuszach:

- Aplikacja jest na pierwszym planie:
powiadomienie jest odbierane metodą onMessageReceived w mojej klasie MyFirebaseMessagingService

- Aplikacja została zabita (nie działa w tle): powiadomienie jest automatycznie wysyłane do tacy powiadomień przez FCM. Gdy użytkownik dotknie powiadomienia, aplikacja jest uruchamiana przez wywołanie aktywności, która ma w pliku manifest android.intent.category.LAUNCHER. Możesz pobrać część danych powiadomienia, używając getIntent (). GetExtras () w metodzie onCreate ().

- Aplikacja działa w tle: powiadomienie jest automatycznie wysyłane do tacy powiadomień przez FCM. Gdy użytkownik dotknie powiadomienia, aplikacja zostanie przeniesiona na pierwszy plan, uruchamiając działanie z manifestem android.intent.category.LAUNCHER. Ponieważ moja aplikacja ma launchMode = "singleTop" w tym działaniu, metoda onCreate () nie jest wywoływana, ponieważ jedno działanie tej samej klasy jest już utworzone, zamiast tego wywoływana jest metoda onNewIntent () tej klasy, a użytkownik otrzymuje część danych powiadomienie tam za pomocą intent.getExtras ().

Kroki: 1– Jeśli zdefiniujesz główną aktywność aplikacji w następujący sposób:

<activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:screenOrientation="portrait"
    android:launchMode="singleTop">
    <intent-filter>
        <action android:name=".MainActivity" />
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

2- dodaj te linie w metodzie onCreate () klasy MainActivity.class

Intent i = getIntent();
Bundle extras = i.getExtras();
if (extras != null) {
    for (String key : extras.keySet()) {
        Object value = extras.get(key);
        Log.d(Application.APPTAG, "Extras received at onCreate:  Key: " + key + " Value: " + value);
    }
    String title = extras.getString("title");
    String message = extras.getString("body");
    if (message!=null && message.length()>0) {
        getIntent().removeExtra("body");
        showNotificationInADialog(title, message);
    }
}

i te metody do tej samej klasy MainActivity.class:

@Override
public void onNewIntent(Intent intent){
    //called when a new intent for this class is created.
    // The main case is when the app was in background, a notification arrives to the tray, and the user touches the notification

    super.onNewIntent(intent);

    Log.d(Application.APPTAG, "onNewIntent - starting");
    Bundle extras = intent.getExtras();
    if (extras != null) {
        for (String key : extras.keySet()) {
            Object value = extras.get(key);
            Log.d(Application.APPTAG, "Extras received at onNewIntent:  Key: " + key + " Value: " + value);
        }
        String title = extras.getString("title");
        String message = extras.getString("body");
        if (message!=null && message.length()>0) {
            getIntent().removeExtra("body");
            showNotificationInADialog(title, message);
        }
    }
}


private void showNotificationInADialog(String title, String message) {

    // show a dialog with the provided title and message
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title);
    builder.setMessage(message);
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();
}

3- utwórz klasę MyFirebase w następujący sposób:

package com.yourcompany.app;

import android.content.Intent;
import android.util.Log;

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

public class MyFirebaseMessagingService extends FirebaseMessagingService {


    public MyFirebaseMessagingService() {
        super();
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        Log.d(Application.APPTAG, "myFirebaseMessagingService - onMessageReceived - message: " + remoteMessage);

        Intent dialogIntent = new Intent(this, NotificationActivity.class);
        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        dialogIntent.putExtra("msg", remoteMessage);
        startActivity(dialogIntent);

    }

}

4- utwórz nową klasę NotificationActivity.class w następujący sposób:

package com.yourcompany.app;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;

import com.google.firebase.messaging.RemoteMessage;

public class NotificationActivity extends AppCompatActivity {

private Activity context;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    context = this;
    Bundle extras = getIntent().getExtras();

    Log.d(Application.APPTAG, "NotificationActivity - onCreate - extras: " + extras);

    if (extras == null) {
        context.finish();
        return;
    }

    RemoteMessage msg = (RemoteMessage) extras.get("msg");

    if (msg == null) {
        context.finish();
        return;
    }

    RemoteMessage.Notification notification = msg.getNotification();

    if (notification == null) {
        context.finish();
        return;
    }

    String dialogMessage;
    try {
        dialogMessage = notification.getBody();
    } catch (Exception e){
        context.finish();
        return;
    }
    String dialogTitle = notification.getTitle();
    if (dialogTitle == null || dialogTitle.length() == 0) {
        dialogTitle = "";
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(context, R.style.myDialog));
    builder.setTitle(dialogTitle);
    builder.setMessage(dialogMessage);
    builder.setPositiveButton(getResources().getString(R.string.accept), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();

}

}

5- Dodaj te wiersze do manifestu aplikacji, wewnątrz swoich tagów

    <service
        android:name=".MyFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

    <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id"/>

    <activity android:name=".NotificationActivity"
        android:theme="@style/myDialog"> </activity>

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

6- dodaj te linie w metodzie Application.java onCreate () lub w metodzie MainActivity.class onCreate ():

      // notifications channel creation
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      // Create channel to show notifications.
      String channelId = getResources().getString("default_channel_id");
      String channelName = getResources().getString("General announcements");
      NotificationManager notificationManager = getSystemService(NotificationManager.class);
      notificationManager.createNotificationChannel(new NotificationChannel(channelId,
              channelName, NotificationManager.IMPORTANCE_LOW));
  }

Gotowy.

Teraz, aby działało to dobrze w 3 wymienionych scenariuszach, musisz wysłać powiadomienie z konsoli internetowej Firebase w następujący sposób:

W sekcji Powiadomienie: Tytuł powiadomienia = Tytuł do wyświetlenia w oknie powiadomień (opcjonalnie) Tekst powiadomienia = Wiadomość do pokazania użytkownikowi (wymagane) Następnie w sekcji Cel: Aplikacja = aplikacja na Androida oraz w sekcji Opcje dodatkowe: Kanał powiadomień na Androida = default_channel_id Niestandardowy klucz danych: wartość tytułu: (tutaj ten sam tekst niż w polu Tytuł sekcji Powiadomienie) klucz: wartość ciała: (ten sam tekst tutaj niż w polu Wiadomość w sekcji Powiadomienie) klucz: wartość aktywności click: .MainActivity Sound = Wyłączony
wygasa = 4 tygodnie

Możesz go debugować w emulatorze za pomocą API 28 z Google Play.

Miłego kodowania!


2
Dziękuję za tę wspaniałą odpowiedź.
Alex Chengalan,

@alvaro, jeśli chcę otworzyć adres URL po otrzymaniu powiadomienia, jak sobie z tym
poradzić

nie działa telefon przeciwny in vivo, gdy aplikacja jest zamknięta lub zabita
Android Developer

Nie próbowałem w telefonie Vivo, ale obecnie działa na wielu innych telefonach z Androidem. Proszę czytać powoli na każdym kroku, sprawdzać wszystkie szczegóły, a następnie włączyć punkty przerwania debugowania w pierwszym wierszu każdej z metod, o których tu wspomniałem, podłącz prawdziwy telefon do komputera programistycznego za pomocą kabla i debuguj aplikację podczas wysyłania wiadomość od FCM. Sprawdź, czy wysyłasz wiadomości FCM ze wszystkimi parametrami i formatem, o którym wspomniałem. Powodzenia!
alvaro,

2
To jest najbardziej aktualna odpowiedź, jak czytamy w dokumentacji Firebase: Gdy aplikacja jest w tle, Android kieruje powiadomienia do paska zadań. Stuknięcie powiadomienia przez użytkownika domyślnie otwiera program uruchamiający aplikacje. Obejmuje to wiadomości zawierające zarówno powiadomienia, jak i ładunek danych. W takich przypadkach powiadomienie jest dostarczane na tacę systemową urządzenia, a ładunek danych jest dostarczany jako dodatek do celu działania programu uruchamiającego. ( firebase.google.com/docs/cloud-messaging/android/… ) Tak wiele starych odpowiedzi jest nieaktualnych
Riot Goes Woof

20

Ponieważ te, display-messagesktóre są wysyłane z interfejsu powiadomień Firebase, działa tylko wtedy, gdy aplikacja jest na pierwszym planie. Dla data-messages, istnieje potrzeba, aby wykonać połączenie POST do FCM

Kroki

  1. Zainstaluj rozszerzenie Advanced Chrome dla klienta Google Rest wprowadź opis zdjęcia tutaj

  2. Dodaj następujące nagłówki

    Klucz : Content-Type, Value : application / json

    Klucz : autoryzacja, wartość : klucz = „klucz serwera” wprowadź opis zdjęcia tutaj

  3. Dodaj ciało

    • Jeśli używasz tematów:

      {
          "to" : "/topics/topic_name",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
          }
      }
    • Jeśli używasz identyfikatora rejestracji:

      {
          "registration_ids" : "[{"id"},{id1}]",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
           }
      }

Otóż ​​to!. Teraz słuchaj onMessageReceivedoddzwaniania jak zwykle.

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String value1 = data.get("key1");
     String value2 = data.get("key2");
}

20

Aby przechwycić wiadomość w tle, musisz użyć BroadcastReceiver

import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.legacy.content.WakefulBroadcastReceiver
import com.google.firebase.messaging.RemoteMessage

class FirebaseBroadcastReceiver : WakefulBroadcastReceiver() {

    val TAG: String = FirebaseBroadcastReceiver::class.java.simpleName

    override fun onReceive(context: Context, intent: Intent) {

        val dataBundle = intent.extras
        if (dataBundle != null)
            for (key in dataBundle.keySet()) {
                Log.d(TAG, "dataBundle: " + key + " : " + dataBundle.get(key))
            }
        val remoteMessage = RemoteMessage(dataBundle)
        }
    }

i dodaj to do swojego manifestu:

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

7
To naprawdę odbiera powiadomienie, gdy aplikacja jest w tle. Ale to nie powstrzymuje domyślnego odbiornika Firebase przed jego obsługą, więc wiadomość nadal jest wyświetlana jako alert powiadomienia.
Galya,

W tej chwili nie działa, dlatego proponuję to rozwiązanie. W bazie błędów Google jest zgłoszony błąd. Możesz to sprawdzić.
Romulano,

Czy mógłbyś zamieścić link do błędu tutaj
Galya

jak uzyskać dane z powiadomienia?
Ravi Vaghela,

To oczywiście nie działa, gdy aplikacja zostanie zabita. Próbowałem tego rozwiązania od wielu godzin. z jakiegoś powodu odbiornik działa, gdy aplikacja jest w tle i nie działa, gdy aplikacja zostanie zabita
XcodeNOOB,

16
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}

nie jest wywoływany za każdym razem, gdy jest wywoływany tylko wtedy, gdy aplikacja jest w polu

istnieje jedna metoda zastępowania, którą wywołuje się za każdym razem, bez względu na to, która aplikacja jest na pierwszym planie, w tle lub została zabita, ale ta metoda jest dostępna w tej wersji interfejsu API

to jest wersja, którą musisz zaimportować z poziomu

compile 'com.google.firebase:firebase-messaging:10.2.1'

to jest metoda

@Override
public void handleIntent(Intent intent) {
    super.handleIntent(intent);

    // you can get ur data here 
    //intent.getExtras().get("your_data_key") 


}

z poprzednim interfejsem firebase tej metody nie było, więc w tym przypadku sama podstawa uchwytu przeciwpożarowego, gdy aplikacja jest w tle .... teraz masz tę metodę, co chcesz zrobić ... możesz to zrobić tutaj w tej metodzie ... ...

jeśli używasz poprzedniej wersji, wówczas rozpocznie się domyślna aktywność. W takim przypadku możesz uzyskać dane w ten sam sposób

if(getIntent().getExtras() != null && getIntent().getExtras().get("your_data_key") != null) {
String strNotificaiton = getIntent().getExtras().get("your_data_key").toString();

// rób co chcesz ...}

generalnie jest to struktura z serwera, którą otrzymujemy w powiadomieniu

{
    "notification": {
        "body": "Cool offers. Get them before expiring!",
        "title": "Flat 80% discount",
        "icon": "appicon",
        "click_action": "activity name" //optional if required.....
    },
    "data": {
        "product_id": 11,
        "product_details": "details.....",
        "other_info": "......."
    }
}

od Ciebie zależy, jak chcesz podać ten klucz danych, czy chcesz powiadomić cokolwiek, co możesz dać ....... cokolwiek dasz tutaj z tym samym kluczem, otrzymasz te dane ........ .

istnieje kilka przypadków, gdy nie wysyłasz akcji kliknięcia w tym przypadku, gdy klikniesz powiadomienie, otworzy się domyślna aktywność, ale jeśli chcesz otworzyć swoją konkretną aktywność, gdy aplikacja jest w tle, możesz wywołać swoją aktywność z tej metody handleIntent, ponieważ to jest wywoływany za każdym razem


Zaktualizowałem komunikat Firebase do 10.2.1, dodałem dane do powiadomienia i zadziałało. Pierwszy plan, tło i zabity. Dzięki
Firas Shrourou

w Kotlin pojawia się błąd: (44, 5) „handleIntent” w „FirebaseMessagingService” jest ostateczny i nie można go zastąpić
ugali soft

Nie działa powyżej wersji
Firebase

14

Według dokumentów: 17 maja 2017 r

Gdy aplikacja działa w tle , system Android przekierowuje powiadomienia do paska zadań. Stuknięcie powiadomienia przez użytkownika domyślnie otwiera program uruchamiający aplikacje .

Obejmuje to wiadomości zawierające zarówno powiadomienia, jak i ładunek danych (oraz wszystkie wiadomości wysyłane z konsoli powiadomień). W takich przypadkach powiadomienie jest dostarczane na tacę systemową urządzenia, a ładunek danych jest dostarczany jako dodatek do celu działania programu uruchamiającego.

Dlatego należy użyć zarówno powiadomienia o ładunku, jak i danych:

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}

Nie ma potrzeby korzystania z klikalności. Powinieneś po prostu uzyskać egzaminy z zamiaru działania LAUNCHER

<activity android:name=".MainActivity">
        <intent-filter>
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

Kod Java powinien znajdować się w metodzie onCreate na MainActivity:

Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
    Bundle extras = intent.getExtras();
    String someData= extras.getString("someData");
    String someData2 = extras.getString("someData2");
}

Możesz przetestować oba powiadomienia o ładunku + dane z konsoli powiadomień Firebase . Nie zapomnij wypełnić niestandardowych pól danych w sekcji Opcje zaawansowane


13

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()lubdidReceiveRemoteNotification oddzwaniane. 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 pobrać w celu, który posłużył do uruchomienia Twojej aktywności. Aby to rozwinąć, jeśli masz "click_action":"launch_Activity_1", możesz pobrać tę intencję getIntent()tylko z Activity_1.

Wiadomości zawierające zarówno powiadomienia, jak i ładunki danych : 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,click_action parametr ten jest często używany w ładunku powiadomień, a nie w ładunku danych. Jeśli zostanie użyty wewnątrz ładunku danych, ten parametr będzie traktowany jako niestandardowa para klucz-wartość, a zatem konieczne będzie zaimplementowanie niestandardowej logiki, aby działał zgodnie z przeznaczeniem.

Ponadto zalecam użycie onMessageReceivedmetody (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ść.

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



8

Proste takie podsumowanie

  • jeśli Twoja aplikacja jest uruchomiona;

    onMessageReceived()

wyzwala.

  • jeśli Twoja aplikacja nie działa (zabita przez przeciągnięcie);

    onMessageReceived()

nie jest uruchamiany i dostarczany przez direclty. Jeśli masz jakąś parę kluczy klucz-wartość. Nie działają, ponieważ onMessageReceived () nie działa.

Znalazłem w ten sposób;

W działaniach związanych z uruchamianiem umieść tę logikę,

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState, R.layout.activity_splash);

    if (getIntent().getExtras() != null && getIntent().getExtras().containsKey("PACKAGE_NAME")) {

        // do what you want

        // and this for killing app if we dont want to start
        android.os.Process.killProcess(android.os.Process.myPid());

    } else {

        //continue to app
    }
}

w tym bloku if wyszukaj klucze zgodnie z interfejsem firebase.

W tym przykładzie mój klucz i wartość jak wyżej; (przepraszam za język =)) wprowadź opis zdjęcia tutaj

Kiedy mój kod działa, pojawia się „com.rda.note”.

android.os.Process.killProcess(android.os.Process.myPid());

za pomocą tego wiersza kodu zamknąłem aplikację i otworzyłem Google Play Market

szczęśliwego kodowania =)


6

Wymyśliłem scenariusze,

Gdy aplikacja jest w planie , onMessageReceived () wywoływana jest metoda z FirebaseService .so pendingIntent zdefiniowane w klasie usługi zostanie wywołana.

A gdy aplikacja jest w tle , wywoływana jest pierwsza aktywność .

Teraz, jeśli użyjesz działania splash , musisz pamiętać, że zostanie wywołana splashactivity, w przeciwnym razie, jeśli nie ma splashActivity, wówczas wywoływane będzie cokolwiek pierwsze działanie.

Następnie trzeba sprawdzić getIntent () z firstActivity aby zobaczyć, czy to ma jakieś zawiniątko .Jeżeli wszystko jest w porządku, widać wiązka jest tam z wartościami wypełnione. Jeśli wartość w znaczniku danych wysyłane z serwera wygląda jak ten,

"data": {
    "user_name": "arefin sajib",
    "value": "user name notification"
  }

Następnie w pierwszym działaniu zobaczysz, że istnieje poprawna intencja ( getIntent () nie ma wartości null ), ważny pakiet i wewnątrz pakietu, będzie cały JSON wspomniany powyżej z danymi jako kluczem .

W tym scenariuszu kod do wyodrębnienia wartości będzie wyglądał następująco:

    if(getIntent()!=null){
            Bundle bundle = getIntent().getExtras();
            if (bundle != null) {
                try {
                   JSONObject object = new JSONObject(bundle.getStringExtra("data"));
String user_name = object.optString("user_name");

                } catch (JSONException e) {
                    e.printStackTrace();
                }


            }
        }

3

Dziękuję wszystkim za odpowiedzi. Ale rozwiązałem ten problem, wysyłając wiadomość danych zamiast powiadomienia . Kod serwera

<?php
$url = "https://fcm.googleapis.com/fcm/send";
$token = "C-l6T_a7HouUK****";
$serverKey = "AAAAaOcKS00:********";
define( 'API_ACCESS_KEY', $serverKey );
$registrationIds = array($token);
// prep the bundle

$msg = array

(
 'message'  => 'here is a message. message',
 'title'        => 'This is a title. title',
 'subtitle' => 'This is a subtitle. subtitle',
 'tickerText'   => 'Ticker text here...Ticker text here...Ticker text 
 here',
 'vibrate'  => 1,
 'sound'        => 1,
 'largeIcon'    => 'large_icon',
 'smallIcon'    => 'small_icon'

);

$fields = array

(
  'registration_ids'    => $registrationIds,
  'data'            => $msg

);
$headers = array

(
  'Authorization: key=' . API_ACCESS_KEY,
 'Content-Type: application/json'

);


$ch = curl_init();

curl_setopt( $ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/send' 
);

curl_setopt( $ch,CURLOPT_POST, true );

curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );

curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );

curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );

curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );

$result = curl_exec($ch );

curl_close( $ch );

echo $result;

?>

I złapał dane w onMessageReceived

public class MyFirebaseMessagingService extends FirebaseMessagingService     {

  private static final String TAG = "MyFirebaseMsgService";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

      sendNotification(remoteMessage.getData().get("message"));
     }
   // Check if message contains a notification payload.
    else if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    sendNotification(remoteMessage.getNotification().getBody());
    }


}
   private void sendNotification(String messageBody) {
    Intent intent = new Intent(this, Notify.class).putExtra("msg",messageBody);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);

    String channelId = "idddd";
    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(MyFirebaseMessagingService.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle("FCM Message")
                    .setContentText(messageBody)
                    .setAutoCancel(true)
                    .setSound(defaultSoundUri)
                    .setContentIntent(pendingIntent);

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

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

1
czy działa również w tle?
Tabish khan

@Tabishkhan Tak bracie, to działa, jeśli masz jakiś problem, możesz mnie zapytać .. dzięki
Android Sanaullah

1
cześć @AndroidSanaullah, czy możesz wyjaśnić pierwszą część kodu serwera, gdzie właściwie go umieściłeś, mam do czynienia z tym samym problemem, ale nie do końca rozumiem część serwerową, czy używasz listonosza?
Shid

curl jest używany do żądania i wszystkie parametry są do niego przekazywane. @
Shid

2

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

Oto, co wysyłam z serwera:

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

Możesz więc otrzymać swoje dane w onMessageReceived(RemoteMessage message)następujący sposób: (powiedzmy, że muszę uzyskać identyfikator)

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

Podobnie możesz uzyskać wszelkie dane, które wysłałeś z serwera onMessageReceived().


2

Łatwy sposób wysyłania wiadomości, nawet jeśli aplikacja jest w tle i na pierwszym planie, w następujący sposób: - Aby wysłać wiadomość za pomocą interfejsu API, możesz użyć narzędzia o nazwie AdvancedREST Client, jego chromowanego rozszerzenia i wysłać wiadomość o następujących parametrach.

Reszta narzędzia klienta Link: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

użyj tego adresu URL: - https://fcm.googleapis.com/fcm/send Content-Type: application / json Autoryzacja: key = Twój klucz serwera From lub klucz autoryzacji (patrz poniżej ref)

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

Klucz autoryzacji można uzyskać, odwiedzając konsolę programistów Google i klikając przycisk Poświadczenia w menu po lewej stronie swojego projektu. Wśród wymienionych kluczy API klucz serwera będzie Twoim kluczem autoryzacyjnym.

I musisz umieścić identyfikator tokena odbiornika w sekcji „do” żądania POST wysłanego za pomocą interfejsu API.


2

chcesz pracować na onMessageReceived (RemoteMessage remoteMessage) w tle wyślij tylko część powiadomienia część danych to:

"data":    "image": "",    "message": "Firebase Push Message Using API", 

„AnotherActivity”: „True”, „to”: „identyfikator urządzenia lub token urządzenia”

Dzięki temu onMessageRecivied jest tłem połączenia i pierwszym planem, nie trzeba obsługiwać powiadomień za pomocą zasobnika powiadomień na temat działania programu uruchamiającego. Obsługa ładunku danych przy użyciu tego:

  public void onMessageReceived(RemoteMessage remoteMessage)
    if (remoteMessage.getData().size() > 0) 
    Log.d(TAG, "Message data payload: " + remoteMessage.getData());      

1

Czerwiec 2018 Odpowiedź -

Musisz upewnić się, że w wiadomości nie ma słowa kluczowego „powiadomienie”. Uwzględnij tylko „dane”, a aplikacja będzie w stanie obsłużyć wiadomość w onMessageReceived, nawet jeśli będzie w tle lub zostanie zabita.

Korzystanie z funkcji chmury:

const message = {
    token: token_id,   // obtain device token id by querying data in firebase
    data: {
       title: "my_custom_title",
       body:  "my_custom_body_message"
       }
    }


return admin.messaging().send(message).then(response => {
    // handle response
});

Następnie w twojej onMessageReceived (), w twojej klasie rozszerzającej com.google.firebase.messaging.FirebaseMessagingService:

if (data != null) {
  Log.d(TAG, "data title is: " + data.get("title");
  Log.d(TAG, "data body is: " + data.get("body");
}

// build notification using the body, title, and whatever else you want.

czy masz jakieś źródło, czy jest bezpieczne?
Yogesh Rathi

Jest bezpieczny, używam go w swoich aplikacjach. Jednak 6 miesięcy od opublikowania nie pamiętam źródła - wyobrażam sobie, że jest to dokumentacja bazy ogniowej.
Jeff Padgett

1

Według OAUTH 2.0:

W tym przypadku wystąpi problem z uwierzytelnianiem, ponieważ FCM używa teraz OAUTH 2

Czytam więc dokumentację bazy ogniowej i zgodnie z dokumentacją nowy sposób przesyłania wiadomości to:

POST: https://fcm.googleapis.com/v1/projects/YOUR_FIREBASEDB_ID/messages:send

Nagłówki

Key: Content-Type, Value: application/json

Aut

Bearer YOUR_TOKEN 

Przykład Ciała

{
   "message":{
    "topic" : "xxx",
    "data" : {
         "body" : "This is a Firebase Cloud Messaging Topic Message!",
         "title" : "FCM Message"
          }
      }
 }

W adresie URL znajduje się identyfikator bazy danych, który można znaleźć w konsoli bazy ognia. (Przejdź do ustawień projektu)

A teraz weźmy nasz token (będzie ważny tylko 1 godzinę):

Najpierw w konsoli Firebase otwórz Ustawienia> Konta usług . Kliknij opcję Generuj nowy klucz prywatny , aby bezpiecznie zapisać plik JSON zawierający klucz. Potrzebowałem tego pliku JSON, aby ręcznie autoryzować żądania serwera. Pobrałem to.

Następnie tworzę projekt node.js i użyłem tej funkcji, aby uzyskać mój token;

var PROJECT_ID = 'YOUR_PROJECT_ID';
var HOST = 'fcm.googleapis.com';
var PATH = '/v1/projects/' + PROJECT_ID + '/messages:send';
var MESSAGING_SCOPE = 'https://www.googleapis.com/auth/firebase.messaging';
var SCOPES = [MESSAGING_SCOPE];

  router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express' });
      getAccessToken().then(function(accessToken) {
        console.log("TOKEN: "+accessToken)
      })

    });

function getAccessToken() {
return new Promise(function(resolve, reject) {
    var key = require('./YOUR_DOWNLOADED_JSON_FILE.json');
    var jwtClient = new google.auth.JWT(
        key.client_email,
        null,
        key.private_key,
        SCOPES,
        null
    );
    jwtClient.authorize(function(err, tokens) {
        if (err) {
            reject(err);
            return;
        }
        resolve(tokens.access_token);
    });
});
}

Teraz mogę użyć tego tokena w mojej prośbie o wpis. Następnie wysyłam wiadomość z danymi, która jest teraz obsługiwana przez moje aplikacje w funkcjiMessageReceived.


Zaakceptowana odpowiedź działa, nie jest konieczne uwierzytelnianie tokena, musisz to przeczytać, aby wypróbować ją z Listonoszem: stackoverflow.com/questions/45309674/…
Carlos Jesus Arancibia Taborga

1

Od 2019 roku Google Firebase ma dużą zmianę w interfejsach API. Mam na myśli: 'com.google.firebase:firebase-messaging:18.0.0'

w 18.0.0 usunęli MyFirebaseInstanceIDServicei musisz zdobyć token, MyFirebaseMessagingServicewięc wystarczy napisać:

@Override
public void onNewToken(String token) {
    Log.d(TAG, "Refreshed token: " + token);

}

a także w pliku AndroidManifest.xml musisz usunąć:

<service android:name=".service.MyFirebaseInstanceIDService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

Ponadto zaleca się ustawienie wartości domyślnych w celu dostosowania wyglądu powiadomień. Możesz określić niestandardową domyślną ikonę i niestandardowy domyślny kolor, które będą stosowane, gdy równoważne wartości nie zostaną ustawione w ładunku powiadomienia.

Dodaj następujące wiersze do znacznika aplikacji, aby ustawić niestandardową domyślną ikonę i niestandardowy kolor:

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

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

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="@string/push_channel" />

teraz, aby obsługiwać powiadomienia w aplikacji działającej w tle, powinieneś zdefiniować zamiar w pierwszej aktywności, nawet jeśli jest to SplashScreen. Gdy aplikacja jest w tle, Android kieruje komunikaty powiadomień do paska zadań. Stuknięcie powiadomienia przez użytkownika domyślnie otwiera program uruchamiający aplikacje.

na przykład, jeśli twój Json jest taki:

 "data": {
"message": "2",
"title": "1",
"pushType" : "banner",
"bannerLink": "http://www.google.com",
"image" : "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"}

wystarczy napisać prosty zamiar, aby uzyskać te wartości:

        Bundle extras = intent.getExtras();
        String bannerLink = extras.getString("bannerLink");
        ...
        String channelId = extras.getString("channelId");

0

Oprócz powyższych odpowiedzi, w przypadku testowania powiadomień wypychanych za pomocą konsoli FCM klucz i obiekt „dane” nie są dodawane do pakietu powiadomień wypychanych. Nie otrzymasz więc szczegółowego powiadomienia push, gdy aplikacja jest w tle lub zostanie zabita.

W takim przypadku musisz wybrać konsolę administracyjną zaplecza, aby przetestować scenariusz aplikacji w tle.

Tutaj dodasz klucz „data” do pakietu push. więc szczegółowe informacje będą wyświetlane zgodnie z oczekiwaniami. Mam nadzieję, że to pomoże niewielu.


0

Za pomocą tego kodu możesz uzyskać powiadomienie w tle / na pierwszym planie, a także wykonać akcję:

//Data should come in this format from the notification
{
  "to": "/xyz/Notifications",
  "data": {
      "key1": "title notification",
      "key2": "description notification"
  }
}

W aplikacji użyj tego kodu:

  @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
      String key1Data = remoteMessage.getData().get("key1");
      // use key1Data to according to your need
    }

// Dane powinny pochodzić w tym formacie od powiadomienia {„do”: „/ xyz / Notifications”, „data”: {„klucz1”: „powiadomienie o tytule”, „klucz2”: „powiadomienie o opisie”}} Jak pisać ten kod w usłudze php?
Tabish khan,

-3

Będą dwa rodzaje powiadomień

  1. Wyświetlaj powiadomienia - wyświetlaj tylko powiadomienia, będą wyświetlane tylko aplikacja nie jest otwarta i znajduje się w stosie aplikacji.
  2. Powiadomienie o danych - wywołanie zwrotne przejdzie do metody onMessageReceived usługi firebasemessaging i działa, gdy aplikacja jest w tle, na pierwszym planie lub w stanie zabicia.

Musisz użyć Powiadomień danych, aby obsłużyć powiadomienie, gdy aplikacja działa w tle.


-5

Wystąpił ten sam problem i ponownie skompilowałem bibliotekę firebase i uniemożliwiłem wysyłanie powiadomień, gdy aplikacja jest w tle

* biblioteka https://github.com/erdalceylan/com-google-firebase-messaging

 dependencies {
        compile 'com.google.firebase:firebase-core:11.2.0'
        compile 'com.github.erdalceylan:com-google-firebase-messaging:v1-11.2.0'
    }

*

@WorkerThread
public void onMessageReceived(RemoteMessage var1) {
  //your app is in background or foreground all time calling
}

nadzieja pomaga. Powodzenia


2
Nie przydatna odpowiedź
Ankit Patidar

2
To okropna sugestia.
vsecades
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.