iOSBlog
iOSBlog copied to clipboard
IM 即时通讯技术篇-技术实现细节
#技术实现细节
IM系列文章
IM系列文章分为下面这几篇:
- 《IM 即时通讯技术在多应用场景下的技术实现,以及性能调优(iOS视角)》
- 《技术实现细节》 (本文)
- 《有一种 Block 叫 Callback,有一种 Callback 做 CompletionHandler》
- 《防 DNS 污染方案》
本文是第二篇。
本文将以开源项目 ChatKit-OC 为例进行介绍:
正文
ChatKit-OC 我们专门为社交场景开发的开源组件:ChatKit-OC,star数,1000+。
项目地址:ChatKit-OC
下文会专门介绍下技术实现细节。
先看下现在 IM 领域的轮子有什么问题:
- Demo 太多,是时候该来一款 Lib 了;
- 闭源的太多,是时候来一款开源的了;
- 部分开源的太多,是时候来一款 100% 开源的了(iOS 端)
- 手撕 Frame 的太多,是时候来一 AutoLayout 款了;
- 自定义能力太弱的太多,是时候来一款可高度自定义的了;
ChatKit-OC 正是为解决这些问题做的,它的特点如下:
- 集成方法简单,但可扩展性好。
- iOS 端代码完全开源,你能看到完整的建立 Socket 连接,以及维持心跳的所有步骤。
- 原生语言开发,利于调试,并非采用C++库。
- Masonry 布局
- 友好的 API 设计
- 接地气
- 支持 CocoaPods
- 不需要改源码,不需要设 Delegate
- 不需要在代码里调整聊天气泡位置
效果展示:
最近联系人 | 语音消息,根据语音长度调整宽度 | 图片消息,尺寸自适应 |
---|---|---|
![]() |
![]() |
![]() |
地理位置消息 | 失败消息本地缓存,可重发 | 上传图片,进度条提示 |
---|---|---|
![]() |
![]() |
![]() |
图片消息支持多图联播,支持多种分享 | 文本消息支持图文混排 | 文本消息支持双击全屏展示 |
---|---|---|
![]() |
![]() |
![]() |
紧凑的API设计:门面模式
使用门面模式,使接入方仅仅需要与一个类打交道,也就使得 API 更加紧凑。
极简参数:
像 UIAlertView 一样,你只需要使用 title 去 init 后,然后直接调用 show 就能达到预期的效果。采用了类似的 API 设计,
隐藏细节:
设计 API时尽量隐藏细节,尽量提供默认实现。
就像 SDWebImage 被使用最多的功能就是 TableView 图片的加载,
只需要传入占位图和图片 URL 两个参数,就能完成复杂的异步加载展示。
无侵入的用户系统接入
需求:与用户的用户帐号体系完全隔离,只需要提供一个 ID 就可以通信,接入方可以对该 ID 进行 MD5 加密后再进行传输和存储,保证开发者用户数据的私密性及安全。
基本的流程示意:
正如图中所示,ChatKit 在需要展现用户图像等信息到 UI 上时,会拿着 ID 去回调一个 Block,这个 Block 需要将对应的用户头像等信息 callback 给 ChatKit,进而展现在 UI 上。
其中最关键的部分是,ChatKit 提供的这个 Block,这个 Block 需要用户自己实现。对这个 Block 的具体实现感兴趣的话,可以看下这篇:
《有一种 Block 叫 Callback,有一种 Callback 做 CompletionHandler》
面向 ID 编程
- 底层协议:Client -- ClientID
- 上层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 坐标,或 颜色的问题:
- 直接写坐标可维护性太差
- 定义成宏,无法满足组件化后的自定义需求
- 失去动态更新能力
为了解决以上问题,ChatKit 使用了 UI 配置文件的方式来提高可维护性:
将配置文件以 JSON 文件,或 plist 文件的方式,我采用的是 plist 文件形式,放置在 bundle 中,让 bundle 文件可以自定义,图片等多媒体资源也就同样可以自定义了。如果在App运行中覆盖对应路径,也就能达到动态更新应用主题的目的。
- 易于维护
- 利于动态更新
- 安卓和iOS公用一套 UI 配置
下图是 ChatKit 中部分可自定义项:
做法类似:
- 安卓开发中的 style xml
- 网页开发中的 css
- 微信团队做法类似。淘宝的一些app也采用了。 微信团队就是如此,软件开发团队从来不负责改坐标、颜色等 UI 参数,这些都是 UI 设计 团队去做。也是采用配置文件。淘宝的聚划算团队也使用了类似的策略,只不过是使用了 JSON 文件的形式。
可拓展性
使用 CocoaPods 集成,在 Demo 层面能实现红包这样大粒度的自定义业务模块,
效果图如下所示:
需要几个 API:
12个接口:
自定义项 | 公开API | 备注 |
---|---|---|
自定义消息 | 2 | -registerSubclass 、 +classMediaType |
自定义Cell | 4 | -registerCustomMessageCell 、+classMediaType 、-setup 、 -configureCellWithData: |
自定义插件 | 6 | -registerCustomInputViewPlugin 、+classPluginType 、-pluginIconImage 、-pluginTitle 、-pluginDidClicked 、sendCustomMessageHandler |
效果图:
- | - | -
-------------|-------------|-------------
|
|
|
|
如何做到在Demo层面进行这样的拓展? 最关键的是:插件映射机制:
比如下图中输入框底部的这些可以点击的插件,ChatKit-OC 提供了一个可变字典,能让用户操作,添加元素。在需要展示 时会去该字典中拿View,因此只要提前进行了映射,就可以加载上。
这种映射机制应用在了:
- 自定义cell类型
- 自定义Message类型
- 自定义输入框底部插件
封装程度高
现状,现在社区中很多轮子,大多数自定义消息的做法,是在“自定义字符串”,对话双方传输的是字符串,接收后需要自己去做序列化、反序列化。
ChatKit-OC 则封装程度更高,发送接收消息时,已经将所有的自定义消息,序列化和反序列化好。你只需要操作 Model 就可以。
IM系列文章
IM系列文章分为下面这几篇:
- 《IM 即时通讯技术在多应用场景下的技术实现,以及性能调优(iOS视角)》
- 《技术实现细节》 (本文)
- 《有一种 Block 叫 Callback,有一种 Callback 做 CompletionHandler》
- 《防 DNS 污染方案》
本文是第二篇。
Posted by 微博@iOS程序犭袁
原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0