Как обрабатывать уведомление, когда приложение находится в фоновом режиме в Firebase

Вот мой манифест

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

Когда приложение находится в фоновом режиме и уведомление приходит, появляется уведомление по умолчанию и не запускает мой код onMessageReceived.

Вот мой код onMessageReceived. Это вызывает, если мое приложение работает на переднем плане, а не приложением в фоновом режиме. Как запустить этот код, когда приложение также находится в фоновом режиме?

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

1. Почему это происходит?

В FCM (Firebase Cloud Messaging) есть два типа сообщений:

  1. Отображаемые сообщения. Эти сообщения активируют onMessageReceived() вызов onMessageReceived() только тогда, когда ваше приложение находится на переднем плане
  2. Сообщения данных. Сообщения тезисов вызывают onMessageReceived() вызов onMessageReceived() даже если ваше приложение находится на переднем плане/фоне/убито

Команда Firebase пока не разработала пользовательский интерфейс для отправки data-messages на свои устройства.

2. Как?

Для этого вам необходимо выполнить запрос POST по следующему URL-адресу:

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

Заголовки

  • Ключ: Content-Type, Value: application/json
  • Ключ: Authorization, Значение: key=<your-server-key>

Тело, использующее темы

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

Или если вы хотите отправить его на определенные устройства

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


ПРИМЕЧАНИЕ. Убедитесь, что вы не добавляете ключевое notification JSON.
ПРИМЕЧАНИЕ. Чтобы получить ключ сервера, вы можете найти его в консоли firebase: Your project → settings → Project settings → Cloud messaging → Server Key

3. Как обрабатывать push-уведомление?

Вот как вы обрабатываете полученное сообщение:

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

     // Manage data
}

Ответ 2

Чтобы библиотека firebase вызывала ваш onMessageReceived() в следующих случаях

  1. Приложение на переднем плане
  2. Приложение в фоновом режиме
  3. Приложение было убито

вы не должны ставить JSON-сообщение "уведомление" в свой запрос на firebase API, но вместо этого используйте "данные", см. ниже.

Следующее сообщение не будет вызывать ваш onMessageReceived(), когда ваше приложение находится в фоновом режиме или убито, и вы не можете настроить свое уведомление.

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

но вместо этого это будет работать

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

В основном сообщение отправляется в аргументе RemoteMessage вместе с вашим объектом данных в виде Карты, тогда вы можете управлять уведомлением в onMessageReceived, как в фрагменте здесь

@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
    */
}

Ответ 3

Я чувствую, что все ответы являются неполными, но у всех есть что-то, что вам нужно для обработки уведомления, которое имеет данные, когда ваше приложение находится в фоновом режиме.

Выполните следующие действия, и вы сможете обрабатывать свои уведомления, когда ваше приложение находится в фоновом режиме.

1. Добавьте фильтр-замысел следующим образом:

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

к активности, которую вы хотите обработать данные уведомления.

  1. Отправлять уведомления в следующем формате:

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

Ключевым моментом здесь является добавление

"click_action" : ".MainActivity"

где.MainActivity - это активность с фильтром намерений, который вы добавили на шаге 1.

  1. Получите информацию "данные" из уведомления в 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
        }
    }
    

И это должно быть все, что вам нужно. Надеюсь, это поможет кому-то :)

Ответ 4

В соответствии с документацией по firebase в send downstream с использованием firebase, существует 2 типа полезной нагрузки:

  1. данные

    Этот параметр указывает пользовательские пары ключ-значение полезной нагрузки сообщения. Клиентское приложение отвечает за обработку сообщений с данными. Сообщения данных имеют только пользовательские пары ключ-значение.

  2. уведомление

    Этот параметр указывает предопределенные видимые пользователем пары ключ-значение полезной нагрузки уведомления. FCM автоматически отображает сообщение для устройств конечного пользователя от имени клиентского приложения. Уведомительные сообщения имеют предопределенный набор видимых пользователю ключей.

Когда вы находитесь на переднем плане, вы можете получить данные внутри FCM, используя onMessageReceived(), вы можете получить свои данные из полезной нагрузки данных.

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

Когда вы находитесь в фоновом режиме, FCM будет отображать уведомления в системном трее на основе информации из полезных данных уведомления. Заголовок, сообщение и значок, используемые для уведомления на панели задач, извлекаются из полезной нагрузки уведомления.

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

