Smack 4.1重新连接问题

17

我正在开发一款聊天应用程序,其中:

  1. 我有一个持续运行的后台服务。
  2. 应用程序正常运行,我能够收发消息而没有任何问题。
  3. 我正在使用默认的Smack 4.1 Re-connection Manager,即在连接丢失时自动重新连接(几乎90%的时间都是如此)。

但有时,当连接丢失时,Smack重新连接管理器会停止工作。

我无法找出这个问题的原因。

当我检查手机时,经过12到14小时的延迟,我可以看到Android服务仍在运行,但XMPP重新连接已停止工作。然后我必须强制停止应用程序,然后重新启动服务,才能再次连接到XMPP服务器。

我的假设是,这可能是因为“手机网络从Wifi切换到数据或从数据切换到Wifi”所致。与此同时,Smack 4.1 Re-connection Manager停止工作。虽然我不确定。

我还有以下问题:

  1. PingManager有什么用?PingManager在这种情况下有帮助吗?
  2. StreamManagement是什么?如何启用它?在这种情况下有帮助吗?

还有其他解决此问题的方法吗?我正在考虑以下解决方案:

  1. 同时使用GCM和XMPP,因此当XMPP无法重新连接时,我可以获得PUSH并根据PUSH再次连接。
  2. 使用Alarm Services。(问题:由于连接丢失而在队列中的消息将依赖于下一个闹钟计划)
  3. 每次用户返回应用程序时都连接XMPP。(问题:由于连接丢失而在队列中的消息将依赖于用户返回应用程序)

我认为你应该像解决方案1中描述的那样使用GCM。它将解决你的连接丢失问题,同时减少服务器负载和用户的移动流量。 - Alexey
1
@shanrais 你问的问题和我一模一样,但是我很失望地发现没有答案 :( 你有得到答案吗? - binaryKarmic
2
我现在正在使用GCM。 - shanraisshan
使用PingManager怎么样?你选择GCM而不是PingManager有什么特别的理由吗? 我也想了解更多关于GCM的细节。是什么触发了GCM PUSH消息?有没有服务器端的逻辑? - binaryKarmic
我已经在服务器端编码,只有在客户端离线时才向客户端发送GCM消息。 - shanraisshan
2个回答

2

2

这是一个比较老的问题,我曾经在使用Smack时也遇到过维护持久连接的难题,需要根据多个资源找出答案。在这篇文章中,我将尝试总结我的发现。

注意 - 不要使用AbstractXMPPConnectionisConnected()方法来确定连接是否处于活动状态。这只是对象内部的状态,没有真正的方法来判断连接是否处于活动状态。
唯一确定的方法是通过服务器或客户端进行ping测试。

持久连接路线 - 不推荐

首先需要理解的是,如果您确实想要与服务器建立持久连接(我已经这样做过,不建议使用-更多信息如下),您必须手动完成一些操作。
在服务器端 - 确保在合理的时间内断开闲置的客户端连接(时间太长,您将丢失消息,因为连接将被终止但服务器仍然认为它是活动的。时间太短,如果用户的互联网连接质量差,则会导致重复的断开连接。我个人使用30秒。我想在30到60秒之间任何时间都可以)这将允许您在客户端检测到与服务器的连接已丢失。
第二件事是实现ConnectionListener Smack接口。它包含对各种连接事件的回调,例如connectionClosedOnError,这样您就可以恢复与服务器的连接。
然后,您应该监听网络连接事件-如果用户更改了网络,您应该断开连接并重新连接。
这是值得商榷的,但我个人遇到了通过依赖于服务器ping和回调来保持连接存活的问题。如果您有需要-您应该从客户端向服务器发送ping请求以确保连接。
Smack正好有一个ServerPingWithAlarmManager类-它每30分钟ping服务器一次。不幸的是,对我而言,这并没有起作用,因为一些OEM(小米我正在看着你)在其自定义Android皮肤中限制了后台任务。对我有用的方法是使用自定义PingManager ping服务器。使用PingManager.getInstanceFor(connection)获取它,并使用AlarmManager安排它每X分钟运行一次(7分钟适合我)。
对于这个ping管理器,您应该注册一个PingFailedListener,在其pingFailed()方法中重新连接。
这一切听起来很糟糕吗?最糟糕的部分是整个过程在API> = 23上失败了。这一切都很好,直到Doze和App Standby出现。因此,如果您选择持久连接路线-您必须请求可怕的ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限,允许您的应用程序绕过Doze和App Standby。
恭喜!假设谷歌没有因为您轻率地请求白名单电池优化权限而禁止您的应用程序进入Play商店-您现在可以在一个即使用户长时间不与之互动也会极大耗费电量的应用程序中通过可靠的持久xmpp连接与服务器建立连接。
正如我之前所说的,这不是理想的解决方案。
更好的解决方案是FCM高优先级消息。
在了解了与服务器持久连接的问题后,此方法是我推荐使用的。
不要试图对抗网络连接和电池优化,每个Android版本都会变得更加严格。
将FCM消息集成到您的服务器中,即使设备处于Doze模式,您的用户也可以实时接收消息。
这是我现在使用的方法,并且具有极低的电量消耗优点。
我不会向服务器发送ping,服务器也不会向我的应用程序发送ping。当设备更改网络或由于错误关闭连接时 - 我只需断开连接。
连接时,通过Message类型的StanzaListener接收消息。
断开连接时,通过FirebaseMessagingService()实现接收消息。
无需保持连接,无需对抗系统,电池消耗也非常小。
希望这个答案能够帮助未来的某些人并为他们节省一些时间,因为我花了很多时间、精力和试错才找到一个令我满意的解决方案。

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