如何使用Firebase数据库和Firebase通知构建聊天应用的通知系统

时间:2016-10-17 15:46:32

标签: android ios notifications firebase-realtime-database firebase-notifications

我正在Android中使用Firebase数据库开发聊天应用程序。

我已经完成了核心(聊天和用户列表活动),但我还没有做通知系统。

我想要的是,当用户被添加到对话(单个或组)并且另一个用户向对话写入新消息时,第一个用户必须接收通知,如果被点击则打开对话活动。

我的困境是如何构建在后台运行的服务以接收推送通知或者监听我需要查看的firebase数据库节点以了解是否有任何消息。

我想出了两种不同的方法:

方法1)使用firebase通知

通过这种方法,我只需在发件人发送邮件时从发件人客户端向会话中的所有其他客户端发送数据通知,接收者将决定显示通知(如果聊天活动没有打开)并处理点击操作。

通过这种方法,我认为我将节省CPU消耗,然后再节省电池。

我不明白如何注册用户以接收群组通知(主题通知)因为据我所知,我必须为该主题订阅该客户,但是如果该应用程序处于后台或关闭状态,如何知道新组,其内部用户已创建,因此必须订阅该主题? 对于双用户对话场景,这不是问题,因为我可以直接将通知发送给目标用户,而无需他订阅任何主题。

方法2)使用后台服务

监听firebase数据库数据节点

使用这种方法,我只需要创建一个可启动服务,该服务可以侦听数据库的特定节点(使用ValueEventListener),并在数据显示新消息/会话即将到来时显示通知。 要侦听的节点的示例可以是关于未见消息的数据,如下所示:

conversation_user_unseen_messages
    $conversationId1
        $user1: 3
    $conversationId2
        $user2: 1

然后,如果数据显示新消息/对话,则Android应用客户端将决定显示系统通知。

我认为通过这种方法会有更多能耗,因为它必须不断检查数据库上是否有新消息。

最终考虑

我找到了一个非常有用的guide,由神秘的Frank van Puffelen编写,它解释了如何设置我需要的系统,使用额外的服务器端组件(node.js服务器)。 我的最后一个问题是:我是否需要设置服务器?比客户端处理所有内容(使用例如http请求)更好的解决方案?

您认为哪种解决方案最好? 非常感谢。

修改

我还在搞清楚,但这里有一些考虑。

我必须请求并使用InstanceID

  

实例ID为您的每个应用实例提供唯一ID。

所以我必须在用户连接时请求InstanceID,并且InstanceId是可用的。

然后不使用主题

  

主题消息针对吞吐量而非延迟进行了优化。对于   快速,安全地交付给单个设备或小型设备组,   将消息定位到令牌,而不是主题。

topic messagin guide所述,反而建议target message to tokens

为此,我必须在用户数据库参考中收集用户令牌:

users: {
    $userId1: {
        name: "John",
        email: "john@gmail.com",
        token: "Ax8HiP3Edf7....",
    }
}

然后当我的应用客户端发送新消息时,它还必须为参与聊天的所有用户发送通知,这是我已经可以对我当前的数据库结构做的事情。

如何处理和收集请求? 我实现了一个连接到Firebase数据库的node.js服务器应用程序,并监听应用程序发出的通知请求,然后通过http调用将通知请求发送到每个目标应用程序。

我什么时候需要注册用户令牌? 当应用客户端第一次启动或InstanceID到期时(onTokenRefresh)。

这是正确的方法吗?

编辑2

我在FCM实施中发现了一个大漏洞。似乎我无法处理发送到不在前台的iOs应用程序的所有通知。

Data notification documentation

中找到
  

在iOS上,FCM存储消息并仅在应用程序位于前台并建立FCM连接时传递消息。在Android上,客户端应用程序在onMessageReceived()中接收数据消息,并可以相应地处理键值对。

即使应用程序处于后台,我也需要捕获数据通知,我需要特别注意,因为我想在应用程序图标上更新我的徽章计数器,让用户知道他有多少未读消息。

我现在尝试OneSignal解决方案即使在后台也能收到通知,它可以免费并与GCM接口。 I' M伤心不与谷歌留下,但如果我可以'吨使用FCM我必须寻找到另一侧更新徽章计数

任何考虑都将受到赞赏。

2 个答案:

答案 0 :(得分:1)

方法1是您应该使用的方法。 Frank's guide正在使用第一种方法,因此您需要设置服务器

  

是否比客户端处理所有内容(使用例如http请求)更好的解决方案?

是。如果您在客户端(应用程序)中发送通知,您的API密钥将被公开(通过网络嗅探或逆向工程),您肯定希望避免这种情况。

  

如果应用关闭或在后台,如何订阅用户到新的群组主题?

您似乎必须在服务器上创建关系映射,方法是使用https://iid.googleapis.com/iid/v1/IID_TOKEN/rel/topics/TOPIC_NAME作为标题调用Authorization: key=YOUR_API_KEY,完整描述为here。按照this guide获取实例ID令牌。

我希望我的回答能回答你的问题。干杯:)

答案 1 :(得分:0)

现在您可以使用firebase函数简单地实现此目标...

这是我的

'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

exports.sendFollowerNotification = 
functions.database.ref('/whatever/{groupUID}/{userUID}/{todoUID}')
.onWrite(async (change, context) => {

  const useruuid = context.params.userUID;
  const thisdata = change.after.val();
  console.log('sendto:'+useruuid);

  var ref = admin.database().ref(`userdatas/${useruuid}/phonetkn`);

return ref.once("value", function(snapshot){
     const payload = {
          notification: {

            image: "default",
            sound:"default",
            vibrate:"true" ,

              title: 'New Mission !',
              body: thisdata.titre ,
              color: '#22c064',
              icon: "notification_icon"
          }
     };
     admin.messaging().sendToDevice(snapshot.val(), payload)

}, function (errorObject) {
    console.log("The read failed: " + errorObject.code);
});


});

//