这是我的清单

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


评论

它写在onMessageReceived()的重写示例中,第二条注释行显示“此处未收到消息?查看为什么会这样:goo.gl/39bRNJ。与下面的答案一样,该解决方案可以在带有通知和数据有效负载的消息的文档中找到

简而言之,要唤醒已终止的应用程序,您应始终发送带有数据对象的通知,以在应用程序中调用通知服务类处理程序FirebaseMessagingService.onMessageReceived()。另外,请尝试不从Firebase控制台发送它,而是从其他地方发送它(例如,在线测试发布服务)。

这个解决方案为我工作stackoverflow.com/a/44150822/6632278希望能对您有所帮助。祝你好运

什么“ .fcm”。 PshycoFirebaseMessagingServices是否在您的清单中?我遇到找不到类的错误..并且在任何地方都找不到该参数的第一部分是什么。

#1 楼

1.为什么会发生这种情况?

FCM(Firebase云消息传递)中有两种消息类型:




显示消息:这些消息仅当您的应用程序位于前景中时才触发onMessageReceived()回调


数据消息:即使您的应用程序位于前景/背景/已终止中,这些消息也会触发onMessageReceived()回调



注意:Firebase团队尚未开发可将data-messages发送到您的设备的UI。您应该使用服务器来发送此类型!




2。

如何实现此目的,您必须对以下网址执行POST请求:


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


标题



键:Content-Type,值: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}"]
}





注意:确保没有添加JSON密钥notification
注意:服务器密钥,您可以在firebase控制台中找到它:Your project -> settings -> Project settings -> Cloud messaging -> Server Key


3。如何处理推送通知消息?

这是您如何处理收到的消息的方法:

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

     // Manage data
}


评论


您可以按照以下步骤在同一通知中发送“数据”和“通知”键stackoverflow.com/a/42279260/2734021 :)

–丹尼尔·S。
17年2月23日在21:38

Firebase团队尚未开发可将数据消息发送到您的设备的UI。在过去的一年中,这种情况发生了变化吗?

–汉克唱片
17年11月20日在10:18

@Antonio在Oreo中,当应用程序被杀死时,不会调用onMessageReceived。我只是有数据的有效载荷。你有什么更新吗?

– Samir Mangroliya
18-2-27在12:46

当应用程序在后台运行时,onMessageReceived不会被调用,这在FCM中是一个严重的问题!另外,请更新您的答案。

–穆罕默德·巴巴尔(Muhammad Babar)
18-4-4在7:39



三年后,这仍然是一个问题:如果您的应用程序在后台运行,则如果您的消息具有“通知”键,则无论其是否具有“数据”键,onReceiveMessage都不会被调用。由于您的服务器无法确定该应用是否在后台运行,因此它需要发送两条消息。荒谬

–戴夫·Nottage
19年11月25日在5:35

#2 楼

要在以下情况下使Firebase库调用onMessageReceived()


前台的应用程序
后台的应用程序
应用程序已被杀死

您不得在对Firebase API的请求中放入JSON密钥“ notification”,而应使用“ data”,请参见下文。

当您的应用程序处于以下状态时,以下消息不会调用onMessageReceived()背景或被杀死,并且您无法自定义通知。

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


,但是使用它会起作用

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


基本上,消息在参数RemoteMessage中作为数据对象与Map一起发送,然后您可以在onMessageReceive中管理通知,如此处的摘录中所述。


评论


是否可以从Firebase控制台实现此目的?

–koder
16年8月24日在9:49

这就是我一天多以来一直在寻找的东西.....非常感谢,它运行得非常好。如果您解释如何在onMessageReceived()中处理数据中的密钥对,以使用这些值启动活动,那将更好。

–Boopathi T
16 Nov 24在8:42



当应用程序在后台运行时,您的方法工作正常,但是当应用程序被终止时,我没有收到数据

– Sanzhar
16 Dec 26'在10:19

Sanzhar的同样问题。如果该应用程序被杀死,我不会收到任何消息。

– Giacomo M
17年5月18日在12:24



当它在后台或被杀死时,它可以工作,但是如果您强行从设置中杀死您的应用程序,它将无法正常工作,但它的工作确实很好,我认为这是最好的解决方案。

–加斯顿·塞伦(GastónSaillén)
18-10-28在19:47

#3 楼

我觉得所有回复都不完整,但是当您的应用程序在后台运行时,所有回复都需要处理一些包含数据的通知。

按照以下步骤操作,您就可以处理自己的您的应用程序在后台运行时发出通知。

1.向此类活动添加一个意图过滤器:

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


处理通知数据。



以以下格式发送通知:

