会话和消息
SDK 中用户与同一个对象的聊天信息的集合,称为一个会话,用 QDSession 来表示。会话又单人会话,群组会话,应用会话,自定义会话等。

typedef NS_ENUM(NSInteger, QDSessionType) {
    QDSessionTypeP2P      = 0,    /** 单聊会话*/
    QDSessionTypeGroup   = 1,    /** 群组会话*/
    QDSessionTypeMuser   = 2,    /** 群发会话*/
    QDSessionTypeApp      = 3,    /** 应用会话*/
    QDSessionTypeNotify   = 4     /** 系统通知*/
};

@interface QDSession : NSObject
/**
 会话ID,如果当前session为group,则sessionId为groupId,如果是P2P则为对方帐号
 */
@property (nonatomic, copy,   readonly) NSString      *sessionId;
/**
 会话类型
 */
@property (nonatomic, assign, readonly) QDSessionType sessionType;

/**
 会话的扩展类型 (PC 端使用 暂时移动端没有使用)
 */
@property (nonatomic, copy,   readonly, nullable) NSString *sessionExtType;
/**
 通过id、type和extType构造会话对象
 @param sessionId          会话ID
 @param sessionType      会话类型
 @param sessionExtType 会话扩展类型
 @return 会话对象实例
 */
+ (instancetype)session:(NSString *)sessionId type:(QDSessionType)sessionType extType:(NSString * _Nullable )sessionExtType;
@end

在使用的时候,不需要去 SDK 获取会话对象,直接根据已有的会话 Id 和 类型构造出即可。
实例:

// p2p
QDSession *friendSession = [QDSession session:@"friend user id" type:QDSessionTypeP2P extType:nil];
// group
QDSession *groupSession = [QDSession session:group.ID type:QDSessionTypeGroup extType:nil];

SDK 中用于表示消息结构为 QDMessage 。消息属于即时通讯中最关键最重要的类,它是传递信息的基本模型。

/**
 消息基础数据
 */
@interface QDMessage : NSObject

/**
 消息ID,唯一标识
 */
@property (nonatomic, copy)   NSString        *messageId;

/**
 消息类型
 */
@property (nonatomic, assign) QDMessageType   messageType;

/**
 所属会话
 */
@property (nonatomic, strong) QDSession       *session;

/**
 消息发送状态
 */
@property (nonatomic, assign) QDMessageStatus status;

/**
 消息发送者id
 */
@property (nonatomic, copy)   NSString        *senderId;

/**
 消息发送者名字
 */
@property (nonatomic, copy)  NSString         *senderName;

/**
 senderssid
 */
@property (nonatomic, copy)  NSString         *ssid;

/**
 消息标题
 */
@property (nonatomic, copy)  NSString         *title;

/**
 消息内容类型(text/json 等)
 */
@property (nonatomic, copy)  NSString         *contentType;

/**
 消息内容
 */
@property (nonatomic, strong) NSString        *content;

/**
 消息附件内容
 */
@property (nullable, nonatomic, strong)       id<QDMessageObject> messageObject;

/**
 额外消息数据
 */
@property (nullable, nonatomic, copy)          NSString           *extData;

/**
 消息扩展类型
 */
@property (nullable, nonatomic, copy)          NSString           *msgExtType;

/**
 消息信息标示
 */
@property (nonatomic, assign) NSInteger        msgFlag;

/**
 消息发送时间(纳秒级)
 
 @discussion 本地存储消息可以通过修改时间戳来调整其在会话列表中的位置,发完服务器的消息时间戳将被服务器自动修正
 */
@property (nonatomic, assign) NSTimeInterval   timestamp;

/**
 消息投递状态 仅针对发送的消息
 */
@property (nonatomic, assign, readonly)        QDMessageDeliveryState deliveryState;

/**
 是否是往外发的消息
 */
@property (nonatomic, assign) BOOL             isOutgoingMsg;

/**
 是否是收到的消息
 
 @discussion 由于有漫游消息的概念,所以自己发出的消息漫游下来后仍旧是"收到的消息",这个字段用于消息出错是时判断需要重发还是重收
 */
@property (nonatomic, assign, readonly)        BOOL isReceivedMsg;

/**
 消息是否被播放过
*/
@property (nonatomic, assign) BOOL             isPlayed;

/**
 消息是否标记为已删除
 
 @discussion 已删除的消息在获取本地消息列表时会被过滤掉,只有根据 messageId 获取消息的接口可能会返回已删除消息
 */
@property (nonatomic, assign, readonly)        BOOL isDeleted;

