这是一个比较老的问题,我曾经在使用Smack时也遇到过维护持久连接的难题,需要根据多个资源找出答案。在这篇文章中,我将尝试总结我的发现。
注意 - 不要使用AbstractXMPPConnection
的isConnected()
方法来确定连接是否处于活动状态。这只是对象内部的状态,没有真正的方法来判断连接是否处于活动状态。
唯一确定的方法是通过服务器或客户端进行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()
实现接收消息。
无需保持连接,无需对抗系统,电池消耗也非常小。
希望这个答案能够帮助未来的某些人并为他们节省一些时间,因为我花了很多时间、精力和试错才找到一个令我满意的解决方案。