{ 
 "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中添加的具有意图过滤器的活动。



从“ .MainActivity”的onCreate的通知中获取“数据”信息:

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



这应该就是您所需要的做。我希望这对某人有帮助:)

评论


这应该是正确的答案。没有任何文档说要要求click_action和Intent Filter才能使通知显示在托盘中。它们都是必需的。

– airowe
17年2月21日在22:17

@airowe,显示通知时不需要它们

–AlwaysConfused
17年5月2日在23:22

我既有数据块又有通知块,但是我不能在活动中接收数据?

–阿什瓦尼
17年5月5日在13:24

我只是不明白这不是公认的答案。没有click_action,它将无法正常工作。拯救了我的一天

–阿伦·香卡(Arun Shankar)
18年11月1日在4:07

感谢您的支持@ArunShankar。接受的答案在我的回答前七个月就得到了答复,这是一个很好的答案。我不明白为什么没有人谈论click_action,这就是为什么我添加了答案。我很高兴它对很多人都非常有用,这才是最终的结果:)

–丹尼尔·S。
18年11月1日在13:57

#4 楼

根据使用Firebase的下游发送中的Firebase文档,有效负载有两种类型:



data



此参数指定消息有效负载的自定义键值对。
客户端应用程序负责处理数据消息。数据消息仅具有自定义键值对。



通知


此参数指定预定义的,用户可见的键-通知有效负载的值对。 FCM代表客户端应用程序自动将消息显示给最终用户设备。通知消息具有一组预定义的用户可见键。




当您处于前台时,可以使用onMessageReceived()获取FCM中的数据,您可以获取来自数据有效负载的数据。

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


当您处于后台时,FCM将基于通知有效负载的信息在系统托盘中显示通知。从通知有效内容中获取用于系统托盘通知的标题,消息和图标。

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


要自动显示通知时使用此通知有效内容当您的应用程序在后台时,请在系统托盘上。
要在后台应用程序时获取通知数据,应在通知有效内容内添加click_action。


如果需要要打开您的应用并执行特定操作(在后台运行),请在通知有效负载中设置click_action并将其映射到您要启动的活动中的意图过滤器。例如,将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"
   }
}


评论


“将意图过滤器放在清单中的应用程序标记内。”您不能将Intent-filter放入应用程序标记内。

– Kyrylo Zapylaiev
17年9月27日在16:11

您的JSON不会显示click_action键的位置。

–乔什
17年12月20日在10:56

这不是正确的答案吗?什么是点击动作?有人应该投反对票或清理这个

–rana
18年2月8日在23:16

@KyryloZapylaiev我只是更正并更新了答案:“将意图过滤器放在清单中的活动标记中”。

–迪卡
19年4月30日在6:08

@Josh已更新并格式化。您可以再次检查

–迪卡
19年4月30日在6:08

#5 楼

根据docs


在后台应用程序中处理消息

当您的应用程序在后台时,Android会将通知
消息定向到系统托盘。用户点击通知会默认打开
应用启动器。

这包括同时包含通知和数据有效载荷的消息。在这种情况下,通知将传递到设备的系统托盘中,而数据有效负载将在启动器活动的意图中附加传递。

如果需要要打开您的应用并执行特定操作,请在通知有效负载中设置
click_action并将其映射到您要启动的活动中的intent
过滤器。例如,将
click_action设置为OPEN_ACTIVITY_1即可触发意图过滤器,例如以下的



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


编辑:

基于此线程:

您无法使用Firebase Console设置click_action有效负载。您可以尝试使用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\"}}"


评论


你是对的。我已经阅读了文档。但是我很困惑在哪里把它放在我的清单上?我必须在该java文件的onMessageReceived上运行代码,因此我该怎么办,先生?

–Parth Patel
16年6月8日在19:27

您无法使应用程序在后台运行时自动调用onMessageReveiced。相反,您需要处理收到的意图并让处理程序对其进行调用。或者,最好是实现单独的类/方法,该类/方法由onMessageReveiced和您的意图处理两者调用。我在主要活动的onNewIntent中添加了处理程序,它对我来说很好用。

– diidu
16年6月15日在10:30

为时已晚,无法回复@Parath Patel的问题,但这也许会对其他有相同问题的人有所帮助,请在此处查看我的答案stackoverflow.com/a/42279260/2734021

–丹尼尔·S。
17年2月23日在21:43

必须在何处执行此操作?我的活动或Firebasemessage服务?

–马赫迪
17-2-27在7:44

**关于多个通知重定向不起作用?例如:如果我在后台使用“ click_action”从fcm收到三个通知,则第一个通知成功重定向,然后2个通知单击,活动重定向不起作用

