如何在Firebase中的后台应用时处理通知

时间:2016-06-08 19:18:20

标签: android firebase firebase-cloud-messaging

这是我的清单

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

30 个答案:

答案 0 :(得分:556)

1。为什么会这样?

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

  1. 显示消息:仅当您的应用处于前景
  2. 时,这些消息才会触发onMessageReceived()回调
  3. 数据消息:如果您的应用处于前景/后台/已杀,则这些消息会触发onMessageReceived()回调甚至
  4. Firebase小组还没有开发用于向您的设备发送data-messages的用户界面。

    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
    }
    

答案 1 :(得分:132)

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

  1. App in foreground
  2. 后台应用
  3. App被杀了
  4. 你不能把JSON密钥和#39;通知&#39;在您对firebase API的请求中,而是使用&#39;数据&#39;,请参阅下文。

    当您的应用在后台或被杀时,以下消息不会调用您的 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发送,然后您可以在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
        */
    }
    

答案 2 :(得分:80)

我觉得所有的回复都不完整,但是当你的应用处于后台时,所有回复都需要处理包含数据的通知。

按照以下步骤操作,您就可以在应用处于后台时处理通知。

1.添加这样的intent-filter:

<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" }
    
  2. 这里的关键是添加

    "click_action" : ".MainActivity"
    

    其中.MainActivity是您在步骤1中添加的intent-filter的活动。

    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
          }
      }
      
    2. 这应该就是你需要做的一切。我希望这有助于某人:)

答案 3 :(得分:31)

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

编辑:

基于此thread

您无法使用Firebase控制台设置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\"}}"

答案 4 :(得分:29)

根据send downstream using firebase中的firebase文档,有两种类型的有效负载:

  1. 数据

      

    此参数指定邮件有效内容的自定义键值对。   客户端应用程序负责处理数据消息。数据消息只有自定义键值对。

  2. <强>通知

      

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

  3. 当您在前台时,您可以使用 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>
    

    将该intent-filter放在您的一个活动代码中的清单上。当您单击通知时,它将打开应用程序并直接转到您在click_action中定义的活动,在本例中为&#34; OPEN_ACTIVTY_1&#34;。 在该活动中,您可以通过以下方式获取数据:

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

    我在我的Android应用程序中使用FCM并使用两个有效负载。 以下是我使用的示例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 :(得分:20)

由于从Firebase Notification UI发送的display-messages仅适用于您的应用位于前台的情况。对于data-messages,需要对FCM

进行POST调用

<强>步骤

  1. 安装Advanced Rest Client Google Chrome扩展程序 enter image description here

  2. 添加以下标题

    :内容类型,:application / json

    密钥:授权,:key =“您的服务器密钥” enter image description here

  3. 添加正文

    • 如果使用主题:

      {
          "to" : "/topics/topic_name",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
          }
      }
      
    • 如果使用注册ID:

      {
          "registration_ids" : "[{"id"},{id1}]",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
           }
      }
      
  4. 多数民众赞成吧!现在像往常一样听onMessageReceived回调。

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

答案 6 :(得分:16)

要在后台捕获邮件,您需要使用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>

答案 7 :(得分:16)

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}
每次只有在app处于forground

时才调用

有一个覆盖方法每次调用此方法,无论前台或后台有什么应用程序或被杀死,但此方法适用于此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这种方法不存在,所以在这种情况下 当应用程序处于后台时,防火基本处理....现在你有这个方法 你想做什么......你可以用这种方法做到这一点......

如果您使用的是先前版本,则会启动默认活动 在这种情况下,你可以获得相同的数据

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

它取决于你如何想要提供该数据密钥,或者你想要通知任何你可以给予的通知....... 你将用相同的密钥给你什么,你将获得该数据.........

如果你没有点击通知默认活动会打开,那么你很少发送点击动作的情况很少,但如果你想在应用程序处于后台时打开你的特定活动,你可以在handleIntent上调用你的活动方法,因为每次调用

答案 8 :(得分:13)

