首页 文章

当应用程序在后台时,Firebase onMessageReceived未被调用

提问于
浏览
160

我正在使用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"));
        }
    }
}

23 回答

  • 1

    只需覆盖FirebaseMessagingService的OnCreate方法即可 . 当您的应用处于后台时调用它:

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

    有两种类型的消息:通知消息和数据消息 . 如果您只发送数据消息,那就没有了消息字符串中的通知对象 . 它将在您的应用程序在后台调用 .

  • 20

    这是按预期工作的,只有当您的应用位于前台时,通知消息才会传递到您的onMessageReceived回调 . 如果您的应用在后台或已关闭,则会在通知中心显示通知消息,以及由于用户点击通知而启动的任何 data from that message is passed to the intent .

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

    当意图启动时,您可以使用

    getIntent().getExtras();
    

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

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

  • 19

    Remove notification field 完全来自您的服务器请求 . 发送 only data 并在 onMessageReceived() 处理它,否则当应用程序处于后台或被杀时,您的 onMessageReceived() 将不会被触发 .

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

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

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

    所以你可以像这样在 onMessageReceived(RemoteMessage message) 收到你的数据....让我说我必须得到身份证明

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

    DEPRECATED SOLUTION:

    我有一个完美的解决方案:

    您需要执行两个简单的步骤:

    • 将您的firebase升级到版本编译 com.google.firebase:firebase-messaging:10.2.1

    • 覆盖 FirebaseMessagingService 类中的 handleIntent(Intent intent) 方法 .

    无论app处于前景,后台还是被杀死状态,每次都会调用 handleIntent() 方法 .

  • 8

    我有同样的问题 . 使用“数据消息”而不是“通知”更容易 . 数据消息始终加载类onMessageReceived .

    在该课程中,您可以使用notificationbuilder自行发出通知 .

    例:

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

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

    Firebase has three message types

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

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

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

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

    欲了解更多信息,请访问我的this thread

  • 8

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

    您可以检查主活动的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);
            }
    
    }
    
  • 60

    根据Firebase Cloud Messaging文档 - 如果Activity在前台,则将调用onMessageReceived . 如果“活动”处于后台或已关闭,则通知中心会显示应用启动器活动的通知消息 . 如果您的应用处于后台,可以通过调用用于firebase消息传递的rest service api来点击通知来调用您的自定义活动:

    URL- 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>
    
  • 96

    如果app处于后台模式或处于非活动状态(已终止),并且 clickNotification 上,则应检查LaunchScreen中的有效负载(在我的情况下,启动屏幕为MainActivity.java) .

    所以在 MainActivity.javaonCreate 检查 Extras

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

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

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

    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版本中测试了这个解决方案 . 谢谢

  • 11

    覆盖 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);
        }
    }
    
  • 3

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

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

    即使应用程序已关闭,背景也在前台,我已经实现了这种简单的方式来发送消息 . 我之前使用的是 firebase 控制台,但我只收到消息,而不是图像和自定义数据 .

    要使用图像发送此自定义数据,您可以使用名为 AdvancedREST Client 的工具,它是Chrome扩展程序,并使用以下参数发送消息:

    Rest client tool Link: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo
    

    使用这个 url:- https://fcm.googleapis.com/fcm/send Content-Type:application/json Authorization:key=Your Server key From or Authorization key (见下面参考)

    { "data": 
      { "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg", 
        "message": "Firebase Push Message Using API" 
        "AnotherActivity": "True" 
      }, 
      "to" : "device id Or Device token" 
    }
    

    可以通过访问Google开发人员控制台并单击项目左侧菜单上的“凭据”按钮来获取授权密钥 . 在列出的API密钥中,服务器密钥将是您的授权密钥 .

    并且您需要将 tokenID 接收器放在使用API发送的 POST 请求的 to 部分中 .

    这段android代码//消息将包含Push消息

    String message = remoteMessage.getData().get("message1");
    
    //imageUri will contain URL of the image to be displayed with Notification
    String imageUri = remoteMessage.getData().get("image");
    
    //If the key AnotherActivity has  value as True then when the user taps on notification, in the app AnotherActivity will be opened.
    //If the key AnotherActivity has  value as False then when the user taps on notification, in the app MainActivity2 will be opened.
    String TrueOrFlase = remoteMessage.getData().get("AnotherActivity");
    
    //To get a Bitmap image from the URL received
    bitmap = getBitmapfromUrl(imageUri);
    
    sendNotification(message, bitmap, TrueOrFlase);
    
  • 1

    如果应用程序在后台默认处理通知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
      }
    }
    

    NOTE :在上面的代码中看到这一行
    "text":"John Doe shared a contact in the group Contact Exchange"在数据有效负载中,您应使用"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());
                }
            }
        }
    
  • 2

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

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

    根据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);
        }
    }
    
  • 5

    试试这个:

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

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

  • 0

    我遇到了同样的问题,并对此进行了更多的挖掘 . 当应用程序在后台时, notification message 被发送到系统托盘,但是 data message 被发送到 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

  • 1

    值得强调的一点是,即使应用程序处于后台,您也必须使用数据消息-- data key only 来获取onMessageReceived处理程序 . 如果应用程序处于后台,您不应该被触发 .

    这里提到了(但在FCM文档中没有这么强调):

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

    使用您的应用服务器和FCM服务器API:仅设置数据密钥 . 可以是可折叠的,也可以是不可折叠的 .

  • 5

    我正在使用的后端是使用 Notification messages 而不是数据消息 . 因此,在阅读完所有答案之后,我试图从发起活动的意图包中检索额外内容 . 但无论我试图从 getIntent().getExtras(); 检索哪些键,该值始终为null .

    但是,我终于找到了一种使用 Notification messages 发送数据的方法,并从意图中检索它 .

    这里的关键是将 data payload 添加到Notification消息中 .

    例:

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

  • 24

    如果您的问题与显示大图像有关,即您是否使用来自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" }
    

相关问题