–prasanthMurugan
17年7月5日在6:20

#6 楼

从2019年7月开始工作

经过许多小时研究所有其他StackOverflow问题之后,Android compileSdkVersion 28,buildToolsVersion 28.0.3和firebase-messaging:19.0.1

和答案,并尝试了无数过时的解决方案,此解决方案设法在以下三种情况下显示通知:

-应用程序处于前台:
通知由MyFirebaseMessagingService类的onMessageReceived方法接收到

-应用程序已被杀死(它不在后台运行):
通知由FCM自动发送到通知托盘。当用户触摸通知时,将通过调用清单中具有android.intent.category.LAUNCHER的活动来启动应用。您可以通过onCreate()方法上的getIntent()。getExtras()获取通知的数据部分。

-应用程序在后台:
通知发送到通知中托盘由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-将这些行添加到MainActivity.class的onCreate()方法中。

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,如下所示: this:

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

    }

}


}

5-将这些行添加到您的应用清单中,在标签内

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

}


6-将以下行添加到Application.java onCreate()方法或MainActivity.class onCreate()方法中:

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


完成。

现在要在上述3种情况下正常运行,您必须通过以下方式从Firebase Web控制台发送通知:

在“通知”部分:
通知标题=在通知对话框中显示的标题(可选)
通知文本=向用户显示的消息(必填)
然后在“目标”部分中:
应用=您的Android app
和“附加选项”部分中的内容:
Android Notification Channel = default_channel_id
自定义数据
键:标题值:(此处与“通知”部分的“标题”字段中的文本相同)
键:正文值:(此处与“通知”部分的“消息”字段中的文本相同)
键:click_action值:.MainActivity
声音=已禁用
到期= 4周

您可以使用带有Google Play的API 28在仿真器中对其进行调试。

祝您编程愉快!

评论


感谢您的出色回答。

– Alex Chengalan
19-10-10在12:36

@alvaro,如果我想在收到通知时打开Url,该如何处理

– engmms
19年11月15日在15:19

应用程式关闭或被杀死时无法在体内的opp手机上工作

– Android开发人员
19年11月19日在8:02

我没有在Vivo手机中尝试过,但目前在其他许多Android手机中都可以使用。请慢慢阅读每一步,检查所有细节,然后在我在这里提到的每种方法的第一行打开调试断点,使用电缆将真实电话连接到开发计算机,并在发送时调试应用程序来自FCM的消息。检查您是否正在发送带有我提到的所有参数和格式的FCM消息。祝好运!

– alvaro
19/12/3在20:41


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


评论


当应用程序在后台运行时,它实际上会收到通知消息。但是,它不会阻止默认的Firebase接收器对其进行处理,因此该消息仍会显示为通知警报。

–加利亚
16-10-5在15:37

目前不起作用,所以这就是我提出此解决方案的原因。 Google错误库中存在一个已归档的错误。您可能要检查一下。

–罗慕拉诺
16-10-20在9:27

您能否在此处发布指向该错误的链接

–加利亚
16-10-20在9:42

如何从通知中获取数据?

–拉维·瓦格拉(Ravi Vaghela)
16年11月12日在10:29

当该应用被终止时,这显然不起作用。我已经尝试了数小时的解决方案。由于某些原因,接收器在应用程序在后台运行时工作,而在应用程序被终止时无法运行

– XcodeNOOB
16年12月14日在7:10

#8 楼

由于从Firebase通知UI发送的display-messages仅在您的应用程序处于前台状态时才起作用。对于data-messages,需要对FCM进行POST调用

步骤


安装Advanced Rest Client Google Chrome扩展程序


添加以下标头

关键字:Content-Type,值:application / json

关键字:授权,值:key =“您的服务器密钥”



添加主体



如果使用主题:

{
    "to" : "/topics/topic_name",
    "data": {
    "key1" : "value1",
    "key2" : "value2",
    }
}



如果使用注册ID:

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







!现在照常收听onMessageReceived回调。

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


#9 楼