Эта полезная нагрузка уведомления используются, когда вы хотите automactically показывать уведомления на панели задач, когда приложение работает в фоновом режиме. Чтобы получать данные уведомлений, когда ваше приложение в фоновом режиме, вы должны добавить click_action внутри полезной нагрузки уведомлений.

Если вы хотите открыть свое приложение и выполнить определенное действие [в то время как в фоновом режиме], установите click_action в полезной нагрузке уведомления и сопоставьте его с фильтром намерений в Activity, которую вы хотите запустить. Например, установите для click_action значение OPEN_ACTIVITY_1, чтобы активировать фильтр намерений, как показано ниже:

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

Поместите этот фильтр намерений в свой манифест, внутри одного из тегов активности. Когда вы щелкнете по уведомлению, оно откроет приложение и сразу перейдет к активности, которую вы определили в click_action, в данном случае "OPEN_ACTIVTY_1". И внутри этой деятельности вы можете получить данные:

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

Я использую FCM для своего приложения для Android и использую обе полезные нагрузки. Вот пример JSON, который я использую:

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

Ответ 5

Согласно документам

Обрабатывать сообщения в фоновом приложении

Когда ваше приложение находится в фоновом режиме, Android направляет уведомления в системный трей. При нажатии на уведомление пользователя открывается панель запуска приложения по умолчанию.

Это включает в себя сообщения, которые содержат как уведомления, так и данные. В этих случаях уведомление доставляется в системный трей устройства, а полезная нагрузка данных доставляется в дополнениях к назначению вашего средства запуска.

Если вы хотите открыть свое приложение и выполнить определенное действие, установите click_action в полезной нагрузке уведомления и сопоставьте его с фильтром намерений в Activity, которую вы хотите запустить. Например, установите для click_action значение OPEN_ACTIVITY_1, чтобы активировать фильтр намерений, как показано ниже:

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

Редактировать:

На основе этой темы:

Вы не можете установить полезную нагрузку click_action с помощью Firebase Console. Вы можете попробовать протестировать с помощью команды curl или пользовательского 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\"}}"

Ответ 6

Поскольку display-messages которые отправляются из интерфейса Firebase Notification UI, работают, только если ваше приложение находится на переднем плане. Для data-messages необходимо выполнить POST-вызов FCM

меры

  1. Установите расширенное клиентское расширение Google Chrome Extension enter image description here

  2. Добавьте следующие заголовки

    Ключ: Content-Type, Значение: application/json

    Ключ: Авторизация, Значение: ключ = "ключ вашего сервера" enter image description here

  3. Добавить тело

    • При использовании тем:

      {
          "to" : "/topics/topic_name",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
          }
      }
      
    • При использовании регистрационного идентификатора:

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

Это оно!. Теперь слушайте onMessageReceived вызов onMessageReceived как обычно.

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

Ответ 7

Для захвата сообщения в фоновом режиме вам нужно использовать 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)
        }
    }

и добавьте это в свой манифест:

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

Ответ 8

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}

не вызывается каждый раз, когда он вызывается только тогда, когда приложение находится в подполье

существует один метод переопределения, этот метод вызывается каждый раз, независимо от того, какое приложение находится на переднем плане или в фоновом режиме или убито, но этот метод доступен с этой версией firebase api

это версия, которую вы должны импортировать из gradle

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

это метод

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

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


}

с предыдущей firebase api этого метода не было, поэтому в этом случае fire base обрабатывает себя, когда приложение находится в фоновом режиме.... теперь у вас есть этот метод, что бы вы хотели сделать... u можете сделать это здесь, в этом методе....

если вы используете предыдущую версию, чем начнется действие по умолчанию, в этом случае вы можете получать данные одинаково

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

//делай то, что захочешь....}

обычно это структура с сервера, который мы получаем в уведомлении

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

это до u, как вы хотите дать этот ключ данных, или вы хотите дать уведомление, что-нибудь, что вы можете дать......., что когда-либо вы дадите здесь с тем же ключом, и получите эти данные........,

есть несколько случаев, если ур не отправляет действие click в этом случае, когда u нажмет на действие по умолчанию уведомления, откроется, но если вы хотите открыть свою конкретную деятельность, когда приложение находится в фоновом режиме, вы можете вызывать свою активность из этого метода handleIntent, потому что это вызывается каждый раз

Ответ 9

Вот более понятные понятия о сообщении firebase. Я нашел его в своей команде поддержки.

Firebase имеет три типа сообщений:

Сообщения оповещения. Сообщение уведомления работает на фоне или переднем плане. Когда приложение находится в фоновом режиме, сообщения уведомления доставляются на системный трей. Если приложение находится на переднем плане, сообщения обрабатываются onMessageReceived() или didReceiveRemoteNotification обратными вызовами. Это, по сути, то, что называется отображаемыми сообщениями.

Сообщения данных. На платформе Android сообщение данных может работать на фоне и переднем плане. Сообщение данных будет обработано onMessageReceived(). Здесь особое внимание будет уделено платформе: на Android полезная нагрузка данных может быть восстановлена ​​в намерении, используемом для запуска вашей активности. Чтобы уточнить, если у вас есть "click_action":"launch_Activity_1", вы можете получить это намерение через getIntent() только с Activity_1.

Сообщения с полезными нагрузками уведомлений и данных. Когда в фоновом режиме приложения получают полезную нагрузку уведомления в лотке уведомлений и обрабатывают только полезную нагрузку данных, когда пользователь нажимает на уведомление. Когда на переднем плане ваше приложение получает объект сообщения с доступными полезными нагрузками. Во-вторых, параметр click_action часто используется в полезной нагрузке уведомления, а не в полезной нагрузке данных. Если используется внутри полезной нагрузки данных, этот параметр будет рассматриваться как настраиваемая пара ключей и значений, поэтому вам потребуется реализовать пользовательскую логику, чтобы она работала по назначению.

Кроме того, я рекомендую использовать метод onMessageReceived (см. сообщение данных) для извлечения набора данных. Из вашей логики я проверил объект пакета и не нашел ожидаемого содержимого данных. Вот ссылка на аналогичный случай, который может обеспечить большую ясность.

Для получения дополнительной информации посетите мой этот поток

Ответ 10

По документам: 17 мая 2017 г.

Когда ваше приложение находится в фоновом режиме, Android направляет уведомления в системный трей. При нажатии на уведомление пользователя открывается панель запуска приложения по умолчанию.

Это включает в себя сообщения, которые содержат как уведомления, так и полезные данные (и все сообщения, отправленные из консоли уведомлений). В этих случаях уведомление доставляется в системный трей устройства, а полезная нагрузка данных доставляется в дополнениях к назначению вашего средства запуска.

Итак, вы должны использовать оба уведомления полезных данных + данные:

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

Нет необходимости использовать click_action. Вам просто нужно получить отрывки из намерений о деятельности LAUNCHER.

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

Код Java должен быть в методе onCreate для MainActivity:

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

Вы можете протестировать оба уведомления полезной нагрузки + данные из консоли уведомлений Firebase. Не забудьте заполнить пользовательские поля данных в разделе "Дополнительные параметры"

Ответ 11

2017 обновленный ответ

Вот четкий ответ из документации по этому поводу:

enter image description here

Ответ 12

Простое резюме, как это

  • если ваше приложение работает;

    onMessageReceived()
    

это триггеры.

  • если ваше приложение не запущено (убито смахиванием);

    onMessageReceived()
    

не запускается и не доставляется по адресу direclty. Если у вас есть особая пара ключ-значение. Они не работают, потому что onMessageReceived() не работает.

Я нашел этот путь;

В своей деятельности по запуску вставьте эту логику,

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

в этом блоке ищите ваши ключи в соответствии с пользовательским интерфейсом Firebase.

В этом примере мой ключ и значение, как указано выше; (извините за язык =)) enter image description here

Когда мой код работает, я получаю "com.rda.note".

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

с этой строкой кода я закрыл свое приложение и открыл Google Play Market

счастливого кодирования =)

Ответ 13

Я понял сценарии,

Когда приложение находится на переднем плане, вызывается метод onMessageReceived() из FirebaseService. Таким образом будет вызван параметр pendingIntent, определенный в классе службы.

И когда приложение находится в фоновом режиме, вызывается первая активность.

Теперь, если вы используете активность всплеска, тогда нужно иметь в виду, что будет вызвана функция splashactivity, иначе, если нет splashActivity, тогда будет вызываться любое первое действие.

Затем вам нужно проверить getIntent() для firstActivity, чтобы узнать, есть ли у него какой-либо комплект. Если все в порядке, вы увидите, что пакет имеет значения, заполненные. Если значение в теге данных, отправленное с сервера, выглядит следующим образом:

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

Затем в первом действии вы увидите, что существует действительное намерение (getIntent() не является нулевым), действительный пакет и внутренний пакет, здесь будет указан весь JSON с данными как ключом.

Для этого сценария код для извлечения значения будет выглядеть следующим образом:

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


            }
        }

Ответ 14

Работает с июля 2019 года

