版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2017.06.08 |
前言
很多app種都集成環(huán)信做第三方信息通訊工具,這里我們就看一下環(huán)信的主要功能和集成方法。先給出環(huán)信3.0的地址。
感興趣的可以參考:
1. 環(huán)信ios客戶端的集成(一)
2. 環(huán)信ios客戶端的集成(二)
3. 環(huán)信ios客戶端的集成(三)
4. 環(huán)信ios客戶端的集成(四)
這一篇主要說(shuō)一下環(huán)信的消息。
一、構(gòu)造信息
消息分為文字,圖片,聲音等等很多種形式,消息的構(gòu)造也分很多種,下面就對(duì)消息的構(gòu)造進(jìn)行說(shuō)明。
1. 構(gòu)造文字消息
看代碼
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要發(fā)送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
//message.chatType = EMChatTypeChatRoom;// 設(shè)置為聊天室消息
2. 構(gòu)造圖片消息
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;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
3. 構(gòu)造位置消息
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;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
//message.chatType = EMChatTypeChatRoom;// 設(shè)置為聊天室消息
4. 構(gòu)造語(yǔ)音消息
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;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
//message.chatType = EMChatTypeChatRoom;// 設(shè)置為聊天室消息
5. 構(gòu)造視頻消息
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;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
//message.chatType = EMChatTypeChatRoom;// 設(shè)置為聊天室消息
6. 構(gòu)造文件消息
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;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
//message.chatType = EMChatTypeChatRoom;// 設(shè)置為聊天室消息
7. 構(gòu)造透?jìng)飨?/h2>
SDK 提供的一種特殊類型的消息,即 CMD,不會(huì)存 db,也不會(huì)走 APNS 推送,類似一種指令型的消息。比如您的服務(wù)器要通知客戶端做某些操作,您可以服務(wù)器和客戶端提前約定好某個(gè)字段,當(dāng)客戶端收到約定好的字段時(shí),執(zhí)行某種特殊操作。
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;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
//message.chatType = EMChatTypeChatRoom;// 設(shè)置為聊天室消息
8. 構(gòu)造擴(kuò)展消息
當(dāng) SDK 提供的消息類型不滿足需求時(shí),開(kāi)發(fā)者可以通過(guò)擴(kuò)展自 SDK 提供的文本、語(yǔ)音、圖片、位置等消息類型,從而生成自己需要的消息類型。
??這里是擴(kuò)展自文本消息,如果這個(gè)自定義的消息需要用到語(yǔ)音或者圖片等,可以擴(kuò)展自語(yǔ)音、圖片消息,亦或是位置消息。
// 以單聊消息舉例
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要發(fā)送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
//message.chatType = EMChatTypeChatRoom;// 設(shè)置為聊天室消息
message.ext = @{@"key":@"value"}; // 擴(kuò)展消息部分
9. 插入消息
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要發(fā)送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 設(shè)置為單聊消息
//message.chatType = EMChatTypeGroupChat;// 設(shè)置為群聊消息
//message.chatType = EMChatTypeChatRoom;// 設(shè)置為聊天室消息
[[EMClient sharedClient].chatManager importMessages:@[message] completion:^(EMError *aError) {
//code
}];
10. 更新消息屬性
/*!
* 更新消息到 DB
*
* @param aMessage 消息
*
* @result 是否成功
*/
- (BOOL)updateMessage:(EMMessage *)aMessage;
//調(diào)用:[[EMClient sharedClient].chatManager updateMessage:aMessage];
二、會(huì)話
會(huì)話:操作聊天消息 EMMessage 的容器,在 SDK 中對(duì)應(yīng)的類型是 EMConversation。
1. 新建/獲取一個(gè)會(huì)話
根據(jù) conversationId 創(chuàng)建一個(gè) conversation。
[[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];
//EMConversationTypeChat 單聊會(huì)話
//EMConversationTypeGroupChat 群聊會(huì)話
//EMConversationTypeChatRoom 聊天室會(huì)話
- getConversation:創(chuàng)建與8001的會(huì)話
- type:會(huì)話類型
- createIfNotExist:不存在是否創(chuàng)建
2. 刪除會(huì)話
刪除單個(gè)會(huì)話
[[EMClient sharedClient].chatManager deleteConversation:@"8001" isDeleteMessages:YES completion:^(NSString *aConversationId, EMError *aError){
//code
}];
- deleteConversation: 刪除與8001的會(huì)話
- deleteMessages: 刪除會(huì)話中的消息
根據(jù) conversationId 批量刪除會(huì)話
[[EMClient sharedClient].chatManager deleteConversations:@[@"8001",@"8002"] isDeleteMessages:YES completion:^(EMError *aError){
//code
}];
- deleteConversations: 要?jiǎng)h除的會(huì)話
- deleteMessages: 刪除會(huì)話中的消息
3. 獲取會(huì)話列表
SDK中提供了三種獲取會(huì)話列表的方法。
獲取或創(chuàng)建
EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];
- getConversation: 獲取或創(chuàng)建與8001的會(huì)話
- type:EMConversationTypeChat: 會(huì)話類型
獲取所有會(huì)話(內(nèi)存中有則從內(nèi)存中取,沒(méi)有則從db中取)
NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
4. 獲取會(huì)話未讀消息數(shù)
[EMConversation unreadMessagesCount];
5. 消息檢索
可以通過(guò)關(guān)鍵字、消息類型、開(kāi)始結(jié)束時(shí)間檢索某個(gè)會(huì)話中的消息。
/*!
* 從數(shù)據(jù)庫(kù)獲取指定數(shù)量的消息,取到的消息按時(shí)間排序,并且不包含參考的消息,如果參考消息的ID為空,則從最新消息取
*
* @param aMessageId 參考消息的ID
* @param count 獲取的條數(shù)
* @param aDirection 消息搜索方向
* @param aCompletionBlock 完成的回調(diào)
*/
- (void)loadMessagesStartFromId:(NSString *)aMessageId
count:(int)aCount
searchDirection:(EMMessageSearchDirection)aDirection
completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
/*!
* 從數(shù)據(jù)庫(kù)獲取指定類型的消息,取到的消息按時(shí)間排序,如果參考的時(shí)間戳為負(fù)數(shù),則從最新消息取,如果aCount小于等于0當(dāng)作1處理
*
* @param aType 消息類型
* @param aTimestamp 參考時(shí)間戳
* @param aCount 獲取的條數(shù)
* @param aUsername 消息發(fā)送方,如果為空則忽略
* @param aDirection 消息搜索方向
* @param aCompletionBlock 完成的回調(diào)
*/
- (void)loadMessagesWithType:(EMMessageBodyType)aType
timestamp:(long long)aTimestamp
count:(int)aCount
fromUser:(NSString*)aUsername
searchDirection:(EMMessageSearchDirection)aDirection
completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
/*!
* 從數(shù)據(jù)庫(kù)獲取包含指定內(nèi)容的消息,取到的消息按時(shí)間排序,如果參考的時(shí)間戳為負(fù)數(shù),則從最新消息向前取,如果aCount小于等于0當(dāng)作1處理
*
* @param aKeywords 搜索關(guān)鍵字,如果為空則忽略
* @param aTimestamp 參考時(shí)間戳
* @param aCount 獲取的條數(shù)
* @param aSender 消息發(fā)送方,如果為空則忽略
* @param aDirection 消息搜索方向
* @param aCompletionBlock 完成的回調(diào)
*/
- (void)loadMessagesWithKeyword:(NSString*)aKeyword
timestamp:(long long)aTimestamp
count:(int)aCount
fromUser:(NSString*)aSender
searchDirection:(EMMessageSearchDirection)aDirection
completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
/*!
* 從數(shù)據(jù)庫(kù)獲取指定時(shí)間段內(nèi)的消息,取到的消息按時(shí)間排序,為了防止占用太多內(nèi)存,用戶應(yīng)當(dāng)制定加載消息的最大數(shù)
*
* @param aStartTimestamp 毫秒級(jí)開(kāi)始時(shí)間
* @param aEndTimestamp 結(jié)束時(shí)間
* @param aCount 加載消息最大數(shù)
* @param aCompletionBlock 完成的回調(diào)
*/
- (void)loadMessagesFrom:(long long)aStartTimestamp
to:(long long)aEndTimestamp
count:(int)aCount
completion:(void (^)(NSArray *aMessages, EMError *aError))aCompletionBlock;
三、聊天
登錄成功之后才能進(jìn)行聊天操作。發(fā)消息時(shí),單聊和群聊調(diào)用的是統(tǒng)一接口,區(qū)別只是要設(shè)置下 message.chatType。
1. 發(fā)送消息
/*!
@property
@brief 發(fā)送消息
@discussion
異步方法
*/
- (void)sendMessage:(EMMessage *)aMessage
progress:(void (^)(int progress))aProgressBlock
completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock;
//調(diào)用:[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {}];
2. 接收消息
注冊(cè)消息回調(diào)
//消息回調(diào):EMChatManagerDelegate
//移除消息回調(diào)
[[EMClient sharedClient].chatManager removeDelegate:self];
//注冊(cè)消息回調(diào)
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
在線普通消息會(huì)走以下回調(diào):
/*!
@method
@brief 接收到一條及以上非cmd消息
*/
- (void)messagesDidReceive:(NSArray *)aMessages;
透?jìng)?cmd)在線消息會(huì)走以下回調(diào):
/*!
@method
@brief 接收到一條及以上cmd消息
*/
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages;
3. 解析普通消息
// 收到消息的回調(diào),帶有附件類型的消息可以用 SDK 提供的下載附件方法下載(后面會(huì)講到)
- (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:
{
// 得到一個(gè)圖片消息body
EMImageMessageBody *body = ((EMImageMessageBody *)msgBody);
NSLog(@"大圖remote路徑 -- %@" ,body.remotePath);
NSLog(@"大圖local路徑 -- %@" ,body.localPath); // // 需要使用sdk提供的下載方法后才會(huì)存在
NSLog(@"大圖的secret -- %@" ,body.secretKey);
NSLog(@"大圖的W -- %f ,大圖的H -- %f",body.size.width,body.size.height);
NSLog(@"大圖的下載狀態(tài) -- %lu",body.downloadStatus);
// 縮略圖sdk會(huì)自動(dòng)下載
NSLog(@"小圖remote路徑 -- %@" ,body.thumbnailRemotePath);
NSLog(@"小圖local路徑 -- %@" ,body.thumbnailLocalPath);
NSLog(@"小圖的secret -- %@" ,body.thumbnailSecretKey);
NSLog(@"小圖的W -- %f ,大圖的H -- %f",body.thumbnailSize.width,body.thumbnailSize.height);
NSLog(@"小圖的下載狀態(tài) -- %lu",body.thumbnailDownloadStatus);
}
break;
case EMMessageBodyTypeLocation:
{
EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody;
NSLog(@"緯度-- %f",body.latitude);
NSLog(@"經(jīng)度-- %f",body.longitude);
NSLog(@"地址-- %@",body.address);
}
break;
case EMMessageBodyTypeVoice:
{
// 音頻sdk會(huì)自動(dòng)下載
EMVoiceMessageBody *body = (EMVoiceMessageBody *)msgBody;
NSLog(@"音頻remote路徑 -- %@" ,body.remotePath);
NSLog(@"音頻local路徑 -- %@" ,body.localPath); // 需要使用sdk提供的下載方法后才會(huì)存在(音頻會(huì)自動(dòng)調(diào)用)
NSLog(@"音頻的secret -- %@" ,body.secretKey);
NSLog(@"音頻文件大小 -- %lld" ,body.fileLength);
NSLog(@"音頻文件的下載狀態(tài) -- %lu" ,body.downloadStatus);
NSLog(@"音頻的時(shí)間長(zhǎng)度 -- %lu" ,body.duration);
}
break;
case EMMessageBodyTypeVideo:
{
EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody;
NSLog(@"視頻remote路徑 -- %@" ,body.remotePath);
NSLog(@"視頻local路徑 -- %@" ,body.localPath); // 需要使用sdk提供的下載方法后才會(huì)存在
NSLog(@"視頻的secret -- %@" ,body.secretKey);
NSLog(@"視頻文件大小 -- %lld" ,body.fileLength);
NSLog(@"視頻文件的下載狀態(tài) -- %lu" ,body.downloadStatus);
NSLog(@"視頻的時(shí)間長(zhǎng)度 -- %lu" ,body.duration);
NSLog(@"視頻的W -- %f ,視頻的H -- %f", body.thumbnailSize.width, body.thumbnailSize.height);
// 縮略圖sdk會(huì)自動(dòng)下載
NSLog(@"縮略圖的remote路徑 -- %@" ,body.thumbnailRemotePath);
NSLog(@"縮略圖的local路徑 -- %@" ,body.thumbnailLocalPath);
NSLog(@"縮略圖的secret -- %@" ,body.thumbnailSecretKey);
NSLog(@"縮略圖的下載狀態(tài) -- %lu" ,body.thumbnailDownloadStatus);
}
break;
case EMMessageBodyTypeFile:
{
EMFileMessageBody *body = (EMFileMessageBody *)msgBody;
NSLog(@"文件remote路徑 -- %@" ,body.remotePath);
NSLog(@"文件local路徑 -- %@" ,body.localPath); // 需要使用sdk提供的下載方法后才會(huì)存在
NSLog(@"文件的secret -- %@" ,body.secretKey);
NSLog(@"文件文件大小 -- %lld" ,body.fileLength);
NSLog(@"文件文件的下載狀態(tài) -- %lu" ,body.downloadStatus);
}
break;
default:
break;
}
}
}
4. 解析透?jìng)飨?/h2>
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages
{
for (EMMessage *message in aCmdMessages) {
EMCmdMessageBody *body = (EMCmdMessageBody *)message.body;
NSLog(@"收到的action是 -- %@",body.action);
}
}
5. 解析消息擴(kuò)展屬性
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
for (EMMessage *message in aCmdMessages) {
// cmd消息中的擴(kuò)展屬性
NSDictionary *ext = message.ext;
NSLog(@"cmd消息中的擴(kuò)展屬性是 -- %@",ext)
}
}
// 收到消息回調(diào)
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
// 消息中的擴(kuò)展屬性
NSDictionary *ext = message.ext;
NSLog(@"消息中的擴(kuò)展屬性是 -- %@",ext);
}
}
6. 自動(dòng)下載消息中的附件
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages
{
for (EMMessage *message in aCmdMessages) {
EMCmdMessageBody *body = (EMCmdMessageBody *)message.body;
NSLog(@"收到的action是 -- %@",body.action);
}
}
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
for (EMMessage *message in aCmdMessages) {
// cmd消息中的擴(kuò)展屬性
NSDictionary *ext = message.ext;
NSLog(@"cmd消息中的擴(kuò)展屬性是 -- %@",ext)
}
}
// 收到消息回調(diào)
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
// 消息中的擴(kuò)展屬性
NSDictionary *ext = message.ext;
NSLog(@"消息中的擴(kuò)展屬性是 -- %@",ext);
}
}
SDK 接收到消息后,會(huì)默認(rèn)下載:圖片消息的縮略圖,語(yǔ)音消息的語(yǔ)音,視頻消息的視頻第一幀。請(qǐng)先判斷你要下載附件沒(méi)有下載成功之后,在調(diào)用以下下載方法,否則SDK下載方法會(huì)再次從服務(wù)器上獲取附件。
[[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. 消息已送達(dá)回執(zhí)
SDK提供了已送達(dá)回執(zhí),當(dāng)對(duì)方收到您的消息后,您會(huì)收到以下回調(diào)。
/*!
@method
@brief 接收到一條及以上已送達(dá)回執(zhí)
*/
- (void)messagesDidDeliver:(NSArray *)aMessages;
9. 消息已讀回執(zhí)
已讀回執(zhí)需要開(kāi)發(fā)者主動(dòng)調(diào)用的。當(dāng)用戶讀取消息后,由開(kāi)發(fā)者主動(dòng)調(diào)用方法。
發(fā)送已讀回執(zhí)
// 發(fā)送已讀回執(zhí)。在這里寫只是為了演示發(fā)送,在APP中具體在哪里發(fā)送需要開(kāi)發(fā)者自己決定。
[[EMClient sharedClient].chatManager sendMessageReadAck:message completion:^(EMMessage *message, EMError *error) {
if (!error) {
NSLog(@"發(fā)送成功");
}
}];
接收已讀回執(zhí)
/*!
* 接收到一條及以上已讀回執(zhí)
*
* @param aMessages 消息列表<EMMessage>
*/
- (void)messagesDidRead:(NSArray *)aMessages;
后記
很多同事都說(shuō)環(huán)信的IM沒(méi)有Tencent的做的好,我感覺(jué)還可以,文檔相對(duì)來(lái)說(shuō)接口好找,比較規(guī)范,未完,待續(xù)~~