这是有关Firebase消息的更清晰的概念。我从他们的支持团队那里找到了它。
Firebase具有三种消息类型:
通知消息:通知消息可在后台或前台使用。当应用程序在后台运行时,通知消息将传递到系统托盘。如果应用程序在前台,则消息由onMessageReceived()didReceiveRemoteNotification回调处理。这些基本上就是所谓的显示消息。
数据消息:在Android平台上,数据消息可以在后台和前台运行。数据消息将由onMessageReceived()处理。这里有一个特定于平台的注释:在Android上,可以在用于启动活动的Intent中检索数据有效负载。详细说明,如果您具有"click_action":"launch_Activity_1",则可以仅从getIntent()通过Activity_1检索此意图。
同时具有通知和数据负载的消息:在后台时,应用程序会在通知托盘中接收通知负载,并且仅处理用户点击通知时的数据有效负载。在前台时,您的应用程序会收到一个同时具有两个有效负载的消息对象。其次,click_action参数通常用于通知有效负载中,而不用于数据有效负载中。如果在数据有效载荷内部使用,则此参数将被视为自定义键值对,因此您需要实现自定义逻辑以使其按预期工作。
此外,我建议您使用onMessageReceived方法(请参阅数据消息) )提取数据包。根据您的逻辑,我检查了bundle对象,但未找到预期的数据内容。这是对类似情况的引用,它可能会更加清楚。
有关更多信息,请访问我的这个线程

#10 楼

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}


每次仅在应用程序处于Forground状态时才被调用

有一个重写方法,无论哪个应用程序位于前景中,每次都将调用此方法或在后台或被杀死,但是此方法在此Firebase api版本中可用

这是您必须从gradle导入的版本

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


这是使用以前的Firebase API的方法

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

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


}


该方法不存在,因此在这种情况下,当应用程序在后台运行时,
fire base处理自身... 。现在您有了此方法
您想做什么... ...您可以在此方法中执行此操作.....

如果您使用的是以前的版本,则默认活动将不会在这种情况下,开始
您可以用相同的方式获取数据

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


由您决定如何给定e数据键或您想要通知的内容,您可以提供的任何内容.......
您将使用相同的键在此处给出的内容您将得到该数据.........

在少数情况下,如果您不发送点击操作,那么您将在单击通知时打开默认活动,但是如果您想在应用程序处于后台运行时打开您的特定活动,则可以从中调用您的活动在handleIntent方法上,因为每次都被调用

评论


我将firebase消息更新为10.2.1,向通知消息中添加了数据,并且可以正常工作。前景,背景和被杀死。谢谢

–Firas Shrourou
17-6-27在18:43



在Kotlin中,我得到此错误:(44,5)'FirebaseMessagingService'中的'handleIntent'是最终的,不能被覆盖

–ugali soft
17年8月8日在15:46

无法在Firebase 11的版本以上运行

–venu46
19年9月11日在6:44

不工作覆盖方法不会运行。

–蓬松的霸王龙
10月19日18:00

#11 楼

根据文档:2017年5月17日


当您的应用程序在后台运行时,Android
将通知消息定向到系统托盘。用户点击
通知会默认打开应用程序启动器。

这包括同时包含通知和数据有效载荷的消息(以及从Notifications控制台发送的所有消息)。在这些情况下,通知将传递到设备的系统托盘,而数据有效负载将在启动器活动的意图范围内传递。


因此,您应该同时使用有效负载通知和数据:

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


无需使用click_action。您应该从intent中获取更多信息在LAUNCHER活动上

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


Java代码应该在MainActivity上的onCreate方法上:
来自Firebase Notifications Console的两个有效负载通知和数据。不要忘记在“高级选项”部分填写自定义数据字段

#12 楼

2017年更新的答案

以下是文档中关于此的明确答案:



评论



#13 楼

像这样的简单摘要



,如果您的应用正在运行;

onMessageReceived()



是触发器。



如果您的应用未运行(通过刷卡杀死);

onMessageReceived()



是并非凭空触发和交付。如果有特殊的键值对。它们不起作用,因为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
    }
}




在此示例中,我的键和值如上; (对不起,语言=))


当我的代码正常工作时,我得到“ com.rda.note”。

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


使用此行代码,我关闭了我的应用程序并打开了Google Play市场

happycoding =)

#14 楼

我弄清楚了这种情况,

当应用程序处于前台时,将从FirebaseService调用
onMessageReceived()方法。因此将调用服务类中定义的pendingIntent。

当应用程序在后台运行时,将调用第一个活动。

现在,如果您使用启动活动,则必须记住将调用启动活动,否则,如果没有启动活动,那么无论第一个活动是什么,都将被调用。

然后您需要检查firstActivity的getIntent()来查看它是否具有任何捆绑包。如果一切正常,您将看到捆绑包存在如果服务器发送的数据标签中的值看起来像这样,

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


然后在第一个活动中,您会看到,
一个有效的intent(getIntent()不为null),有效的包和包内,将使用数据作为键,上面提到的整个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();
                }


            }
        }


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


评论


@Tabishkhan是的,如果您有任何问题,请随时问我。.谢谢

– Android Sanaullah
19 Mar 6 '19 at 15:58

