Cyo*_*nos 201 android firebase firebase-cloud-messaging
我正在使用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"));
}
}
}
Run Code Online (Sandbox Code Playgroud)
Art*_*son 123
这是按预期工作的,只有当您的应用位于前台时,通知消息才会传递到您的onMessageReceived回调.如果您的应用程序处于后台或已关闭,则通知中心会显示通知消息,并且该消息中的任何数据都会传递给由于用户点击通知而启动的意图.
您可以指定click_action以指示在用户点击通知时应启动的意图.如果未指定click_action,则使用主活动.
当意图启动时,您可以使用
getIntent().getExtras();
Run Code Online (Sandbox Code Playgroud)
检索包含与通知消息一起发送的任何数据的Set.
有关通知消息的更多信息,请参阅文档.
Zoh*_*Ali 106
notification
从服务器请求中完全删除字段.仅data
发送并处理它,onMessageReceived()
否则onMessageReceived()
当应用程序处于后台或被杀时,您将不会被触发.
不要忘记"priority": "high"
在通知请求中包含字段.根据文档:数据消息以正常优先级发送,因此它们不会立即到达; 这也可能是问题所在.
这是我从服务器发送的内容
{
"data":{
"id": 1,
"missedRequests": 5
"addAnyDataHere": 123
},
"to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......",
"priority": "high"
}
Run Code Online (Sandbox Code Playgroud)
所以你可以onMessageReceived(RemoteMessage message)
像这样收到你的数据....让我说我必须得到身份证明
Object obj = message.getData().get("id");
if (obj != null) {
int id = Integer.valueOf(obj.toString());
}
Run Code Online (Sandbox Code Playgroud)
man*_*rol 63
此方法handleIntent()已被折旧,因此可以按如下方式处理通知:
前台状态:通知的单击将转到您正在提供的待处理的Intent活动,同时通过编程方式创建通知,因为它通常使用通知的数据有效负载创建.
后台/已杀死状态 - 此处,系统本身会根据通知有效负载创建通知,单击该通知将转到应用程序的启动器活动,您可以在任何生命周期方法中轻松获取Intent数据.
小智 29
我有同样的问题.使用"数据消息"而不是"通知"更容易.数据消息始终加载类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());
}
Run Code Online (Sandbox Code Playgroud)
Md.*_*rim 28
这里有关于firebase消息的更清晰的概念.我是从他们的支持团队那里找到的.
Firebase有三种消息类型:
通知消息:通知消息适用于背景或前景.当应用程序处于后台时,通知消息将传递到系统托盘.如果应用程序是在前台,消息被处理onMessageReceived()
或didReceiveRemoteNotification
回调.这些基本上就是所谓的显示消息.
数据消息:在Android平台上,数据消息可以在后台和前台工作.数据消息将由onMessageReceived()处理.这里的平台特定说明如下:在Android上,可以在用于启动活动的Intent中检索数据有效负载.具体地说就是,如果你有"click_action":"launch_Activity_1"
,你可以通过检索此意图getIntent()
仅从Activity_1
.
具有通知和数据有效负载的消息:在后台,应用程序在通知托盘中接收通知有效负载,并且仅在用户点击通知时处理数据有效负载.在前台时,您的应用会收到一个消息对象,其中包含两个可用的有效负载.其次,click_action参数通常用于通知有效负载而不是数据有效负载.如果在数据有效内容中使用,则此参数将被视为自定义键值对,因此您需要实现自定义逻辑才能使其按预期工作.
另外,我建议您使用onMessageReceived方法(请参阅数据消息)来提取数据包.根据您的逻辑,我检查了bundle对象,但没有找到预期的数据内容.以下是对可能提供更清晰的类似案例的引用.
有关更多信息,请访问我的主题
小智 21
根据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
Run Code Online (Sandbox Code Playgroud)
车身/有效载荷:
{ "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)"
}
Run Code Online (Sandbox Code Playgroud)
在您的应用中,您可以在要调用的活动中添加以下代码:
<intent-filter>
<action android:name="OPEN_ACTIVITY_1" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
Run Code Online (Sandbox Code Playgroud)
vis*_*156 16
onMessageReceived(RemoteMessage remoteMessage)方法基于以下情况调用。
{
"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"
}
}
Run Code Online (Sandbox Code Playgroud)
onMessageReceived(RemoteMessage remoteMessage)调用,在通知栏中显示 LargeIcon 和 BigPicture。我们可以从通知块和数据块中读取内容
onMessageReceived(RemoteMessage remoteMessage)未调用,系统托盘将接收消息并从通知块读取正文和标题,并在通知栏中显示默认消息和标题。
在这种情况下,从 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"
}
}
Run Code Online (Sandbox Code Playgroud)
调用onMessageReceived()的解决方法
onMessageReceived(RemoteMessage remoteMessage)调用,在通知栏中显示 LargeIcon 和 BigPicture。我们可以从通知块和数据块中读取内容
onMessageReceived(RemoteMessage remoteMessage)调用,系统托盘将不会收到消息,因为通知键不在响应中。在通知栏中显示 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());
}
Run Code Online (Sandbox Code Playgroud)
参考链接:
https://firebase.google.com/docs/cloud-messaging/android/receive
Nag*_*nti 12
我遇到了同样的问题.如果应用程序是前台 - 它会触发我的后台服务,我可以根据通知类型更新我的数据库.但是,应用程序进入后台 - 默认通知服务将注意向用户显示通知.
这是我在后台识别应用程序并触发后台服务的解决方案,
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);
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在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>
Run Code Online (Sandbox Code Playgroud)
在最新的Android 8.0版本中测试了这个解决方案.谢谢
Gen*_*ani 11
如果应用程序在后台模式或无效(杀死),以及您点击的通知,您应该为您在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);
}
}
Run Code Online (Sandbox Code Playgroud)
我可能很晚才得到答案,但官方文档有点令人困惑。
还明确指出有两种类型的通知
毫无疑问,如果服务器发送数据消息,那么肯定会调用 onMessageReceived() 方法,但在通知消息的情况下,仅当应用程序位于前台时,才会调用 onMessageReceived() 方法,而当应用程序位于后台时,我们会调用 onMessageReceived() 方法。正在发送只是空。
例子:
假设服务器正在发送通知消息类型:
A.如果是前景:
B.在后台情况下:-remoteMessage.data["key"] 将返回 null,但如果您在默认活动中找到相同的意图数据,则使用 getIntent().getExtras().getString("key") 将起作用
C.如果终止:-remoteMessage.data["key"] 将返回 null,但如果您在默认活动中找到相同的意图数据,则 getIntent().getExtras().getString("key") 将起作用
现在,我们假设服务器正在发送数据消息类型:
D.如果是前景:
E.如果有背景:
F.如果发生杀戮:
毫无疑问,数据消息将始终调用 onMessageReceived() 方法,但如果通知消息且应用程序处于后台/终止状态,您可以使用B的解决方案。谢谢
我希望它能节省每个人的时间。
小智 8
我认为告诉您将消息类型更改为数据的答案对您来说很清楚。
但有时,如果您无法确定收到的消息类型,则必须对其进行处理。我在这里发布我的方法。您刚刚实现了 FirebaseMessagingService 并在handlIntent()方法中处理您的消息。从那里您可以自定义您自己的通知。您可以实现自己的方法sendYourNotificatoin ()
class FCMPushService : FirebaseMessagingService() {
companion object {
private val TAG = "FCMPush"
}
override fun handleIntent(intent: Intent?) {
Logger.t(TAG).i("handleIntent:${intent.toString()}")
val data = intent?.extras as Bundle
val remoteMessage = RemoteMessage(data)
if (remoteMessage.data.isNotEmpty()) {
val groupId: String = remoteMessage.data[MESSAGE_KEY_GROUP_ID] ?: ""
val title = remoteMessage.notification?.title ?: ""
val body = remoteMessage.notification?.body ?: ""
if (title.isNotEmpty() && body.isNotEmpty())
sendYourNotificatoin(this, title, body, groupId)
}
}
Run Code Online (Sandbox Code Playgroud)
}
覆盖我handleIntent
的FirebaseMessageService
作品方法.
这里是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);
}
}
Run Code Online (Sandbox Code Playgroud)
这就是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);
}
}
Run Code Online (Sandbox Code Playgroud)
默认情况下,当您的应用程序处于后台并且您单击通知时,您应用程序中的启动器活动将启动,如果您有任何数据部分与您的通知,您可以在以下相同的活动中处理它,
if(getIntent().getExtras()! = null){
//do your stuff
}else{
//do that you normally do
}
Run Code Online (Sandbox Code Playgroud)
根据 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);
}
}
Run Code Online (Sandbox Code Playgroud)
尝试这个:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
好运
归档时间: |
|
查看次数: |
163025 次 |
最近记录: |