49

58即时通讯移动端架构的实践总结

 4 years ago
source link: https://www.tuicool.com/articles/zqiARri
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

58即时通讯(以下简称微聊,亦或简称IM SDK)作为58集团即时通讯的解决方案,承载了58同城、赶集网、安居客、移动经纪人、招才猫等商业产品线的用户在线沟通能力。目前支持iOS、Android、Web、H5等所有平台。为了满足58集团不断增长的业务需求,从设计之初到现在,微聊的架构经历了几个版本的演进,目前已经形成一套多平台接入、层次分明、结构清晰的客户端架构。

1.背景

在58集团的各业务线中,存在大量需要交易双方沟通交流的场景,比如,客户咨询商家产品信息,售前售后简单的答疑和维权等。此时需要较为完善的即时通信(IM)解决方案,但是由于58集团针对不同的商户和使用场景有多个APP,APP自行实现IM功能代价较大,且维护起来人力分散,于是,IM SDK项目便应运而生,APP通过接入SDK,可以快速实现IM基本功能。

2.整体设计

在最初的设计中,我们总结了如下的几个设计目标:

1)IM 主流程稳定可用:消息传输具有高可靠性。

2)UI 组件直接集成进入SDK,并支持可定制化。

3)富媒体发送集成进入SDK,并可按需定制需要的富媒体类型。

4)实现消息传输层SDK,与带有UI的SDK的功能分离,业务调用方既可以使用消息传输SDK,处理消息,然后自行处理UI,也可以使用带有UI组件的SDK,一步实现较为完备的IM功能。

依据以上几个诉求,我们为IM SDK设计了如下架构:

emmqYnB.png!web

名称

描述

C++ Net

负责SDK长链接相关的逻辑。包括登录、登出、互踢、推消息、心跳包等。

C++ Biz

负责SDK各个模块的数据逻辑,如会话列表、消息列表、用户资料、好有关系、群等。还同时支持持久化存储等功能。更重要的是该层是跨平台的,不仅能够支持移动端平台接入,还能满足Windows、Mac等PC端平台接入使用。

Lib层

平台中间层,为上层提供平台形式的交互接口。

UIKit层

Kit层不仅负责UI渲染、事件订阅、用户事件处理等常规内容,同时还负责拉取会话列表、消息列表上下翻页、消息补空洞、离线消息跳转、同步用户信息等即时通讯的业务逻辑。

总体来说,这个架构采用标准的MVC模式,使得在项目初期,产品得以快速上线发布。并且借助底层核心逻辑的跨平台优势,得以在各个开发平台快速部署,实现功能完善,平台覆盖全面的战略目标。

3.设计要点

此章节中主要描述了,IM SDK设计中一些重要流程。

3.1 消息发送流程

IM SDK目前支持但不限于文字,富文本,音视频、图片、附件、位置、交互卡片等多种形态的消息类型。并提供统一的发送接口,其发送流程主要如下图所示:

2qQ7z2z.jpg!web

3.2 收消息流程

收消息在客户端存在二种场景,一种是在线收消息,一种是离线收消息。以下分别阐述具体过程。

3.2.1 客户端在线收消息

quea2qm.jpg!web

收消息的时候,需要将数据派发到单独的dispatch线程上处理解析、I/O等环节。然后回调业务方的消息监听接口,业务方需要针对UI的具体场景,做不同的处理。除了刷新消息列表,IM SDK还会回调业务方会话列表变更的监听接口,同时刷新会话列表。

3.2.2 客户端离线收消息

客户端退到后台60s以上,或者app处于未启动状态时候,客户端以push的方式收消息。push消息的处理流程如下图所示:

Izueayj.png!web

SDK通过同步会话列表的方式,将每个会话的最后一条push消息拉取到本地,当打开某一个聊天页的时候,才会将中间的其他消息补全。

3.3 可定制化的UI