/**
 对端是否已读
 @discussion 只有当当前消息为 P2P 消息且 isOutgoingMsg 为 YES 时这个字段才有效,需要对端调用过发送已读回执的接口
 */
@property (nonatomic, assign, readonly)        BOOL isRemoteRead;

/**
 是否本地已读
 @discussion 标记未读消息使用
 */
@property (nonatomic, assign, readonly)        BOOL isLocalRead;

/**
 消息附件下载状态 仅针对收到的消息
 */
@property (nonatomic, assign, readonly)        QDMessageAttachmentDownloadState attachmentDownloadState;

/**
 附件信息
 */
@property (nullable, nonatomic, copy)  NSString   *attachments;

/**
 消息打开时间
 */
@property (nonatomic, assign) NSTimeInterval      openTimestamp;

/**
 消息指令包body内容 (NSString、NSDictionary ...)
 */
@property (nonatomic, copy)   id                  body;

/**
 消息来源类型  应用类消息对应的应用类型
 */
@property (nonatomic, copy)   NSString            *appcode;

/**
 会话Id(服务端使用)
 */
@property (nonatomic, copy)   NSString            *conversationId;

/**
 消息序号
 */
@property (nonatomic, assign) unsigned long long  msgnum;

/**
 发送者的消息序号
 */
@property (nonatomic, assign) unsigned long long  senderMsgnum;

/**
 * 模糊查询的消息数量
 */
@property(nonatomic, assign) NSInteger msgCount;


@end
 

目前提供如下几种消息类型

/**
 消息内容类型枚举
 */
typedef NS_ENUM(NSInteger, QDMessageType) {
    QDMessageTypeText           = 0,   /** 文本消息*/
    QDMessageTypeRTF            = 1,   /** 富文本消息*/
    QDMessageTypeImage          = 2,   /** 图片消息*/
    QDMessageTypeFile           = 3,   /** 文件消息*/
    QDMessageTypeAudio          = 4,   /** 语音消息*/
    QDMessageTypeVideo          = 5,   /** 小视频*/
    QDMessageTypeLocation       = 6,   /** 定位消息*/
    QDMessageTypeLink           = 7,   /** 链接消息*/
    QDMessageTypeConfirm        = 8,   /** 签收消息*/
    QDMessageTypeConfirmed      = 9,   /** 确认签收消息*/
    QDMessageTypeNotify         = 10,  /** 通知消息*/
    QDMessageTypeRevoke         = 11,  /** 撤回消息*/
    QDMessageTypeNetCallAudio   = 12,  /** 音频通话*/
    QDMessageTypeNetCallVideo   = 13,  /** 视频通话*/
    QDMessageTypeCustom         = 14,  /** 自定义消息*/
    QDMessageTypeUnkonw         = 15   /** 未知*/
};

消息发送

@interface QDIM : NSObject
/**
 发送消息

 @param message 消息
 @param session 接受方
 @param error   错误 如果在准备发送消息阶段发生错误,这个error会被填充相应的信息
 @return 是否调用成功,这里返回的 result 只是表示当前这个函数调用是否成功,需要后续的回调才能够判断消息是否已经发送至服务器
 */
- (BOOL)sendMessage:(QDMessage *)message toSession:(QDSession *)session error:(NSError * __nullable *)error;

@end
  1. 文本消息
    已发送一条文本消息 hello word 至好友 id 为 userId 的业务场景进行实例:
// 构造出具体会话
QDSession *session = [QDSession session:@"userId" type:QDSessionTypeP2P extType:nil];
// 构造出具体消息
QDMessage *msg    = [QDMessageMaker msgWithText:@"hello word"];
// 错误反馈对象
NSError  *error = nil;
// 发送消息
[[QDIM sharedSDK] sendMessage:msg toSession:session error:&error ];

  1. 图片消息
// 构造出具体会话
QDSession *session = [QDSession session:@"userId" type:QDSessionTypeP2P extType:nil];
// 构造出具体消息
QDMessage *msg    = [QDMessageMaker msgWithImage:image];
// 错误反馈对象
NSError  *error = nil;
// 发送消息
[[QDIM sharedSDK] sendMessage:msg toSession:session error:&error ];
  1. 文件消息
// 构造出具体会话
QDSession *session = [QDSession session:@"userId" type:QDSessionTypeP2P extType:nil];
// 构造出具体消息
QDMessage *msg    = [QDMessageMaker msgWithFilePath:filePath];
// 错误反馈对象
NSError  *error = nil;
// 发送消息
[[QDIM sharedSDK] sendMessage:msg toSession:session error:&error ];
  1. 其它消息 都可以通过 QDMessageMaker 创建消息
