会话和消息
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 ];
```
2. 图片消息
```
// 构造出具体会话
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 ];
```
3. 文件消息
```
// 构造出具体会话
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 ];
```
4. 其它消息 都可以通过 ` 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;
```