这里有关于firebase消息的更清晰的概念。我是从他们的支持团队那里找到的。

Firebase有三种消息类型

通知消息:通知消息适用于后台或前台。当应用程序处于后台时,通知消息将传递到系统托盘。如果应用位于前台,则消息由onMessageReceived()didReceiveRemoteNotification回调处理。这些基本上就是所谓的显示消息。

数据消息:在Android平台上,数据消息可以在后台和前台上运行。数据消息将由onMessageReceived()处理。这里的平台特定说明如下:在Android上,可以在用于启动活动的Intent中检索数据有效负载。要详细说明,如果您有"click_action":"launch_Activity_1",则只能通过getIntent()Activity_1检索此意图。

包含通知和数据有效负载的邮件:在后台,应用会在通知托盘中收到通知有效内容,并仅在用户点击通知时处理数据有效内容。在前台时,您的应用会收到一个消息对象,其中包含两个可用的有效负载。其次,click_action参数通常用于通知有效负载而不是数据有效负载。如果在数据有效内容中使用,则此参数将被视为自定义键值对,因此您需要实现自定义逻辑才能使其按预期工作。

另外,我建议您使用onMessageReceived方法(请参阅数据消息)来提取数据包。根据您的逻辑,我检查了捆绑对象,但未找到预期的数据内容。以下是对可能提供更清晰的类似案例的引用。

有关详细信息,请访问我的this thread

答案 9 :(得分:10)

2017年更新答案

以下是docs关于此问题的明确答案:

enter image description here

答案 10 :(得分:9)

根据文件: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.You应该只关注 LAUNCHER活动的意图

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

Java代码应该在MainActivity上的onCreate方法上:

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

您可以测试来自Firebase Notifications Console的两个有效负载通知+数据。不要忘记在高级选项部分

上填写自定义数据字段

答案 11 :(得分:7)

像这样的简单摘要

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

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

在此if块中,根据firebase UI搜索您的密钥。

在这个例子中,我的键和值如上所述; (抱歉语言=)) enter image description here

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

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

使用这行代码,我关闭了我的应用程序并打开Goog​​le Play Market

快乐编码=)

答案 12 :(得分:6)

我想出了这些情景,

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

当应用程序位于后台时,会调用第一个活动

现在,如果你使用启动活动,那么必须记住将调用 splashactivity ,否则如果没有splashActivity ,无论第一项活动是什么,都会被召唤。

然后你需要检查 firstActivity getIntent(),看看它是否有捆绑。如果一切正常,你会看到bundle已填入值。如果从服务器发送的 data tag 中的值如下所示,

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


            }
        }

答案 13 :(得分:3)

感谢大家的回答。但我通过发送数据消息而不是发送通知解决了这个问题。 服务器代码

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

答案 14 :(得分:2)

即使应用程序处于后台和前台,发送消息的简便方法如下: - 要使用API​​发送消息,您可以使用名为AdvancedREST Client的工具,它的chrome扩展名,并使用以下参数发送消息。

Rest客户端工具链接:https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

使用此网址: - https://fcm.googleapis.com/fcm/send 内容类型:应用程序/ JSON 授权:key =您的服务器密钥From或Authoization密钥(参见下面的参考资料)