@AndroidSanaullah,您好:您能解释一下服务器代码的第一部分,您实际上将它放在哪里,我也面临着同样的问题,但我不太理解服务器部分,您使用的是邮递员吗?

– Shid
19年4月30日在22:45

curl用于请求,所有参数都传递给它。@ Shid

– Android Sanaullah
19年8月14日在8:01



#16 楼

从服务器请求中完全删除通知有效内容。仅发送数据并在onMessageReceived()中处理它,否则当应用程序在后台或被杀死时,您的onMessageReceived将不会被触发。

这是我从服务器发送的内容:

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


所以您可以像这样在onMessageReceived(RemoteMessage message)中接收数据:(假设我必须获取ID)

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


同样,您可以获取onMessageReceived()中从服务器发送的任何数据。

#17 楼


#18 楼

您要在后台处理onMessageReceived(RemoteMessage remoteMessage),仅发送数据部分通知部分:

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



“ AnotherActivity”:“ True”,“至“:”“设备ID或设备令牌”

通过此onMessageRecivied,可以调用后台和前台,而无需使用启动器活动上的通知托盘处理通知。
使用以下方法处理数据有效载荷:

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


#19 楼

我有同样的问题。经过一番挖掘后,为什么我的MainActivity是在没有数据的情况下被有意调用的,我意识到我的LAUNCHER活动(如清单中一样)是SplashActivity。在那里,我找到了消息数据,并将其转发给MainActivity。像sharm一样运作。我相信这可以帮助某人。
感谢所有其他答案。

评论


谢谢你的建议。这对我也有用。我的SplashScreen正在获取意图,并且在MainActivity中不可用

– Neo
12月4日12:37

#20 楼


评论


您有任何资料来源吗?

– Yogesh Rathi
19年1月9日在6:09

很安全,我可以在自己的应用中使用它。但是,自发布以来已有6个月了,我不记得来源了-我想那是firebase文档。

– Jeff Padgett
19年1月12日在19:34

#21 楼

根据OAUTH 2.0:

由于现在使用OAUTH 2的FCM,此案例将出现Auth问题。因此,我阅读了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中有数据库ID,您可以在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函数处理。

评论


接受的答案有效,Barer Token auth无法实现,您需要阅读以下内容才能与邮递员一起尝试:stackoverflow.com/questions/45309674/…

–卡洛斯·耶稣(Carlos Jesus)Arancibia Taborga
19年4月14日在22:02



#22 楼

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


此外,建议您设置默认值以自定义通知的外观。您可以指定在通知有效负载中未设置等效值时将应用的自定义默认图标和自定义默认颜色。

在application标记内添加以下行以设置自定义默认图标和自定义颜色:

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


现在要在后台应用程序中处理通知消息,即使您的第一个Activity是SplashScreen,您也应该在其第一个Activity中定义一个Intent,当您的应用程序在后台时, 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");


#23 楼

除了上述答案之外,如果您正在使用FCM控制台测试推送通知,则“数据”键和对象不会添加到“推送通知”包中。因此,当App处于后台或被终止运行时,您将不会收到详细的推送通知。在这里,您将在推包中添加“数据”键。因此,详细的推送将按预期显示。
希望这对您没有帮助。

#24 楼

使用此代码,您可以在后台/前景中获取通知,并进行操作:

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


评论


//数据应以这种格式来自通知{“ to”:“ / xyz / Notifications”,“ data”:{“ key1”:“标题通知”,“ key2”:“描述通知”}}如何编写这个代码在PHP服务?

–塔比什汗
19-2-20在13:02



#25 楼

通常,FCM(Firebase Cloud Messaging)中有两种类型的消息:


显示消息:仅当您的应用程序位于前台时,这些消息才触发onMessageReceived()回调


数据消息:即使您的应用程序处于前台/后台/已杀死状态,这些消息也会触发onMessageReceived()回调


数据消息示例:
{ 
  "to": "/path", 
  "data": 
     { 
      "my_custom_key": "my_custom_value", 
      "my_custom_key2": true 
     } 
}

显示消息示例:
 {
     "notification": {
            "title" : "title",
            "body"  : "body text",
            "icon"  : "ic_notification",
            "click_action" : "OPEN_ACTIVITY_1"
        }
   }

Android端可以处理如下通知:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    …

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

    …

}

有关FCM的更多详细信息,请参见:设置Android上的Firebase Cloud Messaging客户端应用程序

#26 楼

我遇到了同样的问题,并重新编译了Firebase库,并阻止了该应用在后台运行时发送通知。

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


希望有帮助。祝你好运

评论


没有用的答案

– Ankit Patidar
18年3月26日在9:05

这是一个可怕的建议。

–vsecades
19年5月13日在21:19