版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.06.08 |
前言
很多app种都集成环信做第三方信息通讯工具,这里我们就看一下环信的主要功能和集成方法。先给出环信3.0的地址。
感兴趣的可以参考:
1. 环信ios客户端的集成(一)
2. 环信ios客户端的集成(二)
3. 环信ios客户端的集成(三)
4. 环信ios客户端的集成(四)
这一篇主要说一下环信的消息。
一、构造信息
消息分为文字,图片,声音等等很多种形式,消息的构造也分很多种,下面就对消息的构造进行说明。
1. 构造文字消息
看代码
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
2. 构造图片消息
EMImageMessageBody *body = [[EMImageMessageBody alloc] initWithData:data displayName:@"image.png"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
3. 构造位置消息
EMLocationMessageBody *body = [[EMLocationMessageBody alloc] initWithLatitude:39 longitude:116 address:@"地址"];
NSString *from = [[EMClient sharedClient] currentUsername];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
4. 构造语音消息
EMVoiceMessageBody *body = [[EMVoiceMessageBody alloc] initWithLocalPath:@"audioPath" displayName:@"audio"];
body.duration = duration;
NSString *from = [[EMClient sharedClient] currentUsername];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
5. 构造视频消息
EMVideoMessageBody *body = [[EMVideoMessageBody alloc] initWithLocalPath:@"videoPath" displayName:@"video.mp4"];
NSString *from = [[EMClient sharedClient] currentUsername];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
6. 构造文件消息
EMFileMessageBody *body = [[EMFileMessageBody alloc] initWithLocalPath:@"filePath" displayName:@"file"];
NSString *from = [[EMClient sharedClient] currentUsername];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
7. 构造透传消息
SDK 提供的一种特殊类型的消息,即 CMD,不会存 db,也不会走 APNS 推送,类似一种指令型的消息。比如您的服务器要通知客户端做某些操作,您可以服务器和客户端提前约定好某个字段,当客户端收到约定好的字段时,执行某种特殊操作。
EMCmdMessageBody *body = [[EMCmdMessageBody alloc] initWithAction:action];
NSString *from = [[EMClient sharedClient] currentUsername];
// 生成message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
8. 构造扩展消息
当 SDK 提供的消息类型不满足需求时,开发者可以通过扩展自 SDK 提供的文本、语音、图片、位置等消息类型,从而生成自己需要的消息类型。
这里是扩展自文本消息,如果这个自定义的消息需要用到语音或者图片等,可以扩展自语音、图片消息,亦或是位置消息。
// 以单聊消息举例
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
message.ext = @{@"key":@"value"}; // 扩展消息部分
9. 插入消息
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
[[EMClient sharedClient].chatManager importMessages:@[message] completion:^(EMError *aError) {
//code
}];
10. 更新消息属性
/*!
* 更新消息到 DB
*
* @param aMessage 消息
*
* @result 是否成功
*/
- (BOOL)updateMessage:(EMMessage *)aMessage;
//调用:[[EMClient sharedClient].chatManager updateMessage:aMessage];
二、会话
会话:操作聊天消息 EMMessage 的容器,在 SDK 中对应的类型是 EMConversation。
1. 新建/获取一个会话
根据 conversationId 创建一个 conversation。
[[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];
//EMConversationTypeChat 单聊会话
//EMConversationTypeGroupChat 群聊会话
//EMConversationTypeChatRoom 聊天室会话
- getConversation:创建与8001的会话
- type:会话类型
- createIfNotExist:不存在是否创建
2. 删除会话
删除单个会话
[[EMClient sharedClient].chatManager deleteConversation:@"8001" isDeleteMessages:YES completion:^(NSString *aConversationId, EMError *aError){
//code
}];
- deleteConversation: 删除与8001的会话
- deleteMessages: 删除会话中的消息
根据 conversationId 批量删除会话
[[EMClient sharedClient].chatManager deleteConversations:@[@"8001",@"8002"] isDeleteMessages:YES completion:^(EMError *aError){
//code
}];
- deleteConversations: 要删除的会话
- deleteMessages: 删除会话中的消息
3. 获取会话列表
SDK中提供了三种获取会话列表的方法。
获取或创建
EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];
- getConversation: 获取或创建与8001的会话
- type:EMConversationTypeChat: 会话类型
获取所有会话(内存中有则从内存中取,没有则从db中取)
NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
4. 获取会话未读消息数
[EMConversation unreadMessagesCount];
5. 消息检索
可以通过关键字、消息类型、开始结束时间检索某个会话中的消息。
/*!
* 从数据库获取指定数量的消息,取到的消息按时间排序,并且不包含参考的消息,如果参考消息的ID为空,则从最新消息取
*
* @param aMessageId 参考消息的ID
* @param count 获取的条数
* @param aDirection 消息搜索方向
* @param aCompletionBlock 完成的回调
*/
- (void)loadMessagesStartFromId:(NSString *)aMessageId
count:(int)aCount
searchDirection:(EMMessageSearchDirection)aDirection
completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
/*!
* 从数据库获取指定类型的消息,取到的消息按时间排序,如果参考的时间戳为负数,则从最新消息取,如果aCount小于等于0当作1处理
*
* @param aType 消息类型
* @param aTimestamp 参考时间戳
* @param aCount 获取的条数
* @param aUsername 消息发送方,如果为空则忽略
* @param aDirection 消息搜索方向
* @param aCompletionBlock 完成的回调
*/
- (void)loadMessagesWithType:(EMMessageBodyType)aType
timestamp:(long long)aTimestamp
count:(int)aCount
fromUser:(NSString*)aUsername
searchDirection:(EMMessageSearchDirection)aDirection
completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
/*!
* 从数据库获取包含指定内容的消息,取到的消息按时间排序,如果参考的时间戳为负数,则从最新消息向前取,如果aCount小于等于0当作1处理
*
* @param aKeywords 搜索关键字,如果为空则忽略
* @param aTimestamp 参考时间戳
* @param aCount 获取的条数
* @param aSender 消息发送方,如果为空则忽略
* @param aDirection 消息搜索方向
* @param aCompletionBlock 完成的回调
*/
- (void)loadMessagesWithKeyword:(NSString*)aKeyword
timestamp:(long long)aTimestamp
count:(int)aCount
fromUser:(NSString*)aSender
searchDirection:(EMMessageSearchDirection)aDirection
completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
/*!
* 从数据库获取指定时间段内的消息,取到的消息按时间排序,为了防止占用太多内存,用户应当制定加载消息的最大数
*
* @param aStartTimestamp 毫秒级开始时间
* @param aEndTimestamp 结束时间
* @param aCount 加载消息最大数
* @param aCompletionBlock 完成的回调
*/
- (void)loadMessagesFrom:(long long)aStartTimestamp
to:(long long)aEndTimestamp
count:(int)aCount
completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
三、聊天
登录成功之后才能进行聊天操作。发消息时,单聊和群聊调用的是统一接口,区别只是要设置下 message.chatType。
1. 发送消息
/*!
@property
@brief 发送消息
@discussion
异步方法
*/
- (void)sendMessage:(EMMessage *)aMessage
progress:(void (^)(int progress))aProgressBlock
completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock;
//调用:[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {}];
2. 接收消息
注册消息回调
//消息回调:EMChatManagerDelegate
//移除消息回调
[[EMClient sharedClient].chatManager removeDelegate:self];
//注册消息回调
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
在线普通消息会走以下回调:
/*!
@method
@brief 接收到一条及以上非cmd消息
*/
- (void)messagesDidReceive:(NSArray *)aMessages;
透传(cmd)在线消息会走以下回调:
/*!
@method
@brief 接收到一条及以上cmd消息
*/
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages;
3. 解析普通消息
// 收到消息的回调,带有附件类型的消息可以用 SDK 提供的下载附件方法下载(后面会讲到)
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
EMMessageBody *msgBody = message.body;
switch (msgBody.type) {
case EMMessageBodyTypeText:
{
// 收到的文字消息
EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
NSString *txt = textBody.text;
NSLog(@"收到的文字是 txt -- %@",txt);
}
break;
case EMMessageBodyTypeImage:
{
// 得到一个图片消息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.downloadStatus);
// 缩略图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 EMMessageBodyTypeLocation:
{
EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody;
NSLog(@"纬度-- %f",body.latitude);
NSLog(@"经度-- %f",body.longitude);
NSLog(@"地址-- %@",body.address);
}
break;
case EMMessageBodyTypeVoice:
{
// 音频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.downloadStatus);
NSLog(@"音频的时间长度 -- %lu" ,body.duration);
}
break;
case EMMessageBodyTypeVideo:
{
EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody;
NSLog(@"视频remote路径 -- %@" ,body.remotePath);
NSLog(@"视频local路径 -- %@" ,body.localPath); // 需要使用sdk提供的下载方法后才会存在
NSLog(@"视频的secret -- %@" ,body.secretKey);
NSLog(@"视频文件大小 -- %lld" ,body.fileLength);
NSLog(@"视频文件的下载状态 -- %lu" ,body.downloadStatus);
NSLog(@"视频的时间长度 -- %lu" ,body.duration);
NSLog(@"视频的W -- %f ,视频的H -- %f", body.thumbnailSize.width, body.thumbnailSize.height);
// 缩略图sdk会自动下载
NSLog(@"缩略图的remote路径 -- %@" ,body.thumbnailRemotePath);
NSLog(@"缩略图的local路径 -- %@" ,body.thumbnailLocalPath);
NSLog(@"缩略图的secret -- %@" ,body.thumbnailSecretKey);
NSLog(@"缩略图的下载状态 -- %lu" ,body.thumbnailDownloadStatus);
}
break;
case EMMessageBodyTypeFile:
{
EMFileMessageBody *body = (EMFileMessageBody *)msgBody;
NSLog(@"文件remote路径 -- %@" ,body.remotePath);
NSLog(@"文件local路径 -- %@" ,body.localPath); // 需要使用sdk提供的下载方法后才会存在
NSLog(@"文件的secret -- %@" ,body.secretKey);
NSLog(@"文件文件大小 -- %lld" ,body.fileLength);
NSLog(@"文件文件的下载状态 -- %lu" ,body.downloadStatus);
}
break;
default:
break;
}
}
}
4. 解析透传消息
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages
{
for (EMMessage *message in aCmdMessages) {
EMCmdMessageBody *body = (EMCmdMessageBody *)message.body;
NSLog(@"收到的action是 -- %@",body.action);
}
}
5. 解析消息扩展属性
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
for (EMMessage *message in aCmdMessages) {
// cmd消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"cmd消息中的扩展属性是 -- %@",ext)
}
}
// 收到消息回调
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
// 消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"消息中的扩展属性是 -- %@",ext);
}
}
6. 自动下载消息中的附件
SDK 接收到消息后,会默认下载:图片消息的缩略图,语音消息的语音,视频消息的视频第一帧。请先判断你要下载附件没有下载成功之后,在调用以下下载方法,否则SDK下载方法会再次从服务器上获取附件。
[[EMClient sharedClient].chatManager downloadMessageThumbnail:message progress:nil completion:^(EMMessage *message, EMError *error) {
if (!error) {
NSLog(@"下载成功,下载后的message是 -- %@",aMessage);
}
}];
7. 下载消息中的原始附件
[EMClient sharedClient].chatManager downloadMessageAttachment:message progress:nil completion:^(EMMessage *message, EMError *error) {
if (!error) {
NSLog(@"下载成功,下载后的message是 -- %@",aMessage);
}
}];
8. 消息已送达回执
SDK提供了已送达回执,当对方收到您的消息后,您会收到以下回调。
/*!
@method
@brief 接收到一条及以上已送达回执
*/
- (void)messagesDidDeliver:(NSArray *)aMessages;
9. 消息已读回执
已读回执需要开发者主动调用的。当用户读取消息后,由开发者主动调用方法。
发送已读回执
// 发送已读回执。在这里写只是为了演示发送,在APP中具体在哪里发送需要开发者自己决定。
[[EMClient sharedClient].chatManager sendMessageReadAck:message completion:^(EMMessage *message, EMError *error) {
if (!error) {
NSLog(@"发送成功");
}
}];
接收已读回执
/*!
* 接收到一条及以上已读回执
*
* @param aMessages 消息列表<EMMessage>
*/
- (void)messagesDidRead:(NSArray *)aMessages;
后记
很多同事都说环信的IM没有Tencent的做的好,我感觉还可以,文档相对来说接口好找,比较规范,未完,待续~~