使用XMPP服务器和Google Cloud Messaging(或更新的Firebase Cloud Messaging)的Android聊天应用程序,用于推送通知。

23
我正在为Android开发一个聊天应用程序。我已经阅读了几周关于XMPP和Google云消息传递(以及Firebase云消息传递)的资料,但仍然感到非常困惑。
目前,我已经在本地设置了一个XMPP服务器(Ejabberd),并成功使用Smack库将我的Android应用程序连接到它。
据我所知,我需要使用GCM或更新的FCM进行推送通知,因此我已经在Google云平台上创建了一个项目。我的Android应用程序也可以使用Smack库连接到它(而不是直接连接到我的XMPP服务器)。在我的服务器上,我有一个小型的Java应用程序,也使用Smack库连接到GCM。
到目前为止一切都很好。我的大困惑是:如何在使用GCM进行推送通知时使用我的XMPP服务器?每个文档、示例、指南和教程都只告诉我如何连接到GCM,但没有人告诉我如何将我的XMPP服务器与GCM结合使用。我的Java应用程序只是连接到GCM,并从GCM接收和发送消息,而我的XMPP服务器只是坐在那里什么也没做。实际上,我的Android应用程序和服务器Java应用程序专门使用GCM,而不是我的XMPP服务器。
希望有人能帮助我全面理解这个问题,我显然缺少一些关键元素来实现这个功能。

嗨 SF,你能帮我连接 XMPP 服务器到安卓吗? - Nikhil Verma
你能得到你的答案吗? - Vishal Patoliya ツ
你能帮我吗?我在这里遇到了同样的问题:https://dev59.com/U57ha4cB1Zd3GeqPfSse - Vishal Patoliya ツ
http://stackoverflow.com/questions/41734043/chat-app-for-android-using-a-xmpp-server-and-firebase-cloud-messaging-for-push-n - Vishal Patoliya ツ
5个回答

19
您需要将Ejabberd和FCM混合在一起,这就是所有大型聊天应用程序的做法。对于最基本的情况,有三个组件:通过XMPP连接到FCM的应用程序服务器、Ejabberd和您的客户端应用程序。
  1. 当应用程序在前台时,您使用Smack库直接连接到Ejabberd服务器,发送消息、更改用户的存在状态等。此时连接到您的Ejabberd。保持,您在此期间发送上行消息!
  2. 一旦用户导航离开您的应用程序,您关闭连接。现在将用户视为“离开”或“离线”状态。
  3. 从此时开始,您的应用服务器使用Smack库与FCM通信,以向设备发送下行消息
  4. 在客户端设备上:您处理传入的消息并显示通知。在Android N中,用户可以直接从通知中回复。我假设在这种情况下,您将使用FCM向您的应用程序服务器发送上行消息,因为在此期间,没有活动连接到您的Ejabberd服务器。
  5. 一旦用户点击通知,应用程序回到前台,您将重新连接到Ejabberd,并返回步骤1。
这是实现您想要的架构所必须的非常基本的描述。

在第一步中,当您说“在此期间不发送上行消息”时,您是指向 FCM 发送的上行消息,对吗?换句话说,当客户端设备处于前台时,它总是直接将消息发送到 Ejabberd。客户端设备从 FCM 和 Ejabberd 接收消息还是只从 FCM 接收消息? - Santiago Fermín
1
是的,我提到了FCM。客户端设备从Ejabberd接收消息。当应用程序在后台运行时,您可以使用FCM通知设备有新消息。尽管您可以使用FCM发送高达4KB的有效负载,但我建议您仅使用所谓的“推送同步”消息使用FCM,并从Ejabberd获取实际消息。因此,Ejabberd是所有消息的主要数据存储库,您的应用服务器与FCM下行消息专门用于使客户端与Ejabberd同步。这也意味着Ejabberd和您的应用服务器需要进行通信。 - Nimrod Dayan
1
现在我需要知道如何连接Ejabberd和应用服务器。顺便说一下,我已经使用仅FCM进行下行和上行的客户端应用程序运行良好,我需要使用Ejabberd来提高可扩展性,对吧?仅使用FCM的方法有哪些限制? - Santiago Fermín
查看此帖子https://dev59.com/LGQo5IYBdhLWcg3wR9nD,了解将Ejabberd离线消息转发到您的应用程序服务器。 这不仅是为了可扩展性,而且因为Ejabberd被设计为聊天服务器,所以无需重新发明轮子:)我不确定FCM的其他限制是否除了每条消息的4KB。如果这个答案对您有帮助,请接受它,谢谢! :) - Nimrod Dayan

7
这是一个示例Java项目,用于展示Firebase Cloud Messaging (FCM) XMPP连接服务器。这个项目是我开发的一个非常简单的独立服务器,作为更大项目的基础。它是一个应用服务器,我们必须在自己的环境中实现。该服务器使用XMPP协议通过FCM CCS服务器向客户端应用程序发送数据。
Github链接如下:https://github.com/carlosCharz/fcmxmppserver 此外,我还创建了一段Youtube视频,解释了它的功能。
视频链接如下:https://www.youtube.com/watch?v=PA91bVq5sHw 希望你能找到它有用。