Android compileSdkVersion 28, buildToolsVersion 28.0.3 и Firebase-Messaging: 19.0.1

После многих часов исследований по всем остальным вопросам и ответам StackOverflow и пробования бесчисленных устаревших решений этому решению удалось отобразить уведомления в следующих 3 сценариях:

- Приложение находится на переднем плане:
уведомление получено методом onMessageReceived в моем классе MyFirebaseMessagingService

- Приложение было убито (оно не работает в фоновом режиме): уведомление отправляется на панель уведомлений автоматически с помощью FCM. Когда пользователь касается уведомления, приложение запускается путем вызова действия, в котором есть android.intent.category.LAUNCHER в манифесте. Вы можете получить часть данных уведомления, используя getIntent(). GetExtras() в методе onCreate().

- Приложение находится в фоновом режиме: уведомление отправляется на панель уведомлений автоматически с помощью FCM. Когда пользователь касается уведомления, приложение выводится на передний план, запуская действие, в котором есть android.intent.category.LAUNCHER в манифесте. Поскольку мое приложение имеет launchMode = "singleTop" в этом действии, метод onCreate() не вызывается, потому что одно действие того же класса уже создано, вместо этого вызывается метод onNewIntent() этого класса, и вы получаете часть данных уведомление там с помощью intent.getExtras().

Шаги: 1- Если вы определяете основное действие своего приложения следующим образом:

<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- добавьте эти строки в метод onCreate() вашего 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);
    }
}

и эти методы к тому же 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- создайте класс MyFirebase следующим образом:

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- создайте новый класс NotificationActivity.class следующим образом:

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- Добавьте эти строки в ваше приложение Manifest, внутри ваших тегов

    <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- добавьте эти строки в ваш метод Application.java onCreate() или в метод 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));
  }

Готово.

Теперь, чтобы это хорошо работало в 3 упомянутых сценариях, вы должны отправить уведомление из веб-консоли Firebase следующим образом:

В разделе "Уведомление": заголовок уведомления = заголовок, отображаемый в диалоговом окне уведомлений (необязательно). Текст уведомления = сообщение, отображаемое пользователю (обязательно). Затем в разделе "Цель": приложение = приложение Android и в разделе "Дополнительные параметры": канал уведомлений Android. = default_channel_id Ключ пользовательских данных: значение заголовка: (здесь тот же текст, что и в поле "Заголовок" в разделе "Уведомления") ключ: значение тела: (здесь тот же текст, что и в поле "Сообщение" в разделе "Уведомления") ключ: значение click_action:.MainActivity Sound = Отключено
Истекает = 4 недели

Вы можете отладить его в эмуляторе с API 28 в Google Play.

Удачного кодирования!

Ответ 15

Спасибо всем вам за ваши ответы. Но я решил это, отправив сообщение данных вместо отправки Уведомления. Код сервера

<?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;

?>

И поймал данные в 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());
}
}

Ответ 16

Удалить полезную нагрузку уведомлений полностью из вашего запроса на сервер. Отправляйте только данные и обрабатывайте их в onMessageReceived(), в противном случае ваш onMessageReceived не будет запущен, если приложение находится в фоновом режиме или убито.

Вот что я посылаю с сервера:

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

Итак, вы можете получить свои данные в onMessageReceived(RemoteMessage message) следующим образом: (скажем, мне нужно получить идентификатор)

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

И аналогичным образом вы можете получить любые данные, отправленные с сервера в пределах onMessageReceived().

Ответ 17

Легкий способ отправки сообщений, даже если приложение находится в фоновом режиме и переднем плане: • Чтобы отправить сообщение с помощью API, вы можете использовать инструмент AdvancedREST Client, его расширение chrome и отправить сообщение со следующими параметрами.

Клиентский инструмент для отдыха Ссылка: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

используйте этот URL-адрес: https://fcm.googleapis.com/fcm/send Content-Type: application/json. Авторизация: key = Ключ вашего сервера От или Автоимия (см. ниже)

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

Ключ авторизации можно получить, посетив консоль разработчиков Google и нажмите кнопку "Учетные данные" в меню слева для вашего проекта. Среди перечисленных ключей API ключ сервера будет вашим ключом авторизации.

И вам нужно поместить токенID получателя в раздел "Кому" вашего запроса POST, отправленного с использованием API.

Ответ 18

Июнь 2018 Ответ -

Вы должны убедиться, что в сообщении отсутствует ключевое слово "уведомление". Включите только "данные", и приложение сможет обрабатывать сообщение в onMessageReceived, даже если в фоновом режиме или убито.