@interface QDMessageMaker : NSObject

+ (QDMessage *)msgWithText:(NSString *)text;

+ (QDMessage *)msgWithFilePath:(NSString *)path;

+ (QDMessage *)msgWithFileData:(NSData *)data extension:(NSString *)extension;

+ (QDMessage *)msgWithImage:(UIImage *)image;

+ (QDMessage *)msgWithImagePath:(NSString *)path;

+ (QDMessage *)msgWithAudioPath:(NSString *)path;

+ (QDMessage *)msgWithVideoPath:(NSString *)path;

+ (QDMessage *)msgWithLatitude:(double)latitude longitude:(double)longitude title:(nullable NSString *)title info:(nullable NSString *)info;

+ (QDMessage *)msgWithForwardMessage:(QDMessage *)forwardMessage;

+ (QDMessage *)msgWithCollectMessage:(QDCollect *)collect;

+ (QDMessage *)msgWithText:(NSString *)text atHandler:(QDAtHandler *)atHandler;

+ (QDMessage *)confirmMsgWithText:(NSString *)text;


@end

发送消息的进度,结果可以通过协议监听

@protocol QDChatManagerDelegate <NSObject>

@optional

/**
 即将发送消息回调
 @discussion 因为发消息之前可能会有个异步的准备过程,所以需要在收到这个回调时才将消息加入到datasource中

 @param message 当前发送的消息
 */
- (void)willSendMessage:(QDMessage *)message;

/**
 发送消息进度回调

 @param message  当前发送的消息
 @param progress 进度
 */
- (void)sendMessage:(QDMessage *)message progress:(float)progress;

/**
 发送消息完成回调

 @param message 当前发送的消息
 @param error   失败原因,如果发送成功则error为nil
 */
- (void)sendMessage:(QDMessage *)message didCompleteWithError:(nullable NSError *)error;

接收消息

@protocol QDChatManagerDelegate <NSObject>

**
 收到消息回调
 
 @param messages 消息列表,内部为QDMessage
 */
- (void)onRecvMessages:(NSArray<QDMessage *> *)messages;

/**
 收到消息回执
 */
- (void)onRecvReceiptsMessage:(QDMessage *)message;

/**
 收取消息附件回调

 @param message  当前收取的消息
 @param progress 进度
 @discussion     附件包括:图片,视频的缩略图,语音文件
 */
- (void)fetchMessageAttachment:(QDMessage *)message
                      progress:(float)progress;

/**
 收取消息附件完成回调

 @param message 当前收取的消息
 @param error   错误返回,如果收取成功,error为nil
 */
- (void)fetchMessageAttachment:(QDMessage *)message
          didCompleteWithError:(nullable NSError *)error;

/**
 收到消息被撤回的通知

 @param notification 被撤回的消息信息
 @discusssion 收到消息撤回后,会先从本地数据库中找到对应消息并进行删除,之后通知上层消息已删除
 */
- (void)onRecvRevokeMessageNotification:(QDRevokeMessageNotification *)notification;


/**
 收取确认签收消息的通知

 @param notification 被签收的消息信息
 */
- (void)onRecvConfirmedMessageNotification:(QDConfirmedMessageNotification *)notification;

最近会话

最近会话有变化时可以通过监听 QDConversationManagerDelegate 协议来实现

/**
 添加会话委托

 @param delegate 通知对象
 */
- (void)addConversationDelegate:(id<QDConversationManagerDelegate>)delegate;

/**
 删除会话委托

 @param delegate 通知对象
 */
- (void)removeConversationDelegate:(id<QDConversationManagerDelegate>)delegate;


/**
 删除某个会话的所有消息
 
 @param session 待删除会话
 */
- (void)deleteAllmessagesInSession:(QDSession *)session;

/**
 设置一个会话里所有消息置为已读
 
 @param session  需设置的会话
 */
- (void)markAllMessagesReadInSession:(QDSession *)session;

/**
 删除某个最近会话
 
 @param recentSession  待删除的最近会话
 */
- (void)deleteRecentSession:(QDRecentSession *)recentSession;

/**
 更新最近会话的本地扩展

 @param ext           扩展信息
 @param session       要更新的会话
 @discussion          此扩展不会漫游到其他端,上层需要保证 NSDictionary 可以转换为 JSON。
 */
- (void)updateRecentLocalExt:(nullable NSDictionary *)ext session:(QDSession *)session;