ChenYilong / ChenYilong/iOSBlog

IM 即时通讯技术篇-技术实现细节

Open
#7 0 comments 0 reactions 0 assignees View on GitHub
reference
Dominant language
Objective-C
Stars
1.1k
Forks
184
PR merge metrics
No merged PRs in 30d

Description

#技术实现细节

## IM系列文章

IM系列文章分为下面这几篇:

- [《IM 即时通讯技术在多应用场景下的技术实现,以及性能调优(iOS视角)》](https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/IM%20即时通讯技术在多应用场景下的技术实现,以及性能调优(iOS视角).md)
- [《技术实现细节》]( https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/技术实现细节.md ) (本文)
- [《有一种 Block 叫 Callback,有一种 Callback 做 CompletionHandler》]( https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/有一种%20Block%20叫%20Callback,有一种%20Callback%20做%20CompletionHandler.md )
- [《防 DNS 污染方案》]( https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/防%20DNS%20污染方案.md )

本文是第二篇。

本文将以开源项目 ChatKit-OC 为例进行介绍:

## 正文

ChatKit-OC 我们专门为社交场景开发的开源组件:ChatKit-OC,star数,1000+。

项目地址:[ChatKit-OC]( https://github.com/leancloud/ChatKit-OC )

![](http://ww4.sinaimg.cn/large/7853084cgw1f7yuulsdqgj20vf0kgdlk.jpg)

下文会专门介绍下技术实现细节。

先看下现在 IM 领域的轮子有什么问题:

- Demo 太多,是时候该来一款 Lib 了;
- 闭源的太多,是时候来一款开源的了;
- 部分开源的太多,是时候来一款 100% 开源的了(iOS 端)
- 手撕 Frame 的太多,是时候来一 AutoLayout 款了;
- 自定义能力太弱的太多,是时候来一款可高度自定义的了;

[ChatKit-OC]( https://github.com/leancloud/ChatKit-OC ) 正是为解决这些问题做的,它的特点如下:

- 集成方法简单,但可扩展性好。
- iOS 端代码完全开源,你能看到完整的建立 Socket 连接,以及维持心跳的所有步骤。
- 原生语言开发,利于调试,并非采用C++库。
- Masonry 布局
- 友好的 API 设计
- 接地气
- 支持 CocoaPods
- 不需要改源码,不需要设 Delegate
- 不需要在代码里调整聊天气泡位置

效果展示:

![enter image description here](http://ww3.sinaimg.cn/large/64dfd849jw1f77b0oxnfqg20nl0l77wk.gif)

![enter image description here](http://ww1.sinaimg.cn/large/64dfd849jw1f77b510x7dg20nl0l74r6.gif)

![enter image description here](http://ww2.sinaimg.cn/mw690/64dfd849jw1f77b3wfkuyg20br0krqve.gif)

![enter image description here](http://ww1.sinaimg.cn/mw690/64dfd849jw1f77azzgfmmg20bl0kl1ky.gif)

![](http://ww2.sinaimg.cn/large/801b780ajw1f7wnstpv7mg20bk0l27wh.gif)

最近联系人 | 语音消息,根据语音长度调整宽度 | 图片消息,尺寸自适应
-------------|-------------|-------------|-------------
![enter image description here](http://i63.tinypic.com/1zxqjns.jpg)|![enter image description here](http://i68.tinypic.com/2rx9sfq.jpg) | ![enter image description here](http://i64.tinypic.com/aw87wl.jpg)

地理位置消息| 失败消息本地缓存,可重发 |上传图片,进度条提示
-------------|-------------|-------------
![enter image description here](http://i65.tinypic.com/2vmuaf4.jpg) | ![enter image description here](http://i68.tinypic.com/n6b29v.jpg)| ![enter image description here](http://i66.tinypic.com/orrrxh.jpg)

图片消息支持多图联播,支持多种分享 |文本消息支持图文混排| 文本消息支持双击全屏展示
-------------|-------------|------------
![enter image description here](http://i65.tinypic.com/wmjuvs.jpg) | ![enter image description here](http://i63.tinypic.com/2eoa4j6.jpg) | ![enter image description here](http://i63.tinypic.com/1z1z5ur.jpg)

## 紧凑的API设计:门面模式

![](http://ww2.sinaimg.cn/large/801b780ajw1f88fhsglsxj20dn08oq3d.jpg)

使用门面模式,使接入方仅仅需要与一个类打交道,也就使得 API 更加紧凑。

**极简参数:**

像 UIAlertView 一样,你只需要使用 title 去 init 后,然后直接调用 show 就能达到预期的效果。采用了类似的 API 设计,

**隐藏细节:**

设计 API时尽量隐藏细节,尽量提供默认实现。

就像 SDWebImage 被使用最多的功能就是 TableView 图片的加载,

只需要传入占位图和图片 URL 两个参数,就能完成复杂的异步加载展示。

## 无侵入的用户系统接入

需求:与用户的用户帐号体系完全隔离,只需要提供一个 ID 就可以通信,接入方可以对该 ID 进行 MD5 加密后再进行传输和存储,保证开发者用户数据的私密性及安全。

基本的流程示意:

![](http://ww2.sinaimg.cn/large/801b780ajw1f8ah885yn0j20e70bw754.jpg)

正如图中所示,ChatKit 在需要展现用户图像等信息到 UI 上时,会拿着 ID 去回调一个 Block,这个 Block 需要将对应的用户头像等信息 callback 给 ChatKit,进而展现在 UI 上。

其中最关键的部分是,ChatKit 提供的这个 Block,这个 Block 需要用户自己实现。对这个 Block 的具体实现感兴趣的话,可以看下这篇:

[《有一种 Block 叫 Callback,有一种 Callback 做 CompletionHandler》]( https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/有一种%20Block%20叫%20Callback,有一种%20Callback%20做%20CompletionHandler.md )

## 面向 ID 编程

1. 底层协议:Client -- ClientID
2. 上层UI:Conversation -- ConversationID

ClientId:

WebSocket 通信是 Session 对 Session 的通信,我们将概念简化为 Id 对 Id 的通信,这样一来,两个 APP 只需要 ID 就可以聊起来,这个 ID 我们取名叫 ClientId。

在 ChatKit-OC 的 UI 实现中,体现在对话页面的初始化,你只需要传递一个id,对话id,即可。你同样可以使用ConversationID也就是对话ID来初始化。这样简洁的 API 设计,做法类似 UIAlertView 的初始化只需要传一个 title 就可以。

Conversation(对话)这个概念,我们在使用其他的聊天协议时,比如XMPP,会有单聊和群聊之分,我们在 ChatKit-OC 中,将这个概念简化,不区分单聊群聊。这样一来,你在初始化时就会节省一个概念,而且可以达到只需要一个 ID 就能初始化一个对话页面的目的。在 ChatKit-OC 中我们通过对话中的人数来群分单聊群聊,当然你也可以为对话添加额外的字段,来准确地标记。每个 Conversation 对象都有一个 Attribute 属性,可以自定义字段。

### 可维护性

传统方式设置 View 坐标,或 颜色的问题:

1. 直接写坐标可维护性太差
2. 定义成宏,无法满足组件化后的自定义需求
3. 失去动态更新能力

为了解决以上问题,ChatKit 使用了 UI 配置文件的方式来提高可维护性:

将配置文件以 JSON 文件,或 plist 文件的方式,我采用的是 plist 文件形式,放置在 bundle 中,让 bundle 文件可以自定义,图片等多媒体资源也就同样可以自定义了。如果在App运行中覆盖对应路径,也就能达到动态更新应用主题的目的。

- 易于维护
- 利于动态更新
- 安卓和iOS公用一套 UI 配置

下图是 ChatKit 中部分可自定义项:

![](http://ww4.sinaimg.cn/large/801b780ajw1f8ai6ncfsyj20hf0r042v.jpg)
![](http://ww3.sinaimg.cn/large/801b780ajw1f8ai6ndkn0j20hf0r0788.jpg)

做法类似:

- 安卓开发中的 style xml
- 网页开发中的 css
- 微信团队做法类似。淘宝的一些app也采用了。
微信团队就是如此,软件开发团队从来不负责改坐标、颜色等 UI 参数,这些都是 UI 设计 团队去做。也是采用配置文件。淘宝的聚划算团队也使用了类似的策略,只不过是使用了 JSON 文件的形式。

## 可拓展性

使用 CocoaPods 集成,在 Demo 层面能实现红包这样大粒度的自定义业务模块,

效果图如下所示:

![](http://ww2.sinaimg.cn/large/7853084cjw1f810z9i0z0g20qa0mqu11.gif)

需要几个 API:

12个接口:

自定义项 | 公开API | 备注
-------------|-------------|-------------
自定义消息 | 2 | `-registerSubclass`、 `+classMediaType`
自定义Cell | 4 | `-registerCustomMessageCell`、`+classMediaType`、`-setup`、 `-configureCellWithData:`
自定义插件 | 6 | `-registerCustomInputViewPlugin`、`+classPluginType`、`-pluginIconImage`、`-pluginTitle`、`-pluginDidClicked`、`sendCustomMessageHandler`

效果图:

- | - | -
-------------|-------------|-------------
![](http://ww1.sinaimg.cn/large/7853084cjw1f7ynh6lno3j20bi0kg0ug.jpg) | ![](http://ww3.sinaimg.cn/large/7853084cjw1f7ynh6q4p8j20bi0kgdgm.jpg) | ![](http://ww3.sinaimg.cn/large/7853084cjw1f7ynh6nodqj20bi0kgdgl.jpg)
![](http://ww4.sinaimg.cn/large/7853084cjw1f7ynh6hcqlj20bi0kg74x.jpg) | ![](http://ww1.sinaimg.cn/large/7853084cjw1f7ynh6fj58j20bi0kgab8.jpg) | ![](http://ww1.sinaimg.cn/large/7853084cjw1f7ynh6be0lj20bi0kg75n.jpg)

如何做到在Demo层面进行这样的拓展?
最关键的是:插件映射机制:

比如下图中输入框底部的这些可以点击的插件,ChatKit-OC 提供了一个可变字典,能让用户操作,添加元素。在需要展示 时会去该字典中拿View,因此只要提前进行了映射,就可以加载上。

![](http://ww1.sinaimg.cn/large/7853084cjw1f7ynh6lno3j20bi0kg0ug.jpg)

这种映射机制应用在了:

- 自定义cell类型
- 自定义Message类型
- 自定义输入框底部插件

### 封装程度高

现状,现在社区中很多轮子,大多数自定义消息的做法,是在“自定义字符串”,对话双方传输的是字符串,接收后需要自己去做序列化、反序列化。

ChatKit-OC 则封装程度更高,发送接收消息时,已经将所有的自定义消息,序列化和反序列化好。你只需要操作 Model 就可以。

## IM系列文章

IM系列文章分为下面这几篇:

- [《IM 即时通讯技术在多应用场景下的技术实现,以及性能调优(iOS视角)》](https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/IM%20即时通讯技术在多应用场景下的技术实现,以及性能调优(iOS视角).md)
- [《技术实现细节》]( https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/技术实现细节.md ) (本文)
- [《有一种 Block 叫 Callback,有一种 Callback 做 CompletionHandler》]( https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/有一种%20Block%20叫%20Callback,有一种%20Callback%20做%20CompletionHandler.md )
- [《防 DNS 污染方案》]( https://github.com/ChenYilong/iOSBlog/blob/master/Tips/基于Websocket的IM即时通讯技术/防%20DNS%20污染方案.md )

本文是第二篇。

----------

Posted by [微博@iOS程序犭袁](http://weibo.com/luohanchenyilong/)
原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | [Creative Commons BY-NC-ND 3.0](http://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.