消息
消息:IM 交互实体,在 SDK 中对应的类型是 EMMessage,EMMessage 可以由多个符合 <IEMMessageBody> 协议的 body 组成,但是,推荐使用一个 body,多个 body 有 bug,正在优化。
以下的讲解以一个 body 为例:
构造消息
构造文字消息
EMChatText *txtChat = [[EMChatText alloc] initWithText:@"要发送的消息"];
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithChatObject:txtChat];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息
构造图片消息
EMChatImage *imgChat = [[EMChatImage alloc] initWithUIImage:img displayName:@"displayName"];
EMImageMessageBody *body = [[EMImageMessageBody alloc] initWithChatObject:imgChat];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息
构造位置消息
EMChatLocation *locChat = [[EMChatLocation alloc] initWithLatitude:35.1 longitude:35.1 address:@"地址"];
EMLocationMessageBody *body = [[EMLocationMessageBody alloc] initWithChatObject:locChat];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息
构造语音消息
EMChatVoice *voice = [[EMChatVoice alloc] initWithFile:recordPath displayName:@"audio"];
voice.duration = aDuration;
EMVoiceMessageBody *body = [[EMVoiceMessageBody alloc] initWithChatObject:voice];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息
构造视频消息
EMChatVideo *videoChat = [[EMChatVideo alloc] initWithFile:localPath displayName:@"displayName"];
EMVideoMessageBody *body = [[EMVideoMessageBody alloc] initWithChatObject:videoChat];
// 生成message。 6001,环信id,消息接收方。
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息
构造文件消息
EMChatFile *fileChat = [[EMChatFile alloc] initWithFile:localPath displayName:@"displayName"];
EMFileMessageBody *body = [[EMFileMessageBody alloc] initWithChatObject:fileChat];
// 生成message。 6001,环信id,消息接收方。
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息
构造透传消息
SDK 提供的一种特殊类型的消息,即 CMD,不会存 db,也不会走 APNS 推送,类似一种指令型的消息,比如您的服务器要通知客户端做某些操作,您可以服务器和客户端提前约定好某个字段,当客户端收到约定好的字段时,执行某种特殊操作。
EMChatCommand *cmdChat = [[EMChatCommand alloc] init];
cmdChat.cmd = @"reason";
EMCommandMessageBody *body = [[EMCommandMessageBody alloc] initWithChatObject:cmdChat];
// 生成message。 6001,环信id,消息接收方。
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息
构造扩展消息
有时候需要在消息中携带一些扩展内容,用来实现特殊需求,比如阅后即焚等。EMMessage 提供了 ext 属性,撰文用来存放扩展内容。ext 属性是 NSDictionary 类型,key 和 value 必须是基本类型,且不能是 JSON。
可以这样使用
EMChatText *txt = [[EMChatText alloc] initWithText:@"test1"];
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithChatObject:txt];
// 6001,环信id,消息接收方。
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.ext = @{@"key":@"value"};
ext 是message的属性,所有消息类型的message都有该属性
插入消息
EMChatText *txt = [[EMChatText alloc] initWithText:@"test1"];
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithChatObject:txt];
// 6001,环信id,消息接收方。
EMMessage *message = [[EMMessage alloc] initWithReceiver:@"6001" bodies:@[body]];
message.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息
message.deliveryState = eMessageDeliveryState_Delivered;
[[EaseMob sharedInstance].chatManager insertMessageToDB:message];
更新消息属性
/*!
@method
@brief 更新消息发送状态
@result 是否更新成功
*/
- (BOOL)updateMessageDeliveryStateToDB;
/*!
@method
@brief 更新消息扩展属性
@result 是否更新成功
*/
- (BOOL)updateMessageExtToDB;
/*!
@method
@brief 更新消息的消息体
@result 是否更新成功
*/
- (BOOL)updateMessageBodiesToDB;
/*!
@method
@brief 修改当前 message 的发送状态,下载状态为 failed(crash 时或者 terminate)
@return 是否更新成功
*/
- (BOOL)updateMessageStatusFailedToDB;
会话
会话:操作聊天消息 EMMessage 的容器,在 SDK 中对应的类型是 EMConversation。
新建/获取一个会话
根据 chatter 创建一个 conversation。
EMConversation *conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:@"8001" conversationType:eConversationTypeChat];
- conversationForChatter: 获取或创建与8001的会话
- conversationType: 会话类型
删除会话
删除单个会话
[[EaseMob sharedInstance].chatManager removeConversationByChatter:@"8001" deleteMessages:YES append2Chat:YES];
- removeConversationByChatter: 删除与8001的会话
- deleteMessages: 删除会话中的消息
- append2Chat: 是否更新内存中内容
批量删除会话
根据 chatter 批量删除会话。
[[EaseMob sharedInstance].chatManager removeConversationsByChatters:chatters deleteMessages:YES append2Chat:YES];
- removeConversationsByChatters: 要删除的 chatters
- deleteMessages: 删除会话中的消息
- append2Chat: 是否更新内存中内容
删除所有会话
// deleteMessage,是否删除会话中的message,YES为删除
[[EaseMob sharedInstance].chatManager removeAllConversationsWithDeleteMessages:YES append2Chat:YES];
获取会话列表
SDK 中提供了三种获取会会话列表的方法。
获取或创建
EMConversation *conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:@"8001" conversationType:eConversationTypeChat];
- conversationForChatter: 获取或创建与8001的会话
- isGroup: 会话类型
获取内存中所有会话
NSArray *conversations = [[EaseMob sharedInstance].chatManager conversations];
获取 DB 中的所有会话
NSArray *conversations = [[EaseMob sharedInstance].chatManager loadAllConversationsFromDatabaseWithAppend2Chat:YES];
获取会话未读消息数
[conversation unreadMessagesCount];
聊天
登录成功之后才能进行聊天操作。发消息时,单聊和群聊调用的是统一接口,区别只是要设置下 message.isGroup 属性。坚决不推荐多 body。
发送消息
/*!
@method
@brief 发送一条消息
@discussion 待发送的消息对象和发送后的消息对象是同一个对象,在发送过程中对象属性可能会被更改
@param message 消息对象(包括from、to、body列表等信息)
@param progress 发送多媒体信息时的progress回调对象
@param pError 错误信息
@result 发送完成后的消息对象
*/
- (EMMessage *)sendMessage:(EMMessage *)message
progress:(id<IEMChatProgressDelegate>)progress
error:(EMError **)pError;
/*!
@method
@brief 异步方法,发送一条消息
@discussion 待发送的消息对象和发送后的消息对象是同一个对象,在发送过程中对象属性可能会被更改。在发送过程中,willSendMessage:error:和didSendMessage:error:这两个回调会被触发
@param message 消息对象(包括from、to、body列表等信息)
@param progress 发送多媒体信息时的progress回调对象
@result 发送的消息对象(因为是异步方法,不能作为发送完成或发送成功失败与否的判断)
*/
- (EMMessage *)asyncSendMessage:(EMMessage *)message
progress:(id<IEMChatProgressDelegate>)progress;
/*!
@method
@brief 异步方法,发送一条消息
@discussion 待发送的消息对象和发送后的消息对象是同一个对象,在发送过程中对象属性可能会被更改
@param message 消息对象(包括from、to、body列表等信息)
@param progress 发送多媒体信息时的progress回调对象
@param prepare 将要发送消息前的回调block
@param aPrepareQueue 回调block时的线程
@param completion 发送消息完成后的回调
@param aCompletionQueue 回调block时的线程
@result 发送的消息对象(因为是异步方法,不能作为发送完成或发送成功失败与否的判断)
*/
- (EMMessage *)asyncSendMessage:(EMMessage *)message
progress:(id<IEMChatProgressDelegate>)progress
prepare:(void (^)(EMMessage *message, EMError *error))prepare
onQueue:(dispatch_queue_t)aPrepareQueue
completion:(void (^)(EMMessage *message, EMError *error))completion
onQueue:(dispatch_queue_t)aCompletionQueue;
接收离线消息
离线普通消息会走以下回调:
/*!
@method
@brief 将要接收离线消息的回调
@discussion
@result
*/
- (void)willReceiveOfflineMessages;
/*!
@method
@brief 接收到离线非透传消息的回调
@discussion
@param offlineMessages 接收到的离线列表
@result
*/
- (void)didReceiveOfflineMessages:(NSArray *)offlineMessages;
/*!
@method
@brief 离线非透传消息接收完成的回调
@discussion
@param offlineMessages 接收到的离线列表
@result
*/
- (void)didFinishedReceiveOfflineMessages;
离线透传消息会走以下回调:
/*!
@method
@brief 接收到离线透传消息的回调
@discussion
@param offlineCmdMessages 接收到的离线透传消息列表
@result
*/
- (void)didReceiveOfflineCmdMessages:(NSArray *)offlineCmdMessages;
/*!
@method
@brief 离线透传消息接收完成的回调
@discussion
@param offlineCmdMessages 接收到的离线透传消息列表
@result
*/
- (void)didFinishedReceiveOfflineCmdMessages;
接收在线消息
在线普通消息会走以下回调:
/*!
@method
@brief 收到消息时的回调
@param message 消息对象
@discussion 当EMConversation对象的enableReceiveMessage属性为YES时,会触发此回调
针对有附件的消息,此时附件还未被下载。
附件下载过程中的进度回调请参考didFetchingMessageAttachments:progress:,
下载完所有附件后,回调didMessageAttachmentsStatusChanged:error:会被触发
*/
- (void)didReceiveMessage:(EMMessage *)message;
透传(cmd)在线消息会走以下回调:
/*!
@method
@brief 收到消息时的回调
@param cmdMessage 消息对象
@discussion 当EMConversation对象的enableReceiveMessage属性为YES时,会触发此回调
*/
- (void)didReceiveCmdMessage:(EMMessage *)cmdMessage;
消息未读数变化
/*!
@method
@brief 未读消息数改变时的回调
@discussion 当EMConversation对象的enableUnreadMessagesCountEvent为YES时,会触发此回调
@result
*/
- (void)didUnreadMessagesCountChanged;
解析普通消息
// 收到消息的回调,带有附件类型的消息可以用 SDK 提供的下载附件方法下载(后面会讲到)
-(void)didReceiveMessage:(EMMessage *)message
{
id<IEMMessageBody> msgBody = message.messageBodies.firstObject;
switch (msgBody.messageBodyType) {
case eMessageBodyType_Text:
{
// 收到的文字消息
NSString *txt = ((EMTextMessageBody *)msgBody).text;
NSLog(@"收到的文字是 txt -- %@",txt);
}
break;
case eMessageBodyType_Image:
{
// 得到一个图片消息body
EMImageMessageBody *body = ((EMImageMessageBody *)msgBody);
NSLog(@"大图remote路径 -- %@" ,body.remotePath);
NSLog(@"大图local路径 -- %@" ,body.localPath); // // 需要使用SDK提供的下载方法后才会存在
NSLog(@"大图的secret -- %@" ,body.secretKey);
NSLog(@"大图的W -- %f ,大图的H -- %f",body.size.width,body.size.height);
NSLog(@"大图的下载状态 -- %lu",body.attachmentDownloadStatus);
// 缩略图sdk会自动下载
NSLog(@"小图remote路径 -- %@" ,body.thumbnailRemotePath);
NSLog(@"小图local路径 -- %@" ,body.thumbnailLocalPath);
NSLog(@"小图的secret -- %@" ,body.thumbnailSecretKey);
NSLog(@"小图的W -- %f ,大图的H -- %f",body.thumbnailSize.width,body.thumbnailSize.height);
NSLog(@"小图的下载状态 -- %lu",body.thumbnailDownloadStatus);
}
break;
case eMessageBodyType_Location:
{
EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody;
NSLog(@"纬度-- %f",body.latitude);
NSLog(@"经度-- %f",body.longitude);
NSLog(@"地址-- %@",body.address);
}
break;
case eMessageBodyType_Voice:
{
// 音频SDK会自动下载
EMVoiceMessageBody *body = (EMVoiceMessageBody *)msgBody;
NSLog(@"音频remote路径 -- %@" ,body.remotePath);
NSLog(@"音频local路径 -- %@" ,body.localPath); // 需要使用SDK提供的下载方法后才会存在(音频会自动调用)
NSLog(@"音频的secret -- %@" ,body.secretKey);
NSLog(@"音频文件大小 -- %lld" ,body.fileLength);
NSLog(@"音频文件的下载状态 -- %lu" ,body.attachmentDownloadStatus);
NSLog(@"音频的时间长度 -- %lu" ,body.duration);
}
break;
case eMessageBodyType_Video:
{
EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody;
NSLog(@"视频remote路径 -- %@" ,body.remotePath);
NSLog(@"视频local路径 -- %@" ,body.localPath); // 需要使用SDK提供的下载方法后才会存在
NSLog(@"视频的secret -- %@" ,body.secretKey);
NSLog(@"视频文件大小 -- %lld" ,body.fileLength);
NSLog(@"视频文件的下载状态 -- %lu" ,body.attachmentDownloadStatus);
NSLog(@"视频的时间长度 -- %lu" ,body.duration);
NSLog(@"视频的W -- %f ,视频的H -- %f", body.size.width, body.size.height);
// 缩略图sdk会自动下载
NSLog(@"缩略图的remote路径 -- %@" ,body.thumbnailRemotePath);
NSLog(@"缩略图的local路径 -- %@" ,body.thumbnailRemotePath);
NSLog(@"缩略图的secret -- %@" ,body.thumbnailSecretKey);
NSLog(@"缩略图的下载状态 -- %lu" ,body.thumbnailDownloadStatus);
}
break;
case eMessageBodyType_File:
{
EMFileMessageBody *body = (EMFileMessageBody *)msgBody;
NSLog(@"文件remote路径 -- %@" ,body.remotePath);
NSLog(@"文件local路径 -- %@" ,body.localPath); // 需要使用SDK提供的下载方法后才会存在
NSLog(@"文件的secret -- %@" ,body.secretKey);
NSLog(@"文件文件大小 -- %lld" ,body.fileLength);
NSLog(@"文件文件的下载状态 -- %lu" ,body.attachmentDownloadStatus);
}
break;
default:
break;
}
}
解析透传消息
-(void)didReceiveCmdMessage:(EMMessage *)cmdMessage{
EMCommandMessageBody *body = (EMCommandMessageBody *)cmdMessage.messageBodies.lastObject;
NSLog(@"收到的action是 -- %@",body.action);
}
解析消息扩展属性
-(void)didReceiveCmdMessage:(EMMessage *)cmdMessage{
// cmd消息中的扩展属性
NSDictionary *ext = cmdMessage.ext;
NSLog(@"cmd消息中的扩展属性是 -- %@",ext);
}
// 收到消息回调
-(void)didReceiveMessage:(EMMessage *)message{
// 消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"消息中的扩展属性是 -- %@",ext);
}
自动下载消息中的附件
SDK 接收到消息后,会默认下载:图片消息的缩略图,语音消息的语音,视频消息的视频第一帧。
请先判断你要下载附件没有下载成功之后,在调用以下下载方法,否则 SDK 下载方法会再次从服务器上获取附件。
SDK中提供了三种方法。
1. 同步方法
EMError *error = nil;
EMMessage *aMessage = [[EaseMob sharedInstance].chatManager fetchMessageThumbnail:message progress:nil error:&error];
if (!error) {
NSLog(@"缩略图下载成功,下载后的message -- %@",aMessage);
}
2. block 异步方法
[[EaseMob sharedInstance].chatManager asyncFetchMessageThumbnail:message progress:nil completion:^(EMMessage *aMessage, EMError *error) {
if (!error) {
NSLog(@"缩略图下载成功");
}
} onQueue:nil];
3. IChatManagerDelegate 异步方法
接口调用:
// 当收到消息时,SDK会自动调用下载缩略图。此处在这里调用只是为了演示用。
[[EaseMob sharedInstance].chatManager asyncFetchMessageThumbnail:message progress:nil];
回调监听:
// 当收到图片或视频时,SDK会自动下载缩略图,并回调该方法,如果下载失败,可以通过
// asyncFetchMessageThumbnail:progress 方法主动获取
-(void)didFetchMessageThumbnail:(EMMessage *)aMessage error:(EMError *)error{
if (!error) {
NSLog(@"下载缩略图成功,下载后的message是 -- %@",aMessage);
}
}
下载消息中的原始附件
SDK 中提供了三种方法。
1. 同步方法
EMError *error = nil;
EMMessage *aMessage = [[EaseMob sharedInstance].chatManager fetchMessage:message progress:nil error:&error];
if (!error) {
NSLog(@"下载成功,下载后的message是 -- %@",aMessage);
}
2. block 回调方法
[[EaseMob sharedInstance].chatManager asyncFetchMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *error) {
if (!error) {
NSLog(@"下载成功,下载后的message是 -- %@",aMessage);
}
} onQueue:nil];
3. IChatManagerDelegate 异步方法
接口调用:
// 当message中带有附件的时候执行下载(如图片、音频、视频、文件)
[[EaseMob sharedInstance].chatManager asyncFetchMessage:message progress:nil];
回调监听:
/*!
@method
@brief 收取消息体对象后的回调
@discussion 当获取完消息体对象后,此回调会被触发;如果此消息体所在的消息对象在服务器端已被加密,那么下载完成后会自动进行解压
@param aMessage 要获取的消息对象
@param error 错误信息
*/
- (void)didFetchMessage:(EMMessage *)aMessage error:(EMError *)error;
消息已送达回执
该回调缺省是关闭的,需要您调用打开方法(只需要在SDK初始化后调用一次即可)。
/*!
@property
@brief 开启消息送达通知(默认是不开启的)
@discussion
*/
[[EaseMob sharedInstance].chatManager enableDeliveryNotification];
SDK提供了已送达回执,当对方收到您的消息后,您会收到以下回调:
/*!
@method
@brief 收到"已送达回执"时的回调方法
@discussion 发送方收到接收方发送的一个收到消息的回执,但不意味着接收方已阅读了该消息
@param resp 收到的"已送达回执"对象,包括 from、to、chatId等
@result
*/
- (void)didReceiveHasDeliveredResponse:(EMReceipt *)resp;
消息已读回执
已读回执需要开发者主动调用的。当用户读取消息后,由开发者主动调用方法。
发送已读回执
// 发送已读回执。在这里写只是为了演示发送,在APP中具体在哪里发送需要开发者自己决定。
[[EaseMob sharedInstance].chatManager sendHasReadResponseForMessage:message];
接收已读回执
/*!
@method
@brief 收到"已读回执"时的回调方法
@discussion 发送方收到接收方发送的一个收到消息的回执,意味着接收方已阅读了该消息
@param resp 收到的"已读回执"对象,包括 from、to、chatId等
@result
*/
- (void)didReceiveHasReadResponse:(EMReceipt *)resp;
上一页:iOS SDK基础功能
下一页:好友管理