我正在使用Firestore制作一个消息传递应用程序,我想在发送新消息时发送通知。为此,我正在使用FCM。
现在我声明了 2 个有效载荷:通知有效载荷和数据有效载荷。当用户发送消息时,如果应用在后台,收件人会收到 2 条通知,如果应用在前台,则会收到 1 条通知。如果我删除通知有效负载,无论应用是在前台还是后台,收件人都会收到一条通知。
我希望发生的是,当应用程序处于后台或前台时,用户只收到一个通知,如果应用程序在与发件人的聊天活动中,则不会收到任何通知。我的理解是,当我声明通知和数据有效负载时,这应该是默认行为。
在后台应用中处理通知消息
当您的应用在后台运行时,Android 会将通知消息定向到系统托盘。默认情况下,用户点击通知会打开应用启动器。
这包括同时包含通知和数据负载的消息(以及从通知控制台发送的所有消息(。在这些情况下,通知将传递到设备的系统托盘,并且数据有效负载将在启动器活动的意图的附加内容中传递。
有人可以帮忙吗?我已经阅读了这个和这个,但它似乎对我不起作用,所以也许还有其他我不知道的东西,这是我的清单条目
<service
android:name=".MyFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
这是我的云函数,具有通知和数据有效负载
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.notifyNewMessage =
functions.firestore
.document('users/{ID}/contacts/{contactID}/messages/{messageID}')
.onCreate((docSnapshot , context) => {
const message = docSnapshot.data()
const recipientId = message['recipientId']
const senderId = message['sender']
const senderName = message['senderName']
return admin.firestore().doc('users/' + recipientId).get().then(userDoc =>{
const registrationTokens = userDoc.get('registeredToken')
const notificationBody = (message['data_type'] === "TEXT") ?
message['message'] : "You received a new image message."
const payload = {
notification : {
title : senderName + " sent you a message.",
body : notificationBody
},
data : {
TITLE : senderName + " sent you a message.",
BODY : notificationBody,
USER_NAME : senderName,
USER_NUMBER : message['sender'],
CLICK_ACTION : "MessageListActivity",
MESSAGE : message['message'],
}
}
return
admin.messaging().sendToDevice(registrationTokens,payload).then(response
=> {
})
})
})
这是我的消息传递服务,我现在发送非常基本的通知
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final int NOTIFICATION_MAX_CHARACTERS = 30;
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// Check if message contains a data payload.
if (remoteMessage.getData().size() > 0) {
Map<String, String> data = remoteMessage.getData();
if (data.size() > 0) {
sendNotification(data);
}
}
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
}
}
private void sendNotification(Map<String, String> data) {
String author = data.get("USER_NAME");
String title = data.get("TITLE");
String body = data.get("BODY");
String id = data.get("USER_NUMBER");
String message = data.get("MESSAGE");
Intent intent = new Intent(this, MessageListActivity.class);
intent.putExtra(Constants.USER_NAME, author);
intent.putExtra(Constants.USER_NUMBER, id);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Create the pending intent to launch the activity
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
if (message.length() > NOTIFICATION_MAX_CHARACTERS) {
message = message.substring(0, NOTIFICATION_MAX_CHARACTERS) +
"u2026";
}
Uri defaultSoundUri =
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new
NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_email_black_24dp)
.setContentTitle(String.format(getString(R.string.notification_message),
author))
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */,
notificationBuilder.build());
}
}
如果你想避免显示通知,你应该在你的FirebaseMessagingService
上控制它。您的条件似乎是您的应用程序在特定活动中打开。
如果要避免在应用程序不在前台时收到通知,则应从服务中检查活动管理器。您可以使用此方法:
public boolean isForeground(String myPackage) {
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.getRunningTasks(1);
ComponentName componentInfo = runningTaskInfo.get(0).topActivity;
return componentInfo.getPackageName().equals(myPackage);
}
此外,将<uses-permission android:name="android.permission. REAL_GET_TASKS" />
添加到清单中。
如果您想仅在特定活动中避免它。然后,您需要找到一种方法来跟踪该活动的生命周期。使用SharedPreferences
,一个static
变量,您可以在这篇文章中看到多个示例。
鉴于您的使用案例,我认为您需要向您的 FCM 消息服务传达您的聊天活动状态,并决定是否基于此显示通知。 然后,您可以仅发送带有有效负载的数据部分。
您可以尝试在 FCM 服务中设置广播接收器,并从聊天活动生命周期事件中广播意图,以通知服务是否应生成通知。
在邮件服务中:
private boolean chatActive = false;
private String senderID;
@Override
public void onCreate() {
super.onCreate();
LocalBroadcastManager.getInstance(this).registerReceiver(chatReceiver,new IntentFilter("com.mypackage.CHAT_LIFECYCLE_EVENT"));
}
@Override
public void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(chatReceiver);
super.onDestroy();
}
private BroadcastReceiver chatReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
chatActive = intent.getBooleanExtra("active",false);
senderID = intent.getStringExtra("sender");
}
};
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//Check for whether chat is active with sender
if(!(chatActive && remoteMessage.getData().get("USER_NAME").equals(senderID)){
//sendNotification
}
}
然后,在聊天活动中,您可以在生命周期事件期间发送广播。
@Override
protected void onPause() {
super.onPause();
Intent startNotificationIntent = new Intent();
startNotificationIntent.setAction("com.mypackage.CHAT_LIFECYCLE_EVENT");
startNotificationIntent.putExtra("active",false);
LocalBroadcastManager.getInstance(this).sendBroadcast(startNotificationIntent);
}
@Override
protected void onResume() {
super.onResume();
Intent stopNotificationIntent = new Intent();
stopNotificationIntent.setAction("com.mypackage.CHAT_LIFECYCLE_EVENT");
stopNotificationIntent.putExtra("active",true);
stopNotificationIntent.putExtra("sender",someSenderVariable);
LocalBroadcastManager.getInstance(this).sendBroadcast(stopNotificationIntent);
}