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

Posted

技术标签:

【中文标题】如何使用 Firebase 数据库和 Firebase 通知为聊天应用构建通知系统【英文标题】:How to structure a notification system for a chat app using Firebase Database and Firebase Notification 【发布时间】:2017-02-26 16:30:06 【问题描述】:

我正在使用 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....",
    

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

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

我什么时候必须注册用户令牌? 应用客户端首次启动或InstanceID过期(onTokenRefresh)时。

这是正确的做法吗?

编辑 2

我在 FCM 实现中发现了一个大漏洞。似乎我根本无法处理传递给不在前台的 ios 应用程序的通知。

在Data notification documentation中找到

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

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

我现在正在尝试OneSignal 解决方案即使在后台也可以接收通知,它是免费的并且与 GCM 接口。我很遗憾没有留在 Google,但如果我无法使用 FCM 更新徽章计数,我必须另辟蹊径。

任何考虑将不胜感激。

【问题讨论】:

【参考方案1】:

方法 1 是您应该使用的方法。 Frank's guide 使用的是第一种方法,所以你需要设置一个服务器

它是不是比客户端处理所有事情(例如使用 http 请求)更好的解决方案?

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

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

看起来你必须在服务器上创建关系映射,通过以Authorization: key=YOUR_API_KEY为标题调用https://iid.googleapis.com/iid/v1/IID_TOKEN/rel/topics/TOPIC_NAME,完整描述为here。关注this guide获取Instance ID token。

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

【讨论】:

嗨@JackD,我没有使用InstanceID Token的经验,只有firebase主题。我建议您创建一个新问题,而不是通过编辑帖子添加更多问题。 :) 好的,谢谢。新问题在这里:***.com/questions/40138512/…【参考方案2】:

现在您可以使用 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);
);


);

//

【讨论】:

以上是关于如何使用 Firebase 数据库和 Firebase 通知为聊天应用构建通知系统的主要内容,如果未能解决你的问题,请参考以下文章

Uncaught FirebaseError: Firebase: No Firebase App '[DEFAULT]' has been created - 在 vue.js 中调用 Fireba

如何在 Firebase 中验证休息呼叫?

如何通过 Swift 连接到本地 Firebase 服务器?

如何检测firebase观察childAdded在达到queryLimit时停止调用?

如何在 Firebase 颤振应用程序中合并两个集合?

如何使用 Firebase 分析跟踪 android 片段