随着公司业务规模的扩大与业务线的快速迭代,新的业务也需要IM即时通讯功能,众所周知,哪怕是IM即时通讯的UI功能,也会占据大量的开发与调试时间, 为了解决这个痛点,我们提供完整的IM即时通讯解决方案,包括Lib层(IM接口层解决方案)、UIKit层(UI层解决方案)、Logic层(可定制化的UI抽象层解决方案)等。

我们改造了原有UIKit层方案,将其拆分为Logic+UIKit的架构方式的初衷是:

1)IM即时通讯的UI逻辑有其共通性,具备以SDK的方式提供IM一揽子解决方案的前提条件。

2)我们希望把IM SDK的持续迭代收敛在SDK内部,不对业务方造成干扰。实现和业务方自身UI逻辑解藕的目标。

基于以上的诉求,我们设计了如下的整体架构。以回话列表和消息列表为例,具体的架构设计如下图所示:

ZbyMVrr.jpg!web

描述

ChatVirtualView

聊天页的虚拟view,主要角色是处理聊天页列表的交互(包括但不限于上拉,下拉,消息底部判断,消息在屏幕的位置的定位等),该虚拟view会维护一个业务方的tableview实例对象,托管的tableview对象需要业务方在该类初始化的时候进行配置。配置之后tableview的代理实现和滚动回调会在这个虚拟view中进行处理,并根据情况回调给业务方。

ChatViewModel

处理和聊天页UI相关的数据逻辑,比如上UI的数据源、消息收敛策略、拉取历史消息的任务之间的同步、删除消息、撤回消息、已读未读状态等内容

TalkVirtualView

会话列表页的虚拟view,主要角色是处理会话列表页的交互,该虚拟view会维护一个业务方的tableview实例对象,托管的tableview对象需要业务方在该类初始化的时候进行配置。配置之后tableview的代理实现和滚动回调会在这个虚拟view中进行处理,并根据情况回调给业务方。

TalkViewModel

处理和会话列表页UI相关的数据逻辑,比如上UI的数据源、会话的增量更新策略、业务方插入非IM SDK会话、删除指定会话,获取指定会话等内容

我们还是以会话列表和消息列表为例,具体阐述Logic+UIKit这种架构方案的优势:

3.3.1 会话列表的UI定制化

3.3.1.1 会话列表的类结构介绍

会话列表在IM SDK中的入口是WChatConversationListController类。其具体的类结构如下所示:

fMZBvm7.jpg!web

类图解释:

(1) WChatConversationListController中拥有一个WChatLogic层WIMTalkVirtualView类的实例对象vv,并实现接口类WIMTalkVirtualViewDelegate,如图中左部分所示。

(2) vv以WChatConversationListController中的conversationListTableView为入参,并赋值给其属性conversationListTableView,并将TableView的delegate和dataSource设置为vv,相关处理逻辑封装在vv中。其中所需数据源为:

[WIMLogicTalkViewModelsharedInstance].conversationListDataSource

(3) WChatConversationListController创建vv示例代码如下:

self.vv = [[WIMTalkVirtualView alloc]initWithTableView:self.conversationListTableView];self.vv.delegate = self;

3.3.1.2 WIMTalkVirtualViewDelegate回调实现

由于TableView的回调在vv上,所以接口类WIMTalkVirtualViewDelegate透传了绝大多数TableView的回调方法给WChatConversationListController(如果不满足需求可以通过继承的方式自己扩展)。比如如下几个重要的代理方法:

(1) 绑定会话类型与Cell:

-(UITableViewCell*)tableViewCellForConversationVM:(WIMTalkVirtualView *)vvtableView:(UITableView *)tableview model:(id)model atIndexPath:(NSIndexPath*)indexPath;

(2)TableView Cell 点击回调:

-(void)conversationVM:(WIMTalkVirtualView*)vv didSelectConversation:(id)conversation;

(3)计算会话列表单元行高度:

-(CGFloat)calculateModelHeight:(GmacsConversationModel*)model;