@CarlosBecerraRodríguez 我尝试在Google Cloud模块(端点)中实现您的服务器,但是我遇到了错误,并且下行消息未发送。 - Edijae Crusar
@CarlosBecerraRodríguez 的错误是以下地址失败:'fcm-xmpp.googleapis.com:5236',原因是java.net.SocketException:Permission denied:由于策略,拒绝连接到(10,[2607:f8b0:4001:c06::bc]:5236,6)。我甚至已经在Github上创建了一个问题。 - Edijae Crusar
@JiTHiN 很抱歉回复晚了。我没有收到来自stackoverflow的通知。我确实从GitHub项目中收到了通知。你是否在那里放置了你的错误? - Carlos Becerra Rodriguez

5
你需要设置一个连接到FCM(以前是GCM)的Java服务器。然后,您可以从设备发送上行消息到FCM,FCM将该上行消息发送到您的Java服务器,然后在该Java服务器中处理该上行消息以向目标设备发送下行消息。然后,在设备端,您可以处理接收到的下行消息以提供推送通知。
一些有用的链接:

如何发送上行消息:
https://firebase.google.com/docs/cloud-messaging/upstream#sample-send

如何接收和处理下行消息:
https://firebase.google.com/docs/cloud-messaging/downstream#sample-receive

我如何设置示例Java服务器:
https://stackoverflow.com/a/38170310/4433653

非常感谢您的回答,但我仍然感到困惑。我已经有一个连接到 FCM 的 Java 服务器(与该链接中的代码非常相似),但它在没有我的 XMPP 服务器的情况下就可以工作,它只是使用 FCM 进行一切操作。我错过了什么? - Santiago Fermín
FCM有两种支持的协议:HTTP和XMPP。HTTP仅用于从您的服务器通过FCM向设备发送消息。XMPP允许通过FCM进行服务器到设备和设备到服务器的双向消息传递。 - Arthur Thompson
@ArthurThompson 对的,那么...我如何使用我的XMPP服务器与FCM进行推送通知?我找到的每个实现、示例和指南(包括此答案链接中的内容)都只涉及和解释了FCM部分,那么XMPP呢?那个Java服务器可以在完全没有我的XMPP服务器运行的情况下工作。 - Santiago Fermín
@Santiago Fermin,您可以在应用程序服务器和FCM(确切地说是CCS)之间建立XMPP连接,可以使用类似Smack Java XMPP Library的工具进行连接:https://www.igniterealtime.org/projects/smack。您的应用程序服务器将充当XMPP服务器。 - Arthur Thompson
@ArthurThompson 那我的XMPP服务器(Ejabberd)的作用是什么?这让我很困惑,因为在使用FCM时,Ejabberd没有任何作用,任何连接都不会与它建立联系。 - Santiago Fermín
1
您不需要一个XMPP服务器,CCS(FCM的一部分)就是XMPP服务器。您的应用服务器将成为CCS的XMPP客户端,并与其通信。 - Arthur Thompson

1
我正在使用最新版本的Smack(v.4.1.8)在Android上构建聊天应用程序,我们的服务器使用ejabberd。我没有使用任何第三方工具(如GCM或Firebase)将用户之间的消息推送到下游。如果我没记错,你打算使用GCM或Firebase将用户之间的消息推送到下游,如果是的话,请不要这样做。
为什么呢? TCP协议保持监听已注册的应用程序中的调用侦听器,当连接建立并保持连接时。Smack有一个名为“addAsyncStanzaListener()”的侦听器。
addAsyncStanzaListener用于在应用程序中侦听接收的数据包。他们有...
 public void processPacket(Stanza packet) 

您可以调用它,然后在一段时间内监听数据包。
我正在研究如何保持Smack的稳定连接。大多数Android智能手机都有各自的配置和限制。我们无法测试所有设备。以下是我保持连接稳定的技巧:
  1. 使用前台服务而不是后台服务,我提出这种方法是因为大多数Android设备对在后台运行的应用程序有限制。当应用从任务管理器中划掉时,它们会终止应用程序。(例如Asus zenphone有电源管理)
  2. 前台服务将防止应用程序处于空闲状态。
  3. 注册重新连接管理器
  4. 注册Pingfailed
  5. 注册ServerPingWithAlarmManager
就是这样。如果有任何疑问,请在下面留言:)
此致 R Aditya Gumay

0

你的建议适用于永远不会断开的TCP/IP连接,但在移动3G/4G网络中并非如此。因此,在真实的3G/4G网络中,移动客户端/APP可能处于僵尸状态(已断开连接)。

这就是为什么需要使用Firebase/FCM的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接