消息

会话和消息

SDK 中用户与同一个对象的聊天信息集合,称为一个会话,用 QDSession 来表示。会话有单人会话,群组会话等类型。
原型

typedef NS_ENUM(NSInteger, QDSessionType) {
    QDSessionTypeP2P      = 0,  /** 单聊会话*/
    QDSessionTypeGroup    = 1,  /** 群组会话*/
    QDSessionTypeChatroom = 2,  /** 聊天室 暂时未启用*/
    QDSessionTypeApp      = 3,  /** 应用消息 移动端不支持发送*/
    QDSessionTypeMiLiao   = 4,  /** 密聊消息类型*/
};

@interface QDSession : NSObject<NSCopying>

/**
 *  会话ID,如果当前session为group,则sessionId为groupId,如果是P2P则为对方帐号
 */
@property (nonatomic, copy,   readonly) NSString      *sessionId;

/**
 *  会话类型
 */
@property (nonatomic, assign, readonly) QDSessionType sessionType;

/**
 *  通过id、type和extType构造会话对象
 *
 *  @param sessionId      会话ID
 *  @param sessionType    会话类型
 *  @return 会话对象实例
 */
+ (instancetype)session:(NSString *)sessionId type:(QDSessionType)sessionType;

@end

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

示例

//p2p
QDSession *myFriendSession = [QDSession session:@"friend user id" type:QDSessionTypeP2P];

//team
QDSession *teamSession     = [QDSession session:@"team id" type:QDSessionTypeGroup];

//do something with session

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

原型

@interface QDMessage : NSObject

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

/**
 * 引用消息的消息ID
 */
@property (nonatomic, copy  ) NSString        *sourcemsgId;

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

/**
 *  消息信息标示 2:强通知 4:签收消息
 */
@property (nonatomic, assign) NSInteger       msgFlag;

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

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

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

/**
 *  消息发送者头像信息
 */
@property (nonatomic, copy)  NSString         *senderAvatar;

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

/**
 *  消息文本
 *  @discussion 消息中除 QDMessageTypeText 外,其他消息 text 字段都为 nil  如果text文本长度超过 1000 则会截取到 1000
 */
@property (nonatomic, strong) NSString        *text;

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

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

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

/**
 *  服务端扩展字段
 */
@property (nonatomic, strong) id  remoteExt;

/**
 *  客户端本地扩展
 */
@property (nonatomic, strong) NSDictionary     *localExt;

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

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

/**
 *  消息是否需要被计入未读计数
 ** @discussion 默认为YES。默认情况下,用户收到的所有消息都会被计入未读。设置这个为NO后,对应的消息被对端接受后将不计入未读消息计数内。
 */
@property (nonatomic, assign) BOOL            shouldBeCounted;

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

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

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

/**
 *  消息是否标记为已删除
 *
 *  @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)  QDPlatfromType senderClientType;

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

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

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

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

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

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

@end

上述消息的状态属性,推荐只在主线程对这些属性进行读写

目前提供如下几种消息类型,不同的消息类型对应不同的 MessageObject

消息格式 MessageObject
文本消息 nil
图片消息 QDImageObject
音频消息 QDAudioObject
视频消息 QDVideoObject
文件消息 QDFileObject
地理位置消息 QDLocationObject
通知消息 QDNotificationObject
提醒消息 QDTipObject

消息发送

开发者需要通过 QDClient 里的 QDIMChatManager 协议进行消息发送

原型

@protocol QDIMChatManager <NSObject>

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

@end

属性列表

参数 类型 说明
message QDMessage 需要发送的消息,开发者构造出 message 后,需要选择构造对应的 messageObject (文本消息直接填入 text 即可,无须消息附件注入),即可传入此接口进行发送
session QDSession 需要发送到的会话
error NSError 开发者需要自己构造出一个 NSError 对象,并将对象引用传入。如果在准备发送消息阶段发生错误,这个对象会被填充相应的信息。通常为参数检查错误或者登录状态错误,可参考错误码说明定位具体的出错类型

1 文本消息。

以发送一条文本消息 hello Qida 至好友Id 为 account 的业务场景

// 构造出具体会话
QDSession *session = [QDSession session:@"account" type:QDSessionTypeP2P];
// 构造出具体消息
QDMessage *message = [[QDMessage alloc] init];
message.text       = @"hello Qida";
// 错误反馈
NSError   *error   = nil;
// 发送消息
[[QDClient sharedClient].chatManager sendMessage:message toSession:session error:&error];

2 图片消息。

附件原型:

@interface QDImageObject : NSObject <QDMessageObject>


/**
 *  图片实例对象初始化方法
 *
 *  @param image 要发送的图片
 *  @return 图片选项
 */
- (instancetype)initWithImage:(UIImage *)image;

/**
 *  图片实例对象初始化方法
 *
 *  @param image       要发送的图片
 *  @param imageOption 图片选项
 *  @return 图片实例对象
 */
- (instancetype)initWithImage:(UIImage *)image imageOption:(QDImageOption * _Nullable)imageOption;

/**
 *  图片实例对象初始化方法
 *
 *  @param filepath  要发送的图片路径
 *  @return 图片实例对象
 *  @discussion 使用此方法上传是不做压缩转换的原图上传
 */
- (instancetype)initWithSourcePath:(NSString *)filepath;

/**
 *  展示名
 */
@property (nullable, nonatomic, copy)   NSString *fileName;

/**
 *  图片guid
 */
@property (nullable, nonatomic, copy, readonly) NSString *guid;

/**
 *  图片尺寸
 */
@property (nonatomic, assign, readonly) CGSize   size;

/**
 *  图片本地路径
 *  @discussion 目前 SDK 没有提供下载大图的方法,但推荐使用这个地址作为图片下载地址
 */
@property (nullable, nonatomic, copy, readonly) NSString *path;

/**
 *  本地缩略图路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *thumbPath;

/**
 *  图片远程路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *url;

/**
 *  略缩图远程路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *thumbUrl;

/**
 *  图片选项
 *  @discussion 仅在发送时且通过 initWithImage: 方式初始化才有效
 */
@property (nullable, nonatomic ,strong) QDImageOption *option;

/**
 *  文件大小
 */
@property (nonatomic, assign, readonly) long long fileLength;

/**
 *  图片MD5
 */
@property (nullable,nonatomic, copy, readonly) NSString *md5;

@end

参数列表

参数 类型 说明
path NSString 图片本地路径,目前 SDK 没有提供下载大图的方法,但推荐使用这个地址作为图片下载地址, APP 可以使用自己的下载类或者 SDWebImage 做图片的下载和管理
thumbPath NSString 缩略图本地路径,缩略图在默认情况下由 SDK 自动下载,如果发现本地不存在缩略图,可手动调用 QDIMChatManager 协议中的获取缩略图方法 fetchMessageAttachment:error: 进行下载
url NSString 大图的远程 URL 路径,开发者可通过这个属性自行下载大图
thumbUrl NSString 缩略图远程 URL 路径,仅适用于使用SDK上传服务进行上传的资源,否则无效
size CGSize 图片尺寸
option QDImageOption 图片的压缩选项仅在发送时且通过 initWithImage: 方式初始化才有效
fieLength NSString 文件大小
md5 NSString 图片MD5

QDImageOption 图片选项参数列表

参数 类型 说明
compressQuality float 压缩参数默认为 0.5 ,可传入 0.0 - 1.0 的值,如果值为 0 或者不合法参数时按照 0.5 进行压缩
format QDImageFormat 图片压缩格式,可选 JPEG 和 PNG 两种。默认为 JPEG

以发送一条图片消息, 数据被 image 引用, 至好友 Id 为 user 的业务场景进行示例:

// 构造出具体会话
QDSession *session = [QDSession session:@"user" type:QDSessionTypeP2P];
// 获得图片附件对象
QDImageObject *object = [[QDImageObject alloc] initWithImage:image];
// 构造出具体消息并注入附件
QDMessage *message = [[QDMessage alloc] init];
message.messageObject = object;
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[QDClient sharedClient].chatManager sendMessage:message toSession:session error:&error];

以发送一条图片消息, 数据在路径 path 中, 至好友 Id 为 user 的业务场景进行示例:

// 构造出具体会话
QDSession *session = [QDSession session:@"user" type:QDSessionTypeP2P];
// 获得图片附件对象
QDImageObject *object = [[QDImageObject alloc] initWithSourcePath:path];
// 构造出具体消息并注入附件
QDMessage *message = [[QDMessage alloc] init];
message.messageObject = object;
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[QDClient sharedClient].chatManager sendMessage:message toSession:session error:&error];

3 音频消息

附件原型:

@interface QDAudioObject : NSObject <QDMessageObject>

/**
 *  文件展示名
 */
@property (nullable, nonatomic, copy) NSString *fileName;

/**
 *  声音文件的 guid
 */
@property (nullable, nonatomic, copy, readonly) NSString *guid;

/**
 *  语音的本地路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *path;

/**
 *  语音的远程路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *url;

/**
 *  文件大小
 */
@property (nonatomic, assign, readonly) long long fileLength;

/**
 *  语音时长,毫秒为单位
 */
@property (nonatomic, assign)  long long          duration;

/**
 *  语音对象初始化方法
 *
 *  @param  sourcePath 语音路径
 *  @return 语音实例对象
 */
- (instancetype)initWithSourcePath:(NSString *)sourcePath;

@end

参数列表

参数 类型 说明
fileName NSString 文件展示名
guid NSString 文件在服务端的存储id
path NSString 语音本地路径,语音在默认情况下由 SDK 自动下载,如果发现本地不存在语音文件,可手动调用 QDIMChatManager 协议中的获取语音附件方法 fetchMessageAttachment:error: 进行下载
url NSString 语音的远程 URL 路径
duration long long 语音时长,毫秒为单位
fileLength long long 语音文件大小

提供一种初始化

/**
 *  语音对象初始化方法
 *
 *  @param  sourcePath 语音路径
 *  @return 语音实例对象
 */
- (instancetype)initWithSourcePath:(NSString *)sourcePath;

以发送一条语音消息, 语音保存在路径 path 中, 至好友 Id 为 user 的业务场景进行示例:

// 构造出具体会话
QDSession *session = [QDSession session:@"user" type:QDSessionTypeP2P];
// 获得语音附件对象
QDAudioObject *object = [[QDAudioObject alloc] initWithSourcePath:path];
// 构造出具体消息并注入附件
QDMessage *message = [[QDMessage alloc] init];
message.messageObject = object;
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[QDClient sharedClient].chatManager sendMessage:message toSession:session error:&error];

4 视频消息

附件原型:

@interface QDVideoObject : NSObject <QDMessageObject>

/**
 *  小视频实例对象初始化方法
 *
 *  @param filepath  要发送的视频路径
 *  @return 小视频实例对象
 */
- (instancetype )initWithSourcePath:(NSString *)filepath;

/**
 *  文件展示名
 */
@property (nullable, nonatomic, copy) NSString *fileName;

/**
 *  小视频的guid
 */
@property (nullable, nonatomic, copy, readonly) NSString *guid;

/**
 *  视频MD5
 */
@property (nullable, nonatomic, copy, readonly) NSString *md5;

/**
 *  本地路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *path;

/**
 *  远程路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *url;

/**
 *  视频封面的远程路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *coverUrl;

/**
 *  视频封面的本地路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *coverPath;

/**
 *  封面尺寸
 */
@property (nonatomic, assign, readonly) CGSize    coverSize;

/**
 *  文件大小
 */
@property (nonatomic, assign, readonly) long long fileLength;


@end

参数列表

参数 类型 说明
fileName NSString 文件展示名
guid NSString 文件在服务端的存储id
path NSString 视频的本地路径。目前 SDK 并不提供视频下载功能,但是建议 APP 使用这个 path 作为视频的下载地址,以便后期 SDK 提供缓存清理等功能
url NSString 视频的远程路径
fileLength long long 视频文件大小
md5 NSString 根据视频生成的MD5
coverUrl NSString 视频封面的远程路径
coverPath NSString 视频封面的本地路径。视频封面在默认情况下由 SDK 自动下载,如果发现本地不存在封面文件,可手动调用 QDChatManager 协议中的获取封面方法 fetchMessageAttachment:error: 进行下载
coverSize CGSize 视频封面的大小,由 SDK 自行计算

以路径初始化
原型

@interface QDVideoObject : NSObject <QDMessageObject>

/**
 *  小视频实例对象初始化方法
 *
 *  @param filepath  要发送的视频路径
 *  @return 小视频实例对象
 */
- (instancetype )initWithSourcePath:(NSString *)filepath;

@end

以发送一条视频消息, 视频保存在路径 path 中, 至好友 Id 为 user 的业务场景进行示例:

// 构造出具体会话
QDSession *session = [QDSession session:@"user" type:QDSessionTypeP2P];
// 获得视频附件对象
QDVideoObject *object = [[QDVideoObject alloc] initWithSourcePath:path];
// 构造出具体消息并注入附件
QDMessage *message = [[QDMessage alloc] init];
message.messageObject = object;
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[QDClient sharedClient].chatManager sendMessage:message toSession:session error:&error];

5 文件消息
附件原型:

/**
 *  文件实例对象
 */
@interface QDFileObject : NSObject <QDMessageObject>

/**
 *  文件对象初始化方法(根据文件路径)
 *
 *  @param sourcePath 文件路径
 *  @return 文件实例对象
 */
- (instancetype)initWithSourcePath:(NSString *)sourcePath;

/**
 *  文件对象初始化方法(根据文件数据)
 *
 *  @param data      文件数据
 *  @param extension 文件拓展名
 *  @return 文件实例对象
 */
- (instancetype)initWithData:(NSData *)data extension:(NSString *)extension;

/**
 *  文件显示名
 */
@property (nullable, nonatomic, copy) NSString *fileName;

/**
 *  文件Id
 */
@property (nullable, nonatomic, copy, readonly) NSString *guid;

/**
 *  文件的本地路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *path;

/**
 *  文件的远程路径
 */
@property (nullable, nonatomic, copy, readonly) NSString *url;

/**
 *  文件MD5
 */
@property (nullable, nonatomic, copy, readonly) NSString *md5;

/**
 *  文件大小
 */
@property (nonatomic, assign, readonly) long long fileLength;


@end

参数列表

参数 类型 说明
fileName NSString 文件展示名
guid NSString 文件在服务端的存储id
path NSString 文件的本地路径
url NSString 文件的远程路径
fileLength long long 文件大小
md5 NSString 根据文件生成的MD5

文件消息附件初始化提供两种方式:

以发送一条文件消息, 文件保存在路径 path 中, 至好友 Id 为 user 的业务场景进行示例:

// 构造出具体会话
QDSession *session = [QDSession session:@"user" type:QDSessionTypeP2P];
// 获得文件附件对象
QDFileObject *object = [[QDFileObject alloc] initWithSourcePath:path];
// 构造出具体消息并注入附件
QDMessage *message = [[QDMessage alloc] init];
message.messageObject = object;
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[QDClient sharedClient].chatManager sendMessage:message toSession:session error:&error];

以发送一条文件消息, 文件数据被 data 引用, 至好友 Id 为 user 的业务场景进行示例:

// 构造出具体会话
QDSession *session = [QDSession session:@"user" type:QDSessionTypeP2P];
// 获得文件附件对象
QDFileObject *object = [[QDFileObject alloc] initWithData:data extension:@"data"];
// 构造出具体消息并注入附件
QDMessage *message = [[QDMessage alloc] init];
message.messageObject = object;
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[QDClient sharedClient].chatManager sendMessage:message toSession:session error:&error];

6 位置消息
附件原型:

@interface QDLocationObject : NSObject <QDMessageObject>

/**
 纬度
 */
@property (nonatomic, assign, readonly) double latitude;

/**
 经度
 */
@property (nonatomic, assign, readonly) double longitude;

/**
 标题
 */
@property (nullable, nonatomic, copy, readonly) NSString *title;

/**
 地理位置描述
 */
@property (nullable, nonatomic, copy, readonly) NSString *info;

/**
 位置实例对象初始化方法

 @param latitude  纬度
 @param longitude 经度
 @param title 标题
 @param info  地理位置描述
 @return 位置实例对象
 */
- (instancetype)initWithLatitude:(double)latitude longitude:(double)longitude title:(nullable NSString *)title info:(nullable NSString *)info;


@end

参数列表

参数 类型 说明
latitude double 维度位置,由初始化时传入
longitude double 维度位置,由初始化时传入
title NSString 位置标题信息,由初始化时传入
info long long 位置详情信息,由初始化时传入