3.3.2 消息列表的UI定制化

3.3.2.1 消息列表的类结构介绍

消息列表页面在IM SDK中的入口是WChatConversationController类。其类结构如下图所示:

2QV73ue.jpg!web

类图解释:

(1) WChatConversationController中拥有一个WChatLogic层WIMChatVirtualView类的实例对象vv,并实现接口类WIMChatVirtualViewTableViewDelegate(透传TableView回调的协议)和WIMChatVirtualViewCommonDelegate(其他回调,如上拉开始/结束,下拉开始/结束,消息跳转,发/收消息前,发/收消息后,列表滚动事件等),如图中左部分所示。

(2) vv以WChatConversationController中的messageTableView为入参,并赋值给vv的属性messageTableView,并将TableView的delegate和dataSource设置为vv,相关处理逻辑封装在vv中。其中所需数据源为:

[[WIMLogicChatViewModelsharedInstance].messageList


(3) 如果SDK的消息模型不满足业务方的UI渲染需求,我们支持业务方定义自己的消息模型,方式是继承WIMChatVirtualView类,并在子类中实现-(Class)getMessageModelClass方法,返回业务方自己的消息模型,SDK将为业务方实例化该类作为消息模型对象来使用。

(4) WChatConversationController创建vv示例代码如下:

self.vv = [[WIMChatVirtualView alloc]initWithTableView:self.messageTableView startMessageLocalId:self.startMessageLocalIdtargetId:targetId targetSource:targetSource conversationType:conversationType];

self.vv.tableViewDelegate = self;self.vv.commonDelegate = self;

3.3.2.2 实现回调接口

(1)实现WIMChatVirtualViewTableViewDelegate协议。以下实现是IM SDK的demo部分接口示范代码,业务方根据自己业务逻辑酌情处理。

- (UITableViewCell*)tableView:(UITableView *)tableView

cellForRowAtIndexPath:(NSIndexPath*)indexPath

messageModel:(id)model {

// do something

}


- (CGFloat)tableView:(UITableView *)tableView

heightForRowAtIndexPath:(NSIndexPath*)indexPath

messageModel:(id)model {

// do something

}


- (void)tableView:(UITableView*)tableView

didSelectRowAtIndexPath:(NSIndexPath*)indexPath

messageModel:(id)model {

// do something

}

(2)实现WIMChatVirtualViewCommonDelegate协议。以下实现是IM SDK的demo部分接口示范代码,业务方根据自己业务逻辑酌情处理。

/**

* 开始加载上一页动画

*/

- (void)startLoadBackwardsAnimation {

// do something

}

/**

* 开始加载下一页动画

*/

- (void)startLoadForwardsAnimation {

// do something

}

/**

* 加载上一页动画结束

*

* @param errorCode 错误码

* @param errorMsg 错误描述

*/

-(void)onLoadBackwardsFinished:(NSInteger)errorCode errorMsg:(NSString*)errorMsg {

// do something

}

/**

* 加载下一页动画结束

*

* @param errorCode 错误码

* @param errorMsg 错误描述

*/

-(void)onLoadForwardsFinished:(NSInteger)errorCode errorMsg:(NSString *)errorMsg{

// do something

}

4.总结

以上就是58集团IM SDK架构设计的实践。我们认为好的架构应该是随着业务的拓展而不断的自我进化,脱离于具体业务的架构设计并不是最优设计。58集团的业务特性是业务线多,每个业务线拥有独立账号体系,且不同账号体系之间需要互通。其次是商家分类多样,导致不同身份场景下的交互方式差异性大,与此同时IM SDK需要深度服务于各大业务线,满足业务线的各类即时通讯需求,所以IM SDK移动端对架构的易用性、扩展性、兼容性有十分苛刻的要求。同时我们还注意到,优秀的架构设计能极大程度的降低迭代成本,随着业务线版本的迭代,IM SDK移动端目前也在这个方向持续的优化和努力。

7RFRr2R.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK