我正在开发一个使用Firebase实时数据库的聊天应用程序。我已经能够正确地发送和接收消息。现在,我想实现每当收到新消息时的通知。为此,我已经创建了一个Service
,它使用ChildEventListener
侦听数据库更改并创建通知。问题是我在onChildAdded
方法中创建通知,并且该方法同时为数据库中的现有节点和新节点触发。这将导致每当用户在应用程序中来回导航时,为同一消息创建多次通知。
下面是我如何实现它:
chatMsgsRef.orderByChild(FirebaseDBKeys.LOCATION_LAST_UPDATED).addChildEventListener(new ChildEventListener() {
@Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
ChatMessage message = dataSnapshot.getValue(ChatMessage.class);
if (!message.getSenderId().equals(currentUserId)) {
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(NotificationsService.this)
.setSmallIcon(R.drawable.message)
.setContentTitle("New Message from " + message.getReceipientName())
.setContentText(message.getMessage())
.setOnlyAlertOnce(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
mBuilder.setAutoCancel(true);
mBuilder.setLocalOnly(false);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
@Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
@Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
});
我如何实现通知的方式,它在其他聊天应用程序,如whatsapp等??
5条答案
按热度按时间r8uurelv1#
正确的做法是,当有新聊天发送给客户端时,向客户端推送数据消息。
这个blog post解释了如何实现这个功能。基本上你需要设置一个服务器来监听聊天firebase ref,并在更新时发送推送通知。这样你的客户端可以在应用程序中或应用程序外,仍然可以获得推送。
如果您使用某项服务,则会出现许多潜在问题。
首先,你必须让手机保持清醒。这会耗尽电池。
第二,Android可以随时杀死你的后台服务,所以你的应用程序可能会突然停止工作。
第三,在打盹模式下,Android将阻止网络活动,并阻止您的应用在后台运行。
fsi0uk1n2#
我想到了一个更好的答案:
在这种情况下,你需要的并不一定是知道新消息,而是知道未读消息。
在ChatMessage对象中设置一个“read”标志(或者相反,在某个位置设置一个值,给出最近读取的消息的时间戳或ID)。
现在,每当onChildAdded被触发时,检查是否read == false。如果是,则显示消息未读的通知(如果存在通知,请记住更新通知,这样只会显示一个通知,它将显示最近的一个通知--哦,还记得在子对象更改为read时删除通知)。
如果用户在多台设备上使用你的应用,它会正确检查阅读状态。如果他在手机上阅读了最新的消息,然后转到平板电脑,它不会显示新消息通知。
如果愿意,您甚至可以使用此功能来指示收件人已将您的邮件读给他们听。
你怎么知道它什么时候被阅读呢?也许仅仅是当你把它添加到屏幕上的时候。也许你确保它在视图中(不是滚动出屏幕)并且在几秒钟内是可见的。
up9lanfz3#
是否尝试过添加值事件监听器?
https://www.firebase.com/docs/android/guide/retrieving-data.html#section-start
“只要有新数据添加到Firebase引用中,就会调用此方法,我们不需要编写任何额外的代码来实现这一点。”
EDIT:“它在初始数据时触发一次,每次数据改变时都会再次触发。”我还没有尝试过,但我的想法是在方法第一次触发时设置一个标志。然后每当方法和标志被设置时(换句话说,第二次、第三次、第四次等等),从快照中获取最新的对象。
eoxn13cs4#
@Chad Shultz的答案和您的原始代码的组合,并添加了一些数据库结构。
您将按照最初的计划使用查询
但是,请将数据结构更改为具有以下布局
因此,无论何时发送消息,它都会被推送到“messages”节点。接下来,系统获取所有“参与者”,并将他们推送到该聊天/消息的“message_read_states”节点下,除发送者外,每个人的值都为false。当有人阅读消息时,他们会将其值更改为true。
现在,服务需要确定要通知用户的消息。服务将在message_read_states/chat_X上放置一个监听器,并根据子字段“userID_X”的值对其进行排序(取决于当前用户是谁)。我们将使查询只返回每个聊天的消息ID,对于每个聊天,消息ID下都有一个值“userID_X:false
因此,在本例中,对于“userID_002”,查询将返回“msg_001”,但对于“userID_001”,它将不返回任何内容,因为未找到该键所需的值(他/她是发送者)。
在服务的onStartCommand中,将按如下方式构造查询:
当然,用户很可能会参与多个聊天,您必须遍历与该用户相关的所有聊天,并为每个聊天实现一个Query。
来源:我目前正在开发一个带有聊天系统的Firebase应用程序
cnwbcb6i5#
免费且不含服务
您可以在后端完成所有这些工作,而无需云功能和成本。
但是,我强烈建议不要这样做,因为你必须把你的项目的服务器密钥放在代码中,这是一个巨大的安全问题。设置一个云函数来做这件事是非常简单和安全的。
模块:应用程序依赖项
Api客户端
Api接口
根模型
通知模型
数据模型
使用此方法发送通知
您可以在消息选项卡的Firebase项目设置中获取
ConstantKey.SERVER_KEY
。