以发送一条位置消息, 经纬度为 (48.28476,120.94720) ,地点名为 address , 至好友 Id 为 user 的业务场景进行示例:

// 构造出具体会话
QDSession *session = [QDSession session:@"user" type:QDSessionTypeP2P];
// 获得位置附件对象
QDLocationObject *object = [[QDLocationObject alloc] initWithLatitude:120.94720
                                                            longitude:48.28476
                                                                title:@"title"
                                                                 info:@"address"];
// 构造出具体消息并注入附件
QDMessage *message = [[QDMessage alloc] init];
message.messageObject = object;
// 错误反馈对象
NSError *error = nil;
// 发送消息
[[QDClient sharedClient].chatManager sendMessage:message toSession:session error:&error];

7 通知消息

一些特定场景的行为,服务器预置了一些通知消息。通知消息也是一种特定消息,开发者需要解析消息中附带的信息,来获取通知内容。

附件原型:

@interface QDNotificationObject : NSObject <QDMessageObject>

/**
 *  通知内容
 */
@property (nonatomic, strong, readonly) QDNotificationContent *content;

/**
 *  通知类型
 */
@property (nonatomic, assign, readonly) QDNotificationType    notificationType;

@end

参数列表
|参数|类型|说明|
| :—-: | :—-: |:—-: |
|content|QDNotificationContent|通知内容|
|notificationType|QDNotificationType|通知类型,通知类型会随着 SDK 版本升级扩展,开发者需要考虑升级所带来的兼容问题|

接收消息

接收消息过程通过 chatManager 的回调函数通知上层

原型

@protocol QDChatManagerDelegate <NSObject>

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

@end

参数列表

参数 类型 说明
messages NSArray 消息集合,集合按时间排序并保证所属同一个会话

如果收到的是图片,视频等需要下载附件的消息,在回调的处理中还需要调用下载附件接口

原型

@protocol QDIMChatManager <NSObject>

/**
*  收取消息附件
*
*  @param message 需要收取附件的消息
*  @param error   错误
*  @return        是否调用成功
*  @discussion    附件包括:图片消息的图片缩略图,视频消息的视频缩略图,音频消息的音频文件,文件消息的文件以及自定义消息中的自定义文件
*  个人和群组消息 SDK 会在收到该消息时自动调用本接口,自动下载除 "文件消息的文件" 外的所有附件内容
*/
- (BOOL)fetchMessageAttachment:(QDMessage *)message error:(NSError * __nullable *)error;

@end

进行附件的下载,附件的下载过程会通过回调反馈

@protocol QDChatManagerDelegate <NSObject>

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

@end

已读回执

在会话界面中调用发送已读回执的接口并传入最后一条消息,即表示这之前的消息都已读,对端将收到此回执。

发送已读回执

@protocol QDChatManager <NSObject>

/**
*  发送已读消息
*
*  @param message 已读消息
*  @param completion 完成回调
*/
- (void)sendMessageReceipt:(QDMessage *)message completion:(void(^ _Nullable)(NSError * _Nullable error))completion;

@end

接收已读回执

@protocol QDChatManagerDelegate <NSObject>

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

@end

消息撤回

在会话时,允许用户撤回一定时间内发送过的消息。

@protocol QDIMChatManager <NSObject>

/**
*  撤回消息
*
*  @param message    需要被撤回的消息
*  @param completion 完成回调
*/
- (void)revokeMessage:(QDMessage *)message completion:(void(^ _Nullable)(NSError * _Nullable error))completion;

在撤回消息请求调用成功后, SDK 会先回调给上层成功,再自动将本地的这条消息删除。如果需要在撤回后显示一条已撤回的提示 ( 见 Demo 交互 ) ,开发者可以自行构造一条提醒消息并插入本地数据库。

当有消息撤回发生时,被撤回方 SDK 会触发回调:

@protocol QDChatManagerDelegate <NSObject>

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

@end

SDK 在收到消息撤回后,会先从本地数据库中找到对应消息并进行删除,之后通知上层消息已删除。如果需要在撤回后显示一条已撤回的提示 ( 见 Demo 交互 ) ,开发者在这个回调中自行构造一条提醒消息并插入本地数据库。