Firebase onMessageReceived未在后台应用中调用
我正在使用Firebase,并在应用程序处于后台时从我的服务器向我的应用程序发送通知。 通知发送成功,它甚至出现在设备的通知中心,但是当通知出现时,或者即使点击它,我的FCMessagingService中的onMessageReceived方法也不会被调用。
当我testing这个时,我的应用程序在前台,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")); } } }
这是按预期工作,只有当您的应用程序在前台时,通知消息才会传递给您的onMessageReceivedcallback。 如果您的应用程序处于后台或closures状态,则会在通知中心显示通知消息,并且来自该消息的任何数据都将传递到由于用户点击通知而启动的意图 。
您可以指定click_action来指示用户点击通知时应启动的意图。 如果没有指定click_action,则使用主要活动。
当意图启动时,您可以使用
getIntent().getExtras();
检索一个包含与通知消息一起发送的任何数据的Set。
有关通知消息的更多信息,请参阅文档 。
我有一个完美的解决scheme:
你需要执行2个简单的步骤:
- 将您的firebase升级到版本,编译
com.google.firebase:firebase-messaging:10.2.1
- 覆盖
FirebaseMessagingService
类中的handleIntent(Intent intent)
方法。
handleIntent()
方法每次调用是否应用程序处于前景,背景或死亡状态。
从您的服务器请求中完全删除通知有效载 只发送数据并在onMessageReceived()中处理,否则当应用程序处于后台或被终止时,onMessageReceived不会被触发。
这是我从服务器发送的内容
{ "data":{ "id": 1, "missedRequests": 5 "addAnyDataHere": 123 }, "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......" }
所以你可以在onMessageReceived(RemoteMessage消息)这样的接收你的数据….让我说我必须得到ID
Object obj = message.getData().get("id"); if (obj != null) { int id = Integer.valueOf(obj.toString()); }
我有同样的问题。 使用“数据信息”而不是“通知”更容易。 数据消息总是加载类onMessageReceived。
在那个类中,你可以使用通知构build器自己做出通知。
例:
@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()); }
根据Firebase云消息传递文档 – 如果Activity位于前台,则onMessageReceived将被调用。 如果“活动”处于后台或closures状态,则会在通知中心显示通知消息以显示应用启动器活动。 如果您的应用在后台,则可以通过点击通知来调用您的自定义活动,方法是调用restbase messaging的rest service api,如下所示:
urlhttps://fcm.googleapis.com/fcm/send
方法types – 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>
这里是关于firebase消息的更清晰的概念。 我从他们的支持团队find了它。
Firebase有三种消息types :
通知消息 :通知消息在后台或前台工作。 当应用程序在后台时,通知消息被传递到系统托盘。 如果应用程序处于前台,则消息由onMessageReceived()
或didReceiveRemoteNotification
callback处理。 这些实质上就是所谓的显示消息。
数据信息 :在Android平台上,数据信息可以在后台和前台工作。 数据消息将由onMessageReceived()处理。 这里的平台特定的注意事项是:在Android上,数据有效载荷可以在用于启动您的活动的Intent中检索。 详细说明一下,如果你有"click_action":"launch_Activity_1"
,你可以通过只有Activity_1
getIntent()
来获取这个intent。
具有通知和数据有效载荷的消息 :在后台时,应用程序在通知托盘中接收通知有效内容,并且只在用户点击通知时处理数据有效载荷。 在前台时,您的应用程序会收到一个消息对象,其中都有可用的有效负载。 其次,click_action参数通常用于通知有效载荷,而不是数据有效载荷。 如果在数据有效负载中使用,则此参数将被视为自定义键值对,因此您需要实现自定义逻辑才能按预期工作。
此外,我build议您使用onMessageReceived方法(请参阅数据消息)来提取数据包。 从你的逻辑,我检查了捆绑对象,并没有find预期的数据内容。 这里提供一个类似的案例,可能会提供更多的清晰度。
更多信息请访问我的这个线程
如果应用程序处于后台模式或不活动(杀死),并且您单击 通知 ,您应该检查LaunchScreen中的有效载荷(在我的启动屏幕是MainActivity.java)。
所以在MainActivity.java上onCreate检查Extras :
if (getIntent().getExtras() != null) { for (String key : getIntent().getExtras().keySet()) { Object value = getIntent().getExtras().get(key); Log.d("MainActivity: ", "Key: " + key + " Value: " + value); } }
默认情况下,当您的应用程序处于后台时,您的应用程序中的启动器活动将启动,并且您单击该通知,如果您的通知中有任何数据部分,则可以在以下相同的活动中处理该通知,
if(getIntent().getExtras()! = null){ //do your stuff }else{ //do that you normally do }
我已经实现了这种简单的方式来发送消息,即使应用程序已closures,背景和前景。 我以前使用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开发者控制台并点击项目左侧菜单上的Credentialsbutton来获得。 列出的API密钥中,服务器密钥将是您的授权密钥。
而且您需要将接收器的tokenID
放在使用API发送的POST
请求的部分中。
而这段android代码//消息将包含推送消息
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);
只需在您的MainActivity的onCreate方法中调用它:
if (getIntent().getExtras() != null) { // Call your NotificationActivity here.. Intent intent = new Intent(MainActivity.this, NotificationActivity.class); startActivity(intent); }
我有这个问题(应用程序不希望打开通知点击,如果应用程序在后台或closures),并且问题是通知正文中的一个无效的click_action
,尝试删除或更改为有效的东西。
我有同样的问题,并做了更多的挖掘。 当应用程序在后台时, 通知消息被发送到系统托盘,但数据消息发送到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
有两种types的消息:通知消息和数据消息。 如果您只发送数据消息,那么在消息string中没有通知对象。 这将在您的应用程序在后台时被调用。
值得强调的一点是,即使在应用程序处于后台时,您也必须使用数据消息 – 数据键来获取onMessageReceived处理函数。 您的有效载荷中不应该有任何其他通知消息密钥,否则如果应用程序在后台,处理程序将不会被触发。
这里提到(但在FCM文档中没有这么强调):
https://firebase.google.com/docs/cloud-messaging/concept-options#notifications_and_data_messages
使用您的应用程序服务器和FCM服务器API: 仅设置数据密钥 。 可以是可折叠的或不可折叠的。
我正在使用的后端是使用通知消息,而不是数据消息。 所以在阅读所有的答案后,我尝试从已经启动的活动的意图集合中检索额外信息。 但是,无论我试图从getIntent().getExtras();
检索哪个键getIntent().getExtras();
该值始终为空。
但是,我终于find了使用通知消息发送数据并从意图中检索数据的方法。
这里的关键是将数据有效载荷添加到通知消息。
例:
{ "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
参考
如果您的问题与显示大图像相关,也就是说,如果您使用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" }
覆盖FirebaseMessageService
的handleIntent
方法适用于我。
这里的代码在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中的代码(未经testing)
public void handleIntent(Intent intent) { try { if (intent.getExtras() != null) { RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService"); foreach (string key : intent.getExtras().KeySet()) { builder.addData(key, intent.getExtras().Get(key).toString()); } this.OnMessageReceived(builder.build()); } else { base.handleIntent(intent); } } catch (Exception) { base.handleIntent(intent); } }
根据t3h Exi的解决scheme,我想在这里发布干净的代码。 只要把它放到MyFirebaseMessagingService,一切正常,如果应用程序在后台模式。 您至less需要编译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); } }