{ "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密钥中,服务器密钥将是您的授权密钥。

你需要将接收者的tokenID放在使用API​​发送的POST请求的“to”部分。

答案 15 :(得分:2)

从服务器请求中完全删除通知有效内容。发送仅数据并在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()内获取从服务器发送的任何数据。

答案 16 :(得分:2)

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

感谢所有其他答案。

答案 17 :(得分:1)

我在 firebase-messaging-sw.js 中添加了以下代码,

messaging.onBackgroundmessage((payload)=>{
    console.log("background message detected!!");
    console.log("message : ", payload);
})

每次在后台收到消息时都会触发。但是我无法在主线程中使用有效负载,因为 SW 不支持它。于是我查了很多资料,在一个安卓论坛上找到了解决办法。

所以解决方案是我们必须从请求负载中删除通知负载。

所以我改变了我的有效载荷

{
    "notification": {
        "title": "Hey there",
        "body": "Subscribe to AMAL MOHAN N youtube channel"
    },
    "to": "your-browser-token",
    "data": {
        "value1": "text",
        "value2": "",
        "value3": "sample3",
        "value4": "sample4"
    }
}

{
    "to": "your-browser-token",
    "data": {
            "value1": "text",
            "value2": "",
            "value3": "sample3",
            "value4": "sample4"
          }
}

负载的变化自动使 receiveMessage() 在前台消息和后台消息中触发。

我在一个 Android 论坛上找到了这个,这对我有用!如果这对您有用,请告诉我。

答案 18 :(得分:1)

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

验证

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函数处理。

答案 19 :(得分:1)

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

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

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

通过此onMessageRecivied调用后台和前台,无需在启动器活动上使用通知托盘处理通知。 使用以下方法处理数据有效负载:
    公共无效onMessageReceived(RemoteMessage remoteMessage)     如果(remoteMessage.getData()。size()> 0)     Log.d(TAG,“消息数据有效载荷:” + remoteMessage.getData());

答案 20 :(得分:1)

2018年6月答案-

您必须确保消息中的任何地方都没有“ notification”关键字。仅包含“数据”,该应用程序将能够在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.

答案 21 :(得分:0)

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

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

答案 22 :(得分:0)

除了以上答案外, 如果您正在使用 FCM控制台测试推送通知,则键和对象不会添加到“推送通知”捆绑包中。因此,当应用程序处于后台或被终止运行时,您将不会收到详细的推送通知。

在这种情况下,您必须选择后端管理控制台来测试App后台情况。

在这里,您将在推包中添加“数据”键。因此,详细的推送将按预期显示。 希望对您有所帮助。

答案 23 :(得分:0)

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

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

答案 24 :(得分:0)

  // 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 :(得分:0)

从2019年7月开始工作

Android compileSdkVersion 28,buildToolsVersion 28.0.3和firebase-messaging:19.0.1

经过许多小时的研究,研究了其他所有StackOverflow问题和答案,并尝试了无数过时的解决方案,该解决方案设法在以下三种情况下显示通知:

-应用程序处于前台:
     该通知是通过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:

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-将这些行添加到标签中的应用清单中

    <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 Web控制台发送通知:

在“通知”部分中:     通知标题=要在通知对话框中显示的标题(可选)     通知文本=向用户显示的消息(必填) 然后在“目标”部分中:     应用=您的Android应用 并在“其他选项”部分中:     Android通知频道= default_channel_id     自订资料         键:标题值:(此处与“通知”部分的“标题”字段中的文本相同)         键:正文值:(此处与“通知”部分的“消息”字段中的文本相同)         key:click_action值:.MainActivity      声音=已禁用
     过期= 4周

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

编码愉快!

答案 26 :(得分:0)

会有两种类型的通知

  1. 显示通知-仅显示通知,仅在未打开的应用及其在应用堆栈中的情况下显示。
  2. 数据通知-回调将进入firebasemessagingservice的onMessageReceived方法中,并且在应用程序处于后台,前台或已终止状态时起作用。

当应用程序在后台运行时,您必须使用数据通知来处理通知。

答案 27 :(得分:0)

常规

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

  • 显示消息:仅当您的应用位于前景

    中时,这些消息才会触发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的更多详细信息,您可以在这里找到:Set up a Firebase Cloud Messaging client app on Android

答案 28 :(得分:0)

提供的解决方案在我的情况下不起作用。

归根结底,我发现某些电池优化应用可以让用户控制允许或阻止应用发送通知。就我而言,三星的智能管理器会在我的应用程序从最近列表中被杀死/清除后自动阻止它。

为我的应用关闭该功能是我能找到的唯一解决方案。

答案 29 :(得分:-4)

我遇到了同样的问题并重新编译了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
}

希望有所帮助。祝你好运