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.