Android SDK 体系架构

    本文档将详细介绍融云的 SDK 产品架构和消息体系,以便于您更深入的了解融云并更快速的开发自己的产品。

    image
    融云 SDK 系统架构

    IMKit

    IMKit 的功能主要是封装各种界面对象,服务于开发者快速实现自己的产品,主要特点是是支持快速集成,支持丰富的界面定制功能。

    IMLib

    IMLib 的功能是提供基本通信能力库,封装了通信能力和 Conversation,Message 等各种对象,服务于需要根据自己的产品去自己实现界面的开发者。主要特点是封装清晰,轻量,便于使用。

    Protocol

    Protocol 是融云的核心协议栈,使用融云自定义的私有二进制协议。主要特点是是轻量化,有序可靠,不丢消息。Protocol 部分使用 Native 语言开发,在 Android 和 iOS 平台上保证业务一致性,便于开发者商用化自己的产品。

    IMLib 体系架构

    首先介绍 IMLib 的体系,对于真正使用融云 SDK 的用户,不管您选择 IMLib 还是 IMKit,您都需要了解一下体系概念。

    image
    融云 IMLib 体系架构
    IMLib 的命名规则,在 iOS 上是 RCIMClient,在 Android 上是 RongIMClient。这是为了符合两个平台的命名习惯。

    消息体系架构详解

    会话与消息的关系

    融云 SDK 中已经默认包含了消息数据的本地存储机制,开发者不再需要自己进行消息的存储。也就是说,在融云 SDK 收到消息后,先在本地进行了数据存储,然后再通过消息接收事件通知给开发者。开发者可以通过一系列接口读取和操作本地存储的消息数据。

    会话实体和消息实体

    会话实体类和消息实体类是用来存储本地会话和消息的容器类,除了包含会话内容和消息内容外,还包括了保存在本地的各种状态。

    用来存储消息的实体类主要有 Conversation(会话) 和 Message(消息) 两个实体类,您在客户端读取消息时,获取的对象都和这两个类相关。会话有多种类型,可以是私聊会话,也可以是群组会话等,每一个 Conversation(会话)包含多条 Message(消息),关系如下图所示:

    image

    如何标识一个会话

    通过 conversationType 和 targetId,可以唯一确定一个会话。ConversationType 枚举值意义和对应的 targetId 意义为:

    会话类型枚举 ConversationType 说明 对应的 targetId
    PRIVATE 单聊 用户的 Id(userId)。
    GROUP 群组 群组的 Id(groupId)。
    DISCUSSION 讨论组 讨论组的 Id(discussionId)。
    CHATROOM 聊天室 聊天室的 Id(chatroomId)。
    CUSTOMER_SERVICE 客服 客服的 Id(customerServiceId)。
    SYSTEM 系统会话 系统账户 Id。可以理解为 QQ 的 10000 号的角色。
    APP_PUBLIC_SERVICE 应用公众服务 应用公众服务的 Id(publicServiceId)。
    PUBLIC_SERVICE 公众服务 公众服务的 Id(publicServiceId)。
    请注意区分会话类型和消息类型,会话类型是针对会话的分类,不同的会话类型决定了不同的会话逻辑。

    另:系统会话类型并不一定代表是“系统消息”,本质上与单聊会话类型没有区别,只是逻辑上做了不同的区分,便于展开不同的产品业务逻辑。

    通过一个 conversationType 和 targetId 组合,您可以确定会话列表中一个唯一的对象。以获取某会话的未读消息数举例:获取某会话未读消息数的方法是 RongIM.getInstance().getUnreadCount(ConversationType conversationType, java.lang.String targetId)

    获取一个私聊会话未读消息数的代码片段:

    String userId = "9527";
    
    // 注意:调用 RongIM.getInstance() 方法前,务必保证调用了 init 和 connect。
    int unreadCount = RongIM.getInstance().getRongIMClient().getUnreadCount(ConversationType.PRIVATE, userId);
    

    获取一个群组会话未读消息数的代码片段:

    String groupId = "1234";
    
    // 注意:调用 RongIM.getInstance() 方法前,务必保证调用了 init 和 connect。
    int unreadCount = RongIM.getInstance().getRongIMClient().getUnreadCount(ConversationType.GROUP, groupId);
    

    消息的定义

    消息类(MessageContent 的子类)不同于消息实体类(Message),消息类代表一条具体的消息内容,消息实体类是消息类的外层容器,消息实体对象是消息对象在本地存储的外层对象,消息实体对象除了包含消息对象外,还包括消息的方向、接收状态、接收时间、发送者等。

    消息基类

    MessageContent 是融云的消息基类,所有消息类都继承于 MessageContent 类。需要注意的是,MessageContent 类和 Message 类之间的关系:Message 中包含了一个具体的继承自 MessageContent 的消息,就是 Content 属性,可以通过 setContent() 和 getContent() 进行存取。

    约定:如果您要定义一个内容类消息(需要显示在聊天会话界面中,且不是通知类消息),请从 MessageContent 类继承,命名为 XxxxxMessage。

    内容消息表示一个用户间发送的包含具体内容的消息,需要展现在聊天界面上,如文字消息、语音消息等。

    通知消息基类

    NotificationMessage 没有具体的功能定义,只是用来保证设计上良好的继承关系。

    约定:如果需要定义一个通知类消息,请从 NotificationMessage 类继承,命名为 XxxxxNotificationMessage。

    通知消息表示一个通知信息,可能展现在聊天界面上,如提示条通知。

    状态消息基类

    StatusMessage 没有具体的功能定义,只是用来保证设计上良好的继承关系。

    约定:如果需要定义一个状态类消息,请从 StatusMessage 类继承,命名为 XxxxxStatusMessage。

    状态消息表示一个状态,用来实现如“对方正在输入”的功能。

    消息的分类

    消息分类 消息行为状态标识
    内容类消息 表示一个用户间发送的包含具体内容的消息,需要展现在聊天界面上,如文字消息、语音消息等。
    通知类消息 表示一个通知信息,可能展现在聊天界面上,如提示条通知。
    状态类消息 表示一个状态,用来实现如“对方正在输入”的功能。

    内容类消息

    消息类型 是否上线 ObjectName 类名 父类 是否计数 是否存储
    文字消息 RC:TxtMsg TextMessage MessageContent
    语音消息 RC:VcMsg VoiceMessage MessageContent
    图片消息 RC:ImgMsg ImageMessage MessageContent
    图文消息 RC:ImgTextMsg RichContentMessage MessageContent
    位置消息 RC:LBSMsg LocationMessage MessageContent
    表情贴纸消息 RC:StkMsg StickerMessage MessageContent
    公众服务单图文消息 RC:PSImgTxtMsg PublicServiceRichContentMessage MessageContent
    公众服务多图文消息 RC:PSMultiImgTxtMsg PublicServiceMultiRichContentMessage MessageContent

    通知类消息

    消息类型 是否上线 ObjectName 类名 父类 是否计数 是否存储
    好友通知消息 RC:ContactNtf ContactNotificationMessage NotificationMessage
    资料通知消息 RC:ProfileNtf ProfileNotificationMessage NotificationMessage
    通用命令通知消息 RC:CmdNtf CommandNotificationMessage NotificationMessage
    提示条通知消息 RC:InfoNtf InformationNotificationMessage NotificationMessage
    群组通知消息 RC:GrpNtf GroupNotificationMessage NotificationMessage
    讨论组通知消息 RC:DizNtf DiscussionNotificationMessage NotificationMessage
    已读通知消息 RC:ReadNtf ReadReceiptMessage MessageContent
    公众服务命令消息 RC:PSCmd PublicServiceCommandMessage NotificationMessage
    命令消息 RC:CmdMsg CommandMessage NotificationMessage

    状态类消息

    消息类型 是否上线 ObjectName 类名 父类 是否计数 是否存储
    对方正在输入状态消息 RC:TypSts TypingStatusMessage StatusMessage
    是否计数:表示客户端收到消息后,是否进行未读消息计数(未读消息数增加 1),所有内容型消息都应该设置此值。
    是否存储:表示客户端收到消息后,是否进行存储,并在之后可以通过接口查询。

    内置内容类消息

    文字消息

    用来发送文字类消息,其中可以包括超链接,会自动识别。

    消息类名:TextMessage

    消息 ObjectName:RC:TxtMsg

    消息状态行为标识:MessageTag.ISPERSISTED | MessageTag.ISCOUNTED

    消息的结构:{"content":"Hello world!","extra":""}

    其中 content 为文字消息的文字内容,extra 可以放置任意的数据内容,也可以去掉此属性。

    语音消息

    用来发送语音片段消息,其中可以包括超链接,会自动识别。

    消息类名:VoiceMessage

    消息 ObjectName:RC:VcMsg

    消息状态行为标识:MessageTag.ISPERSISTED | MessageTag.ISCOUNTED

    消息的结构:{"content":"bhZPzJXimRwrtvc=","duration":7,"extra":""}

    其中 content 为语音消息录制转码成 AMR 格式后,进行 Base64 编码的结果值,duration 为语音消息的时长(单位:秒),extra 可以放置任意的数据内容,也可以去掉此属性。

    图片消息

    用来发送图片类消息。

    消息类名:ImageMessage

    消息 ObjectName:RC:ImgMsg

    消息状态行为标识:MessageTag.ISPERSISTED | MessageTag.ISCOUNTED

    消息的结构:{"content":"bhZPzJXimRwrtvc=","imageUri":"http://p1.cdn.com/fds78ruhi.jpg","extra":""}

    图片消息包括两个主要部分:缩略图和大图,缩略图直接 Base64 编码后放入 content 中,大图首先上传到文件服务器(融云 SDK 中默认上传到七牛云存储),然后将云存储上的大图地址放入消息体中。流程示意如下:

    App -> App: 压缩原图到大图尺寸 App -> File Server: 上传大图 File Server --> App: 返回上传大图的地址 App -> App: 压缩大图到缩略图并进行 Base64 转码 App -> RongCloud IM Server: 发送图片消息(内附缩略图内容和大图地址)

    其中 content 为图片内容进行 Base64 编码的结果值,imageUri 为图片上传到图片存储服务器后的地址,extra 可以放置任意的数据内容,也可以去掉此属性。

    缩略图尺寸为:240 x 240 像素,以宽度和高度中较长的边不超过 240 像素等比压缩。

    大图尺寸为:960 x 960 像素,以宽度和高度中较长的边不超过 960 像素等比压缩。

    图文消息

    用来发送图文消息,包含一个标题,一段文字内容和一张图片。

    消息类名:RichContentMessage

    消息 ObjectName:RC:ImgTextMsg

    消息状态行为标识:MessageTag.ISPERSISTED | MessageTag.ISCOUNTED

    消息的结构: {"title":"Big News","content":"I'm Ironman.","imageUri":"http://p1.cdn.com/fds78ruhi.jpg","url":"http://www.rongcloud.cn","extra":""}

    其中 title 为消息的标题,content 为消息的文字内容,imageUri 为图片的地址,url 为跳转的地址,extra 可以放置任意的数据内容,也可以去掉此属性。

    图片尺寸为:120 x 120 像素。

    位置消息

    用来发送地理位置消息。

    消息类名:LocationMessage

    消息 ObjectName:RC:LBSMsg

    消息状态行为标识:MessageTag.ISPERSISTED | MessageTag.ISCOUNTED

    消息的结构:{"content":"bhZPzJXimRwrtvc=","latitude":39.9139,"longitude":116.3917,"poi":"北京市朝阳区北苑路北辰泰岳大厦","extra":""}

    其中 content 为地图缩略图内容进行 Base64 编码的结果值,latitude 为位置的纬度值,longitude 为位置的经度值,poi 为位置兴趣点名称,extra 可以放置任意的数据内容,也可以去掉此属性。

    文件消息

    消息类名:FileMessage

    消息 ObjectName:RC:FileMsg

    消息状态行为标识:MessageTag.ISPERSISTED | MessageTag.ISCOUNTED

    消息的结构:{"name”:”a.txt","size":190184,"type":"txt","fileUrl":"http://rongcloud-image.ronghub.com/text_plain_1471242002?e=2147"}

    其中 name 为文件名,size 为文件大小,type 为文件类型,fileUrl 为文件地址,extra 可以放置任意的数据内容,也可以去掉此属性。

    内置通知类消息

    提示条(小灰条)通知消息

    用来发送在聊天会话页面显示的提示条(小灰条)通知。

    消息类名:InformationNotificationMessage

    消息 ObjectName:RC:InfoNtf

    消息状态行为标识:MessageTag.ISPERSISTED

    消息的结构:{"message":"请在聊天中注意人身财产安全",extra:""}

    其中 message 为提示条消息内容,extra 可以放置任意的数据内容,也可以去掉此属性。

    联系人(好友)通知消息

    用来发送联系人操作(加好友等)的通知消息。

    消息类名:ContactNotificationMessage

    消息 ObjectName:RC:ContactNtf

    消息状态行为标识:MessageTag.ISPERSISTED

    消息的结构:{"operation":"Request","sourceUserId":"123","targetUserId":"456","message":"我是小艾,能加一下好友吗?","extra":""}

    其中 operation 为联系人操作的指令,sourceUserId 为发出通知的用户 Id,targetUserId 为接收通知的用户 Id,message 为通知附带的消息内容,extra 可以放置任意的数据内容,也可以去掉此属性。

    官方针对 operation 属性定义了 "Request", "AcceptResponse", "RejectResponse" 几个常量,也可以由开发者自行扩展。

    资料通知消息

    用来发送用户资料变更通知消息。

    消息类名:ProfileNotificationMessage

    消息 ObjectName:RC:ProfileNtf

    消息状态行为标识:MessageTag.ISPERSISTED

    消息的结构:{"operation":"Update","data":"{\"nickname\":\"韩梅梅\", \"hometown\":\"beijing\"}","extra":""}

    其中 operation 为资料通知操作,可以自行定义,data 为操作的数据,extra 可以放置任意的数据内容,也可以去掉此属性。

    通用命令通知消息

    用来发送通用的指令通知消息,消息内可以定义任意 JSON 内容。

    消息类名:CommandNotificationMessage

    消息 ObjectName:RC:CmdNtf

    消息状态行为标识:MessageTag.ISPERSISTED

    消息的结构:{"name":"AtPerson","data":"{\"sourceId\":\"9527\"}"}

    其中 name 为命令名称,可以自行定义,data 为命令的内容。

    群组通知消息

    用来发送群组操作的通知消息。

    消息类名:GroupNotificationMessage

    消息 ObjectName:RC:GrpNtf

    消息状态行为标识:MessageTag.ISPERSISTED

    消息的结构:{"operatorUserId":"4324","operation":"Rename","data":"本地生活","message":"修改本群名为本地生活","extra":""}

    其中 operatorUserId 为操作人用户 Id,operation 为操作名,data 为操作数据如:目标用户 Id 或修改后群名称,详细可参见内置消息类型说明message 为消息内容,extra 可以放置任意的数据内容,也可以去掉此属性。

    讨论组通知消息

    用来发送讨论组操作的通知消息。

    消息类名:DiscussionNotificationMessage

    消息 ObjectName:RC:DizNtf

    消息状态行为标识:MessageTag.ISPERSISTED

    消息的结构:{"type":1,"extension":"3213,4332","operator":"5435"}

    其中 type 为讨论组操作类型 1:加入讨论组 2:退出讨论组 3:讨论组改名 4:讨论组管理员踢人,extension 为被加入讨论组用户 Id,多个用户 Id 以逗号分割,operator 为当前操作用户 Id。

    已读通知消息

    用来发送消息已经被接收到的状态消息。

    消息类名:ReadReceiptMessage

    消息 ObjectName:RC:ReadNtf

    消息的结构:{"lastMessageSendTime":1408706337,"messageUId":"XXXXXX","type":1}

    其中 lastMessageSendTime 为最后一条消息的发送时间,messageUId 为最后一条消息的 UId,type 为消息类型。

    公众服务命令消息

    公众服务中用来发送通用的指令通知消息,消息内可以定义任意 JSON 内容,与通用命令通知消息的区别是不存储、不计数。

    消息类名:PublicServiceCommandMessage

    消息 ObjectName:RC:PSCmd

    消息的结构:{"cmd":"AtPerson","data":"{\"sourceId\":\"9527\"}"}

    其中 cmd 为命令名称,可以自行定义,data 为命令的内容。

    命令消息

    用来发送通用的指令通知消息,消息内可以定义任意 JSON 内容,与通用命令通知消息的区别是不存储、不计数。

    消息类名:CommandMessage

    消息 ObjectName:RC:CmdMsg

    消息的结构:{"name":"AtPerson","data":"{\"sourceId\":\"9527\"}"}

    其中 name 为命令名称,可以自行定义,data 为命令的内容。

    内置状态类消息

    对方正在输入状态消息

    用来发送对方正在输入时的状态消息,不存储、不计数。

    消息类名:TypingStatusMessage

    消息 ObjectName:RC:TypSts

    消息的结构:{"typingContentType":"RC:TxtMsg"}

    typingContentType 为正在输入消息类型。