【问题标题】:Firebase onMessageReceived not called when app in background应用程序在后台时未调用 Firebase onMessageReceived
【发布时间】:2017-04-22 00:56:08
【问题描述】:

我正在使用 Firebase 并测试在应用处于后台时从我的服务器向我的应用发送通知。通知发送成功,它甚至出现在设备的通知中心,但是当通知出现或者即使我点击它,我的 FCMessagingService 中的 onMessageReceived 方法也永远不会被调用。

当我的应用程序在前台进行测试时,调用了 onMessageReceived 方法,一切正常。当应用在后台运行时会出现问题。

这是预期的行为,还是有办法解决这个问题?

这是我的 FBMessagingService:

import android.util.Log;

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

public class FBMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i("PVL", "MESSAGE RECEIVED!!");
        if (remoteMessage.getNotification().getBody() != null) {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getNotification().getBody());
        } else {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getData().get("message"));
        }
    }
}

【问题讨论】:

标签: android firebase firebase-cloud-messaging


【解决方案1】:

我遇到了这个问题(如果应用程序处于后台或关闭状态,应用程序不想在点击通知时打开),问题是通知正文中的 click_action 无效,请尝试将其删除或更改为有效的内容。

【讨论】:

    【解决方案2】:
    推荐的答案 Google Cloud

    这是按预期工作的,只有当您的应用程序处于前台时,通知消息才会传递到您的 onMessageReceived 回调。如果您的应用处于后台或已关闭,则通知中心会显示一条通知消息,并且该消息中的任何数据都会传递到因用户点击而启动的意图通知。

    您可以指定 click_action 来指示用户点击通知时应启动的意图。如果未指定 click_action,则使用主要活动。

    Intent 启动后,您可以使用

    getIntent().getExtras();
    

    检索包含随通知消息一起发送的任何数据的 Set。

    有关通知消息的更多信息,请参阅docs

    【讨论】:

    • 我在使用 Firebase 通知控制台时是否可以设置 click_action
    • 好的,但是如果应用程序被杀死(没有前台或后台)怎么办?
    • 但是如何禁用用户丢弃通知?因为如果用户丢弃它,则意味着所有数据都将被跳过......对吗?
    • 正确!因此,在向 Android 发送通知消息时,随附的数据应该是增强通知体验的数据。它不应该是应用程序的关键数据,即使用户关闭通知,也可以将数据消息用于应用程序需要的数据。
    • 这并不完全正确。如果消息只包含数据而不包含通知负载,则无论应用程序是否在前台,消息都将始终传递到 onMessageReceive。
    【解决方案3】:

    我遇到了同样的问题。使用“数据消息”而不是“通知”更容易。数据消息总是加载 onMessageReceived 类。

    在该类中,您可以使用通知构建器制作自己的通知。

    例子:

     @Override
        public void onMessageReceived(RemoteMessage remoteMessage) {
            sendNotification(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"));
        }
    
        private void sendNotification(String messageTitle,String messageBody) {
            Intent intent = new Intent(this, MainActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            PendingIntent pendingIntent = PendingIntent.getActivity(this,0 /* request code */, intent,PendingIntent.FLAG_UPDATE_CURRENT);
    
            long[] pattern = {500,500,500,500,500};
    
            Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    
            NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                    .setSmallIcon(R.drawable.ic_stat_name)
                    .setContentTitle(messageTitle)
                    .setContentText(messageBody)
                    .setAutoCancel(true)
                    .setVibrate(pattern)
                    .setLights(Color.BLUE,1,1)
                    .setSound(defaultSoundUri)
                    .setContentIntent(pendingIntent);
    
            NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
        }
    

    【讨论】:

    • 谢谢..我更改了我的服务器代码并使用“数据”而不是“通知”,现在它运行完美,
    • @Koot 仅当应用程序在前台而不是在后台时才有效。你能帮我在这两种情况下触发这个事件吗??
    • @AnantShah 您对 Firebase 服务器的 POST 是什么样的?
    • 这里实际上有三种可能的情况。 1)前台应用。 2)后台应用程序。 3) 应用程序未运行。正如您所说,在前两种情况下会收到一条“数据”消息,但在第三种情况下,当应用程序未运行时,不会。为了满足所有三种情况,您需要在消息中设置“通知”字段。 (如果您想同时支持 iOS 和 Android 客户端,这也是一个好主意)
    • 即使在应用程序没有运行的情况下,我仍然会在 onmessagereceived 函数上从服务器收到一条消息。我同意你的观点,如果你也想支持 ios,最好使用“通知”。
    【解决方案4】:

    根据 Firebase 云消息传递文档 - 如果 Activity 处于前台,则将调用 onMessageReceived。如果 Activity 在后台或关闭,则通知中心会显示应用启动器活动的通知消息。 如果您的应用在后台,您可以通过单击通知来调用您的自定义活动,方法是调用 rest 服务 api 进行 firebase 消息传递:

    网址-https://fcm.googleapis.com/fcm/send

    方法类型 - POST

    Header- Content-Type:application/json
    Authorization:key=your api key
    

    身体/有效载荷:

    { "notification": {
        "title": "Your Title",
        "text": "Your Text",
         "click_action": "OPEN_ACTIVITY_1" // should match to your intent filter
      },
        "data": {
        "keyname": "any value " //you can get this data as extras in your activity and this data is optional
        },
      "to" : "to_id(firebase refreshedToken)"
    } 
    

    在您的应用程序中,您可以在要调用的活动中添加以下代码:

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

    【讨论】:

    • 我应该在哪里创建意图并让它打开一个特定的活动?我知道这会在清单中注册 OPEN_ACTIVITY_1 意图,但我实际上在哪里调用它?
    • 我们应该从意图过滤器中调用一个活动吗?还是在onMessageReceived手动启动?
    【解决方案5】:

    默认情况下,当您的应用程序处于后台并单击通知时,应用程序中的Launcher Activity 将启动,如果您的通知中有任何数据部分,您可以在相同的活动中处理它,如下所示,

    if(getIntent().getExtras()! = null){
      //do your stuff
    }else{
      //do that you normally do
    }
    

    【讨论】:

    • 如果我从 mainActivity 导航,如何导航回特定的 Activity?
    • @Uzair getIntent().getExtras() 总是为空,你还有其他解决方案吗?当应用程序运行时,onMessageReceived 方法不调用
    【解决方案6】:

    我遇到了同样的问题,并对此进行了更多挖掘。当应用程序在后台时,会向系统托盘发送通知消息,但会向onMessageReceived()
    发送数据消息https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3
    https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java

    为了确保您发送的消息,文档说,“使用您的应用服务器和 FCM 服务器 API:仅设置数据密钥。可以是可折叠的或不可折叠的。” 见https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

    【讨论】:

      【解决方案7】:

      有两种类型的消息:通知消息和数据消息。 如果您只发送数据消息,则消息字符串中没有通知对象。当您的应用在后台时会调用它。

      【讨论】:

        【解决方案8】:

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

        Firebase 具有三种消息类型

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

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

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

        另外,我建议您使用 onMessageReceived 方法(请参阅数据消息)来提取数据包。根据您的逻辑,我检查了 bundle 对象并没有找到预期的数据内容。这是对类似案例的参考,可能会提供更清晰的信息。

        从服务器端,firebase 通知应采用以下格式

        服务器端应该发送 "notification" 对象。我的TargetActivity 中缺少“通知”对象没有使用getIntent() 收到消息。

        正确的消息格式如下:

        {
         "data": {
          "body": "here is body",
          "title": "Title"
         },
        "notification": {
          "body": "here is body",
          "title": "Title",
          "click_action": "YOUR_ACTION"
         },
         "to": "ffEseX6vwcM:APA91bF8m7wOF MY FCM ID 07j1aPUb"
        }
        

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

        更多信息请访问我的this threadthis thread

        【讨论】:

        • 值得一提的是,如果设备处于深度休眠模式(Android 7.0 中引入),将不会收到“数据消息”。小心那些!
        【解决方案9】:

        值得强调的一点是,即使应用程序在后台,您也必须使用数据消息 - 仅数据键 - 才能调用 onMessageReceived 处理程序。您的有效负载中不应有任何其他通知消息键,否则如果应用程序在后台,处理程序将不会被触发。

        此处提到(但在 FCM 文档中并未如此强调):

        https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages

        使用您的应用服务器和 FCM 服务器 API:设置 仅数据密钥。可 可折叠或不可折叠。

        【讨论】:

          【解决方案10】:

          从您的服务器请求中完全删除 notification 字段仅发送data 并在onMessageReceived() 中处理它,否则您的onMessageReceived() 将不会在应用处于后台或被终止时触发。

          不要忘记在您的通知请求中包含"priority": "high" 字段。根据文档:数据消息以正常优先级发送,因此它们不会立即到达;这也可能是问题所在。

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

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

          所以你可以像这样在onMessageReceived(RemoteMessage message) 接收你的数据....假设我必须得到 id

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

          【讨论】:

          • 我发现如果我只发送数据消息,那么从任务管理器中清除的应用程序将无法收到通知。这是预期的行为吗?
          • 这是我在后台接收消息的解决方案!
          • 在奥利奥中,当应用程序被杀死时,onMessageReceived 不会被调用。我只有数据的有效载荷。你有什么更新吗?
          • 像魅力一样工作!
          • 非常喜欢你这个答案:p
          【解决方案11】:

          我正在使用的后端使用的是通知消息,而不是数据消息。因此,在阅读了所有答案后,我试图从启动活动的意图包中检索额外内容。 但无论我尝试从getIntent().getExtras(); 检索哪些键,该值始终为空。

          不过,我终于找到了一种使用通知消息发送数据并从意图中检索数据的方法。

          这里的关键是将数据负载添加到通知消息中。

          例子:

          {
              "data": {
                  "message": "message_body",
                  "title": "message_title"
              },
              "notification": {
                  "body": "test body",
                  "title": "test title"
              },
              "to": "E4An.."
          }
          

          完成此操作后,您将能够通过以下方式获取您的信息:

          intent.getExtras().getString("title") 将是message_title

          intent.getExtras().getString("message") 将是message_body

          Reference

          【讨论】:

            【解决方案12】:

            只需在 MainActivity 的 onCreate 方法中调用它即可:

            if (getIntent().getExtras() != null) {
                       // Call your NotificationActivity here..
                        Intent intent = new Intent(MainActivity.this, NotificationActivity.class);
                        startActivity(intent);
                    }
            

            【讨论】:

            • 如果我从 mainActivity 导航,如何导航回特定的 Activity?
            【解决方案13】:

            如果应用程序处于后台模式或非活动状态(已终止),并且您在 Notification单击,则应在 LaunchScreen(在我的情况下为启动屏幕)中检查有效负载是 MainActivity.java)。

            所以在 onCreate 上的 MainActivity.java 中检查 Extras

                if (getIntent().getExtras() != null) {
                    for (String key : getIntent().getExtras().keySet()) {
                        Object value = getIntent().getExtras().get(key);
                        Log.d("MainActivity: ", "Key: " + key + " Value: " + value);
                    }
                }
            

            【讨论】:

            • 如何获取通知标题、正文和数据?
            • 谢谢,这就是答案。 @Md.Tarikul Islam 使用 onMessageReceived() 如本问题所述。
            【解决方案14】:

            如果您的问题与显示大图像有关,即如果您从 firebase 控制台发送带有图像的推送通知,并且仅当应用程序在前台时才显示图像。此问题的解决方案是发送仅包含数据字段的推送消息。像这样的:

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

            【讨论】:

            • 您在“AnotherActivity”之前丢失了逗号。我的 android 振动,但实际上什么也没显示(没有文字、没有图像、没有推送)。
            【解决方案15】:

            这个方法handleIntent()已经被弃用了,所以处理一个通知可以如下:

            1. 前台状态:单击通知将转到您在以编程方式创建通知时提供的待处理 Intent 活动,因为它通常使用通知的数据有效负载创建。

            2. Background/Killed State - 在这里,系统本身会根据通知负载创建一个通知,单击该通知将带您进入应用程序的启动器活动,您可以在其中轻松获取任何生活中的 Intent 数据-循环方法。

            【讨论】:

            • 谢谢!!!我在这个问题上浪费了几天时间,这个问题救了我。
            • 真的是完美的解决方案!
            • 我正在处理handleIntent(Intent intent)中的通知显示逻辑,但是当应用程序在后台时,会显示2个通知,一个是我创建的,另一个默认包含来自通知的整个消息.
            • 太棒了,但在这种情况下我看不出OnMessageReceived 有什么用处!?
            • 我有 com.google.firebase:firebase-messaging:11.6.2 & handleIntent 现在是最终的。检查stackoverflow.com/questions/47308155/…
            【解决方案16】:

            覆盖FirebaseMessageServicehandleIntent 方法对我有用。

            这里是 C# (Xamarin) 中的代码

            public override void HandleIntent(Intent intent)
            {
                try
                {
                    if (intent.Extras != null)
                    {
                        var builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            
                        foreach (string key in intent.Extras.KeySet())
                        {
                            builder.AddData(key, intent.Extras.Get(key).ToString());
                        }
            
                        this.OnMessageReceived(builder.Build());
                    }
                    else
                    {
                        base.HandleIntent(intent);
                    }
                }
                catch (Exception)
                {
                    base.HandleIntent(intent);
                }
            }
            

            这就是 Java

            中的代码
            public void handleIntent(Intent intent)
            {
                try
                {
                    if (intent.getExtras() != null)
                    {
                        RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            
                        for (String key : intent.getExtras().keySet())
                        {
                            builder.addData(key, intent.getExtras().get(key).toString());
                        }
            
                        onMessageReceived(builder.build());
                    }
                    else
                    {
                        super.handleIntent(intent);
                    }
                }
                catch (Exception e)
                {
                    super.handleIntent(intent);
                }
            }
            

            【讨论】:

            • handleIntent() 是最终的
            • @Ettore 如何调用 handleIntent 函数?
            • 当你收到来自 Firebase 的消息时调用该方法,但你不能覆盖,因为该方法被声明为 final。 (Firebase 11.6.0)
            【解决方案17】:

            根据 t3h Exi 的解决方案,我想在此处发布干净的代码。只需将其放入 MyFirebaseMessagingService 中,如果应用程序处于后台模式,一切正常。你至少需要编译 com.google.firebase:firebase-messaging:10.2.1

             @Override
            public void handleIntent(Intent intent)
            {
                try
                {
                    if (intent.getExtras() != null)
                    {
                        RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            
                        for (String key : intent.getExtras().keySet())
                        {
                            builder.addData(key, intent.getExtras().get(key).toString());
                        }
            
            
            
                       onMessageReceived(builder.build());
                    }
                    else
                    {
                        super.handleIntent(intent);
                    }
                }
                catch (Exception e)
                {
                    super.handleIntent(intent);
                }
            }
            

            【讨论】:

            • 我正在尝试实现您的解决方案,但 handleIntent() 方法在我的 SDK 版本(SDK 27)中是最终的,所以我无法在我的服务中覆盖它...
            • 是的,但这不是我的错,也不是给-1的任何理由!很嚣张。它一直有效,直到 firebase 11.4.2 然后谷歌改变了它(使这个方法最终)。所以现在你必须编写自己的带有通知的解决方案。
            • 我没有给 -1 而是给 +1 !
            • 你救了我的工作:P
            【解决方案18】:

            我遇到了同样的问题。如果应用程序在前台 - 它会触发我的后台服务,我可以在其中根据通知类型更新我的数据库。 但是,应用程序会进入后台 - 默认通知服务会小心地向用户显示通知。

            这是我在后台识别应用并触发后台服务的解决方案,

            public class FirebaseBackgroundService extends WakefulBroadcastReceiver {
            
              private static final String TAG = "FirebaseService";
            
              @Override
              public void onReceive(Context context, Intent intent) {
                Log.d(TAG, "I'm in!!!");
            
                if (intent.getExtras() != null) {
                  for (String key : intent.getExtras().keySet()) {
                    Object value = intent.getExtras().get(key);
                    Log.e("FirebaseDataReceiver", "Key: " + key + " Value: " + value);
                    if(key.equalsIgnoreCase("gcm.notification.body") && value != null) {
                      Bundle bundle = new Bundle();
                      Intent backgroundIntent = new Intent(context, BackgroundSyncJobService.class);
                      bundle.putString("push_message", value + "");
                      backgroundIntent.putExtras(bundle);
                      context.startService(backgroundIntent);
                    }
                  }
                }
              }
            }
            

            在 manifest.xml 中

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

            在最新的 android 8.0 版本中测试了这个解决方案。谢谢

            【讨论】:

            • 要使用这个 FirebaseBackgroundService 类吗? @Nagendra Badiganti
            • 在哪里使用此代码 public class FirebaseBackgroundService extends WakefulBroadcastReceiver @Nagendra Badiganti
            • 在您的包中创建一个服务类并在您的 manifest.xml 中注册。确保您有通知过滤器。因为服务会针对每个 GCM 通知触发。
            • firebase.google.com/docs/cloud-messaging/android/… 我正在关注此链接,我需要添加此类以接收通知。只是从firebase第一条消息发送消息..它说完成但没有收到通知@Nagendra Badiganti
            • WakefulBroadcastReceiver 自 API 级别 26.1.0 起已弃用。
            【解决方案19】:

            如果应用程序在后台 Fire-base 默认处理通知但是如果我们想要自定义通知,那么我们必须更改我们的服务器端,它负责发送我们的自定义数据(数据有效负载)

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

            现在,你的服务器端代码格式看起来像,

            {
              "collapse_key": "CHAT_MESSAGE_CONTACT",
              "data": {
                "loc_key": "CHAT_MESSAGE_CONTACT",
                "loc_args": ["John Doe", "Contact Exchange"],
                "text": "John Doe shared a contact in the group Contact Exchange",
                "custom": {
                  "chat_id": 241233,
                  "msg_id": 123
                },
                "badge": 1,
                "sound": "sound1.mp3",
                "mute": true
              }
            }
            

            注意:见上述代码中的这一行
            "text": "John Doe 在群组联系人交流中分享了一个联系人" 在数据负载中,您应该使用“text”参数而不是“body”或“message”参数来进行消息描述或任何您想使用的文本。

            onMessageReceived()

            @Override
                public void onMessageReceived(RemoteMessage remoteMessage) {
                    Log.e(TAG, "From: " + remoteMessage.getData().toString());
            
                    if (remoteMessage == null)
                        return;
            
                    // Check if message contains a data payload.
                    if (remoteMessage.getData().size() > 0) {
                       /* Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());*/
                        Log.e(TAG, "Data Payload: " + remoteMessage);
            
                        try {
            
                            Map<String, String> params = remoteMessage.getData();
                            JSONObject json = new JSONObject(params);
                            Log.e("JSON_OBJECT", json.toString());
            
            
                            Log.e(TAG, "onMessageReceived: " + json.toString());
            
                            handleDataMessage(json);
                        } catch (Exception e) {
                            Log.e(TAG, "Exception: " + e.getMessage());
                        }
                    }
                }
            

            【讨论】:

              【解决方案20】:

              试试这个:

              public void handleIntent(Intent intent) {
                  try {
                      if (intent.getExtras() != null) {
                          RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
                          for (String key : intent.getExtras().keySet()) {
                          builder.addData(key, intent.getExtras().get(key).toString());
                      }
                          onMessageReceived(builder.build());
                      } else {
                          super.handleIntent(intent);
                      }
                  } catch (Exception e) {
                      super.handleIntent(intent);
                  }
              }
              

              【讨论】:

              • handleIntent 不再用于 firebase:11.8.0 及更高版本。
              【解决方案21】:

              只需覆盖 FirebaseMessagingService 的 OnCreate 方法。当您的应用在后台时调用它:

              public override void OnCreate()
              {
                  // your code
                  base.OnCreate();
              }
              

              【讨论】:

              • 如果您可以添加解释并链接到某些文档,此答案可能会更有用。你能告诉我们这应该有什么帮助吗?
              • @kilokahn 你能解释一下你不明白的地方吗?指示的方法必须插入作为问题一部分并完全回答问题的代码中。该代码适用于 Xamarin,但您可以简单地在 java 中转换。
              • AFAIK 官方文档 (firebase.google.com/docs/cloud-messaging/android/client) 没有谈到在扩展 FirebaseMessagingService 的服务中覆盖 OnCreate - 如果您可以访问相关文档,也许您可​​以分享一个链接?此外,从您的回答来看,尚不清楚覆盖 onCreate 如何解决单击通知时未调用 onMessageReceived 的问题 - 因此请求提供更多信息。
              • 文档没有提到 OnCreate 方法的覆盖,但它可以工作,因为我在生产中使用它。您想在 onMessageReceived 方法中插入的代码显然用于执行一些后台操作,可以在 OnCreate 上执行。
              • 在这种情况下,详细说明它对您有用的事实可能比仅仅列出解决方案更有帮助。此外,未记录的行为可能会任意停止使用更新,并且使用它们的人必须准备好在更新时重新编写他们的代码。需要填写此免责声明。
              【解决方案22】:

              当收到消息并且您的应用处于后台时,通知将发送到主要活动的额外意图。

              您可以在主活动的 oncreate() 或 onresume() 函数中检查额外的值。

              您可以检查数据、表格等字段(通知中指定的字段)

              例如我使用数据作为密钥发送

              public void onResume(){
                  super.onResume();
                  if (getIntent().getStringExtra("data")!=null){
                          fromnotification=true;
                          Intent i = new Intent(MainActivity.this, Activity2.class);
                          i.putExtra("notification","notification");
                          startActivity(i);
                      }
              
              }
              

              【讨论】:

                【解决方案23】:

                Firebase 推送通知有 2 种

                1- 通知消息(显示消息)-> -- 1.1 如果您选择此变体,如果应用程序在Background 中,操作系统将创建它自己的通知,并将在intent 中传递数据。然后由客户端来处理这些数据。

                -- 1.2 如果应用在Foreground,那么它将通过callback-functionFirebaseMessagingService中的callback-function收到通知,由客户端处理。

                2- 数据消息(最多 4k 数据)-> 这些消息用于仅向客户端发送数据(静默),并且由客户端通过 @ 中的回调函数在后台/前台两种情况下处理它987654325@

                这是根据官方文档:https://firebase.google.com/docs/cloud-messaging/concept-options

                【讨论】:

                  【解决方案24】:

                  onMessageReceived(RemoteMessage remoteMessage)方法基于以下情况调用。

                  • FCM 响应带有通知数据块:
                  {
                    
                  "to": "device token list",
                    "notification": {
                      "body": "Body of Your Notification",
                      "title": "Title of Your Notification"
                    },
                    "data": {
                      "body": "Body of Your Notification in Data",
                      "title": "Title of Your Notification in Title",
                      "key_1": "Value for key_1",
                      "image_url": "www.abc.com/xyz.jpeg",
                      "key_2": "Value for key_2"
                    }
                  }
                  
                  1. 前台应用:

                  onMessageReceived(RemoteMessage remoteMessage) 调用,在通知栏中显示 LargeIcon 和 BigPicture。我们可以从 notificationdata

                  中读取内容
                  1. 后台应用:

                  onMessageReceived(RemoteMessage remoteMessage) 未调用,系统托盘将接收消息并从 通知 块中读取正文和标题,并在通知栏中显示默认消息和标题。

                  • FCM 响应仅使用 数据 块:

                  在这种情况下,从 json 中删除 通知

                  {
                    
                  "to": "device token list",
                    "data": {
                      "body": "Body of Your Notification in Data",
                      "title": "Title of Your Notification in Title",
                      "key_1": "Value for key_1",
                      "image_url": "www.abc.com/xyz.jpeg",
                      "key_2": "Value for key_2"
                    }
                  }
                  

                  调用onMessageReceived()的解决方案

                  1. 前台应用:

                  onMessageReceived(RemoteMessage remoteMessage) 调用,在通知栏中显示 LargeIcon 和 BigPicture。我们可以从 notificationdata

                  中读取内容
                  1. 后台应用:

                  onMessageReceived(RemoteMessage remoteMessage) 调用,系统托盘将不会收到消息,因为 notification 键不在响应中。在通知栏中显示 LargeIcon 和 BigPicture

                  代码

                   private void sendNotification(Bitmap bitmap,  String title, String 
                      message, PendingIntent resultPendingIntent) {
                  
                      NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
                      style.bigPicture(bitmap);
                  
                      Uri defaultSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
                  
                      NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
                      String NOTIFICATION_CHANNEL_ID = mContext.getString(R.string.default_notification_channel_id);
                  
                      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                          NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);
                  
                          notificationManager.createNotificationChannel(notificationChannel);
                      }
                      Bitmap iconLarge = BitmapFactory.decodeResource(mContext.getResources(),
                              R.drawable.mdmlogo);
                      NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                              .setSmallIcon(R.drawable.mdmlogo)
                              .setContentTitle(title)
                              .setAutoCancel(true)
                              .setSound(defaultSound)
                              .setContentText(message)
                              .setContentIntent(resultPendingIntent)
                              .setStyle(style)
                              .setLargeIcon(iconLarge)
                              .setWhen(System.currentTimeMillis())
                              .setPriority(Notification.PRIORITY_MAX)
                              .setChannelId(NOTIFICATION_CHANNEL_ID);
                  
                  
                      notificationManager.notify(1, notificationBuilder.build());
                  
                  
                  }
                  

                  参考链接:

                  https://firebase.google.com/docs/cloud-messaging/android/receive

                  【讨论】:

                  • 对于遭受背景问题的人来说,最重要的部分是从服务器发送的 JSON 中删除“通知”属性。这解决了这个问题。非常感谢。
                  【解决方案25】:

                  检查@Mahesh Kavathiya 的答案。就我而言,在服务器代码中只有这样:

                  {
                  "notification": {
                    "body": "here is body",
                    "title": "Title",
                   },
                   "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
                  }
                  

                  你需要改成:

                  {
                   "data": {
                    "body": "here is body",
                    "title": "Title",
                    "click_action": "YOUR_ACTION"
                   },
                  "notification": {
                    "body": "here is body",
                    "title": "Title"
                   },
                   "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
                  }
                  

                  然后,如果应用程序在后台,默认的活动意图额外将获得“数据”

                  祝你好运!

                  【讨论】:

                    【解决方案26】:

                    你可以在你的主 Activity 中尝试这个,当在后台时

                       if (getIntent().getExtras() != null) {
                                for (String key : getIntent().getExtras().keySet()) {
                                    Object value = getIntent().getExtras().get(key);
                                    Log.d(TAG, "Key: " + key + " Value: " + value);
                                }
                            }
                    

                    检查following project作为参考

                    【讨论】:

                      【解决方案27】:

                      我有类似的问题。根据本页中提到的答案和参考资料,以下是我如何通过以下方法解决问题的两分钱:

                      我之前的消息格式如下:

                          {
                        "notification": {
                          "title": "AppName",
                          "sound": null,
                          "body": "Hey!YouhaveaMessage"
                        },
                        "data": {
                          "param1": null,
                          "param2": [
                            238
                          ],
                          "id": 1
                        },
                        "to": "--the device push token here--"
                      }
                      

                      我将消息格式修改为如下:

                          {
                        "data": {
                          "title": "AppName",
                          "body": "Hey! You have a message",
                          "param1": null,
                          "param2": [
                            238
                          ],
                          "id": 1
                        },
                        "priority": "high",
                        "to": " — device push token here — "
                      }
                      

                      然后我从“数据”负载本身中检索了标题、正文和所有参数。这解决了问题,即使应用程序在后台,我也可以获得 OnMessageReceived 回调。 我写了一篇博文解释了同样的问题,你可以找到它here

                      【讨论】:

                      • 请将 更改为"。实际上,它不是一个有效的 JSON。
                      • 感谢您指出这一点。我现在已经修复了引号以生成有效的 JSON。
                      【解决方案28】:

                      我在这里回答可能很晚,但官方文档有点混乱。

                      还明确说明有两种通知方式

                      • 通知消息:由 FCM 自动处理
                      • 数据消息:由客户端应用处理。

                      毫无疑问,如果服务器发送数据消息,那么 onMessageReceived() 方法肯定会被调用,但在通知消息的情况下,onMessageReceived() 方法只会在应用程序处于前台且应用程序处于后台时被调用我们发送的数据只是空的。

                      示例:

                      假设服务器正在发送通知消息类型:

                      A.如果是前景:

                      • remoteMessage.data["key"] 可以工作

                      B. 如果是背景: -remoteMessage.data["key"] 将返回 null 但是在这里,如果您在使用 getIntent().getExtras().getString("key") 的默认活动中发现相同的意图数据将起作用

                      C. 如果被杀: -remoteMessage.data["key"] 将返回 null 但是在这里,如果您在使用 getIntent().getExtras().getString("key") 的默认活动中发现相同的意图数据将起作用

                      现在,假设服务器正在发送数据消息类型:

                      D.如果是前景:

                      • remoteMessage.data["key"] 可以工作

                      E.如果是背景:

                      • remoteMessage.data["key"] 可以工作

                      F.如果被杀:

                      • remoteMessage.data["key"] 可以工作

                      毫无疑问,数据消息总是会调用 onMessageReceived() 方法,但在通知消息和应用处于后台/杀死状态的情况下,您可以使用 B 的解决方案。谢谢

                      我希望它能节省大家的时间。

                      【讨论】:

                        猜你喜欢
                        • 2017-01-14
                        • 1970-01-01
                        • 1970-01-01
                        • 2017-04-21
                        • 1970-01-01
                        相关资源
                        最近更新 更多