对于移动APP来说,IM功能正变得越来越重要,它能够创建起人与人之间的连接。社交类产品中,用户与用户之间的沟通可以产生出更好的用户粘性。
在复杂的 Android 生态环境下,多种因素都会造成消息推送不能及时达到客户端。另外,不稳定的移动网络也给数据传输的速率和可靠性增加了障碍。
本文详解了网易云信IM SDK在应对弱网环境、移动端硬件限制以及Android复杂的生态现状时的探索与心得.如何实现不影响用户体验的后台保活,改善的长连接加推送组合方案,以及在弱网环境大数据传输的优化实践。
相关阅读推荐:
网易云信即时通讯推送保障及网络优化详解(一)如何做长连接加推送组合方案
网易云信即时通讯推送保障及网络优化详解(三)如何在弱网环境下优化大数据传输
如何做长连接
对于IM来说,及时的消息推送和较低的电量消耗也并非不可兼得。在传统上,每个IM客户端都会各自维护一条与服务器的长连接,自己的消息和信令都在这条长连接上传递,每个APP也独自去心跳,断线重连等事情。
这种模式比较简单,不同的APP也是完全隔离的,不会互相影响。但他的缺点也非常明显,首先是做了很多重复的事情,造成了流量和电量的无谓消耗;第二是要保证所有的进程都能在后台运行很难。优化的方向也就非常明显了,那就是共享连接,现在绝大部分推送SDK也是这么做的。从这些APP里面选出一个当前正在运行的,或者是被杀概率最低的APP作为总代理,只由这个代理和服务器建立连接,一个手机上的所有其他APP都通过这个代理中转与服务器通信。但是,IM有一个很基本的要求在这种模式下无法得到满足:安全。所有APP的消息都经过代理中转,代理到服务器的连接是加密的,安全的,但到了代理这里,消息都被解开了,因此代理理论上可以看到其他所有APP的来往消息。因此,这种共享长连接的方式并不适用于IM。
虽然共享长连接方式不合适,但仍然提供了一个优化的思路。在此基础上,有另一个可以脱敏共享连接的方式:安全长连接加推送连接模式。
每个APP在使用和真正传递数据时,仍然独立使用自己的安全长连接。而当APP退到后台一段时间之后,则断开长连接,然后每个APP开启一个推送代理,并选择其中一个和网易云信的推送服务器建立连接,之后当APP有新消息时,就通过这个推送连接传递。APP可以自己控制发出的推送消息的安全级别,可以是包含说话人和消息内容,可以只包含说话人,或者只是一条简单的有新消息到达的提醒文案。推送到达后,如果是代理APP自己的消息,直接传递给代理APP即可。如果是其他APP消息,前面说到过,直接唤醒可能会失败,而且会导致无谓的电量消耗,所以这里并不直接将提醒传递给目标APP,而是由带来发出一条通知栏提醒。等用户去点击通知栏提醒后,才会把目标APP唤醒。
现在国内的ROM中,华为和小米的系统本来是带有推送系统,且开放给了第三方APP的。在这两个系统上,使用系统的推送通道明显会更加稳定,也更加节省资源。因此在MIUI上,从长连接到推送通道的切换流程仍然和前面的一样,只是不再使用自己的推送连接,而是将消息转发到MIUI的推送服务器,然后转给MIUI系统的推送代理,然后传递给网易云信的APP。华为的推送系统流程也是一样。不过现在华为和MIUI在推送实现上有一些区别,例如MIUI的通知栏提醒是在自己的推送代理里完成的,而华为却是将提醒通知交给APP自己去完成的,另外,他们的通知栏提醒的管理接口也有很多区别。在APP没有被禁用的情况下,两者都可以收到推送,而如果APP已经被禁用了,MIUI的通知栏提醒方式还可以将推送送达,而其他的推送方式则不能送达了。
以上就是在保障消息推送方面所能够做的所有事情了。如果以后有更多的系统开放自己的推送系统也可以选择逐步接入,以提高推送到达即时性,减少资源消耗。不过相应的,也要承受不断加入各种系统的推送SDK,增大发布包体积的缺点。
移动通信网络的三个特点
第一个是慢,尤其是2G,3G网络,慢的令人发指。
第二个是断,手机跟着人不停的移动,网络也不停的在切换,从wifi到移动网络,从一个基站到另一个基站,从有信号到没信号,都可能导致网络中断。有些制式的网络,接打电话也会导致数据网络断开。另外,移动基站还有NAT超时,到一个连接上长时间空闲后,基站就会默默的将连接断开,没有任何通知。
第三个是贵,这个就不用多说。
三种长连接类型
在网易云信整个通信系统中有3种类型的连接:TCP,UDP,HTTP。虽说这三个并不是同一层的协议,不过毕竟都在应用的更下层,因此这么划分也无妨。3种类型的协议对应了不同的业务应用。TCP主要是用户长连接,也就是普通IM消息和信令的传输,UDP用于传输实时音视频数据流,而HTTP则主要用在音频,图片等文件的上传下载上。对于不同的业务,SDK优化的关注点会有一些不相同。
IM长连接优化怎么做?
第一个是协议的选择。前面说,长连接的使用量是最大,选择一个合适的协议至关重要。如果是刚开始接触IM开发,一般会选择一些开源的协议,比如XMPP,SIP等。这是XMPP协议的一个请求样例,可以看到是一段XML格式的文本数据。
这是基于SIP的SIMPLE协议的一个请求样例,可以看到是一段类似HTTP协议的文本数据。这些协议的优势在于开源,有成熟的解决方案可以使用,扩展性好,甚至还可以和其他系统互联互通,协议的可读性也非常好。但是在普遍比较臃肿,冗余字段很多,在昂贵的移动网络里面用起来会比较浪费。网易云信采用的是私有的二进制协议,这是一个请求的数据样例,这里是把二进制数据转为了16进制显示出来,每个字节这里显示为两个字符。可以看到二进制协议的特点在于完全失去了可读性,但是,却带来极高的表达效率,相对于文本协议,可以节省非常多的数据流量。
另一个例子是登录的优化。由于移动网络经常断开,所以登录常常是心跳之外交互最多的协议了。使用量越大,优化就越有意义。一般而言,登录会经过这么几步。
第一步是LBS。这里的LBS不是经常说的基于地址位置的服务,在不同的厂商可能也有不同的叫法,反正作用都是获取服务器的IP地址。像云信这种需要提供全球服务的系统,在世界各地都要部署服务器,用户登录时,肯定要选择一台最优的服务器接入服务。通过lbs,客户端可以获取离自己最近,连通性最好的服务器连接机IP地址,服务器也可以据此做负载均衡。
拿到服务器连接机IP后,客户端就去连接该服务器。
连接成功,需要有一次握手。这个握手不是TCP的三次握手,而是为了建立安全连接,同服务器协商加密算法和加密密钥。
然后就发送登录请求,这里会带上用户认证信息,本机设备信息等数据。
登录成功之后,就是同步数据,包括离线消息,用户信息,群组信息等。一般而言,这里不会去做全量同步,而是采用基于时间戳的增量同步。
在移动网络上,每一次交互都需要比较长的时间,同时,每一次网络请求电量消耗也是很大的。所以,优化的方向就是尽量减少交互次数,而方法则是合并请求,并行操作以及省略请求。
LBS和连接这两个步骤是可以并行完成的。如果前面已经获取过LBS,这里可以有之前的缓存地址,如果没有,可以先连一个默认地址。
其次是握手和登录也可以并行操作。在握手包中,就可以把加密后的登录包直接带上去了。如果是断线重连,网易还可以简化登录,直接带上上一次登录的会话ID,一来减少服务器鉴权压力,二则可以直接带回在断线期间是否有未读消息等数据,如果没有,则能直接将同步这一步省略掉。如果有,同步也可以只做部分同步,只去拉去离线消息即可。等到APP切换到前台,才去同步其他的信息。
通过这些优化,登录时间可以降为原来的1/2到1/3,登录的流量消耗也可以节省30%左右。