Использование облачных функций:

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

Затем в вашем onMessageReceived() в вашем классе расширяется 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.

Ответ 19

вы хотите работать с onMessageReceived (RemoteMessage remoteMessage) в фоновом режиме и отправлять только часть данных, уведомляющую эту часть:

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

"AnotherActivity": "True", "to": "идентификатор устройства или токен устройства"

При этом onMessageRecivied является фоном вызова и передним планом, нет необходимости обрабатывать уведомления с помощью панели уведомлений о вашей активности запуска. Обработайте данные, используя это:

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

Ответ 20

Согласно OAUTH 2.0:

В этом случае будет проблема с аутентификацией, так как FCM теперь использует OAUTH 2

Поэтому я читаю документацию FireBase и, согласно документации, новый способ публикации сообщений данных;

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

Заголовки

Key: Content-Type, Value: application/json

Auth

Bearer YOUR_TOKEN 

Пример тела

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

В URL есть идентификатор базы данных, который вы можете найти на своей консоли Firebase. (Идут проектные расчеты)

А теперь давайте возьмем наш токен (он будет действителен только 1 час):

Сначала в консоли Firebase откройте " Настройки"> "Учетные записи служб". Нажмите " Создать новый закрытый ключ", надежно сохраните файл JSON, содержащий ключ. Мне был нужен этот JSON файл для авторизации запросов к серверу вручную. Я скачал это.

Затем я создаю проект node.js и использую эту функцию для получения моего токена;

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

Теперь я могу использовать этот токен в своем почтовом запросе. Затем я публикую свое сообщение с данными, и теперь оно обрабатывается функцией приложения onMessageReceived.

Ответ 21

В дополнение к ответам выше, если вы тестируете push-уведомления с помощью консоли FCM, ключ и объект "данные" не добавляются в комплект Push-уведомлений. Таким образом, вы не будете получать подробные push-уведомления, когда приложение будет фоновым или убитым.

В этом случае вам нужно выбрать консоль администратора для тестирования фонового сценария приложения.

Здесь вы добавите ключ "data" в ваш push-пакет. Таким образом, подробный толчок будет показан, как и ожидалось. Надеюсь, это поможет немногим.

Ответ 22

Используя этот код, вы можете получить уведомление в фоновом режиме/на переднем плане, а также поместить действие:

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

В приложении используйте этот код:

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

Ответ 23

С 2019 года Google Firebase сильно изменил свои API, я имею в виду: 'com.google.firebase:firebase-messaging:18.0.0'

в 18.0.0 они удалили MyFirebaseInstanceIDService и вам нужно получить токен в MyFirebaseMessagingService поэтому вам просто нужно написать:

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

}

а также в вашем AndroidManifest.xml вы должны удалить:

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

Также рекомендуется установить значения по умолчанию, чтобы настроить внешний вид уведомлений. Вы можете указать пользовательский значок по умолчанию и пользовательский цвет по умолчанию, которые применяются всякий раз, когда в полезной нагрузке уведомления не заданы эквивалентные значения.

Добавьте эти строки внутри тега приложения, чтобы установить значок по умолчанию и цвет:

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

Теперь для обработки уведомительных сообщений в фоновом приложении вы должны определить Intent в своей первой Деятельности, даже если это SplashScreen. Когда ваше приложение находится в фоновом режиме, Android направляет уведомления в системный трей. При нажатии на уведомление пользователя открывается панель запуска приложения по умолчанию.

например, если ваш Json такой:

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

вам просто нужно написать простое намерение получить эти значения:

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

Ответ 24

  // Place this code on your MainActivity,then you will get your payload
  // Handle possible data accompanying notification message.
    // [START handle_data_extras]
    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d(TAG, "Key: " + key + " Value: " + value);
        }
    }

Ответ 25

Будет два типа уведомлений

  1. Отображать уведомления - отображаются только уведомления, только приложение не открыто и находится в стеке приложений.
  2. Уведомление о данных - обратный вызов переходит в метод onMessageReceived службы firebasemessagingservice и работает, когда приложение находится в фоновом, переднем или закрытом состоянии.

Вы должны использовать Data Notifications для обработки уведомлений, когда приложение находится в фоновом режиме.

Ответ 26

Я столкнулся с той же проблемой и перекомпилировал библиотеку firebase и не дал ей отправлять уведомления, когда приложение находится в фоновом режиме

* библиотека 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
}

надеюсь. Удачи.