环信SDK

初始化 SDK

第 1 步:引入相关头文件 #import “EMSDK.h”。

第 2 步:在工程的 AppDelegate 中的以下方法中,调用 SDK 对应方法。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //AppKey:注册的AppKey,详细见下面注释。
    //apnsCertName:推送证书名(不需要加后缀),详细见下面注释。
    EMOptions *options = [EMOptions optionsWithAppkey:@"douser#istore"];
    options.apnsCertName = @"istore_dev";
    [[EMClient sharedClient] initializeSDKWithOptions:options];
 
    return YES;
}
 
// APP进入后台
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [[EMClient sharedClient] applicationDidEnterBackground:application];
}
 
// APP将要从后台返回
- (void)applicationWillEnterForeground:(UIApplication *)application
{
    [[EMClient sharedClient] applicationWillEnterForeground:application];
}

调用的 SDK 接口参数解释如下:

环信为 IM 部分提供了 APNS 推送功能,如果您要使用,请跳转到APNS离线推送

注册

注册模式分两种,开放注册和授权注册。

  • 只有开放注册时,才可以客户端注册。开放注册是为了测试使用,正式环境中不推荐使用该方式注册环信账号。
  • 授权注册的流程应该是您服务器通过环信提供的 REST API 注册,之后保存到您的服务器或返回给客户端。
EMError *error = [[EMClient sharedClient] registerWithUsername:@"8001" password:@"111111"];
if (error==nil) {
    NSLog(@"注册成功");
}

登录

登录:调用 SDK 的登录接口进行的操作。

EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
if (!error) {
    NSLog(@"登录成功");
}

自动登录

自动登录:即首次登录成功后,不需要再次调用登录方法,在下次 APP 启动时,SDK 会自动为您登录。并且如果您自动登录失败,也可以读取到之前的会话信息。

SDK 中自动登录属性默认是关闭的,需要您在登录成功后设置,以便您在下次 APP 启动时不需要再次调用环信登录,并且能在没有网的情况下得到会话列表。

EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
if (!error)
{
   [[EMClient sharedClient].options setIsAutoLogin:YES];
}

自动登录在以下几种情况下会被取消:

  • 用户调用了 SDK 的登出动作;
  • 用户在别的设备上更改了密码,导致此设备上自动登录失败;
  • 用户的账号被从服务器端删除;
  • 用户从另一个设备登录,把当前设备上登录的用户踢出。

所以,在您调用登录方法前,应该先判断是否设置了自动登录,如果设置了,则不需要您再调用。

BOOL isAutoLogin = [EMClient sharedClient].options.isAutoLogin;
if (!isAutoLogin) {
    EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
}

SDK 中,如果发生自动登录,会有以下回调:

/*!
 *  自动登录返回结果
 *
 *  @param aError 错误信息
 */
- (void)didAutoLoginWithError:(EMError *)aError
 
//添加回调监听代理: [[EMClient sharedClient] addDelegate:self delegateQueue:nil];

重连

当掉线时,iOS SDK 会自动重连,只需要监听重连相关的回调,无需进行任何操作。

/*!
 *  SDK连接服务器的状态变化时会接收到该回调
 *
 *  有以下几种情况,会引起该方法的调用:
 *  1. 登录成功后,手机无法上网时,会调用该回调
 *  2. 登录成功后,网络状态变化时,会调用该回调
 *
 *  @param aConnectionState 当前状态
 */
- (void)didConnectionStateChanged:(EMConnectionState)aConnectionState;

退出登录

退出登录分两种类型:主动退出登录和被动退出登录。

  • 主动退出登录:调用 SDK 的退出接口;
  • 被动退出登录:1. 正在登录的账号在另一台设备上登录;2. 正在登录的账号被从服务器端删除。

logout:YES:是否解除 device token 的绑定,在被动退出时 SDK 内部处理,不需要调用退出方法。

EMError *error = [[EMClient sharedClient] logout:YES];
if (!error) {
     NSLog(@"退出成功");
}

被动退出登录

使用回调方法监听被动退出登录。

/*!
 *  当前登录账号在其它设备登录时会接收到该回调
 */
- (void)didLoginFromOtherDevice;
 
/*!
 *  当前登录账号已经被从服务器端删除时会收到该回调
 */
- (void)didRemovedFromServer;

消息



消息:IM 交互实体,在 SDK 中对应的类型是 EMMessage。EMMessage 由 EMMessageBody 组成。

构造消息

构造文字消息

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;// 设置为聊天室消息

构造图片消息

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;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息

构造位置消息

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;// 设置为聊天室消息

构造语音消息

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;// 设置为聊天室消息

构造视频消息

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;// 设置为聊天室消息

构造文件消息

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;// 设置为聊天室消息

构造透传消息

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.messageType = eMessageTypeChat; // 设置为单聊消息
//message.messageType = eConversationTypeGroupChat;// 设置为群聊消息
//message.messageType = eConversationTypeChatRoom;// 设置为聊天室消息

构造扩展消息

当 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"}; // 扩展消息部分

插入消息

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]];

更新消息属性

/*!
 *  更新消息到 DB
 *
 *  @param aMessage  消息
 *
 *  @result 是否成功
 */
- (BOOL)updateMessage:(EMMessage *)aMessage;
 
//调用:[[EMClient sharedClient].chatManager updateMessage:aMessage];

会话

会话:操作聊天消息 EMMessage 的容器,在 SDK 中对应的类型是 EMConversation。

新建/获取一个会话

根据 conversationId 创建一个 conversation。

[[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];
//EMConversationTypeChat            单聊会话
//EMConversationTypeGroupChat       群聊会话
//EMConversationTypeChatRoom        聊天室会话
  • getConversation:创建与8001的会话
  • type:会话类型
  • createIfNotExist:不存在是否创建

删除会话

删除单个会话

[[EMClient sharedClient].chatManager deleteConversation:@"8001" deleteMessages:YES];
  • deleteConversation: 删除与8001的会话
  • deleteMessages: 删除会话中的消息

根据 conversationId 批量删除会话

[[EMClient sharedClient].chatManager deleteConversations:@[@"8001",@"8002"] deleteMessages:YES];
  • deleteConversations: 要删除的会话
  • deleteMessages: 删除会话中的消息

获取会话列表

SDK中提供了三种获取会会话列表的方法。

获取或创建

EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];
  • getConversation: 获取或创建与8001的会话
  • type:EMConversationTypeChat: 会话类型

获取内存中所有会话

NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];

获取 DB 中的所有会话

NSArray *conversations = [[EMClient sharedClient].chatManager loadAllConversationsFromDB];

获取会话未读消息数

[EMConversation unreadMessagesCount];

消息检索

可以通过关键字、消息类型、开始结束时间检索某个会话中的消息。

/*!
 *  从数据库获取指定类型的消息,取到的消息按时间排序,如果参考的时间戳为负数,则从最新消息向前取,如果 aLimit 是负数,则获取所有符合条件的消息
 *
 *  @param aType        消息类型
 *  @param aTimestamp   参考时间戳
 *  @param aLimit       获取的条数
 *  @param aSender      消息发送方,如果为空则忽略
 *  @param aDirection   消息搜索方向
 *
 *  @result 消息列表<EMMessage>
 */
- (NSArray *)loadMoreMessagesWithType:(EMMessageBodyType)aType
                               before:(long long)aTimestamp
                                limit:(int)aLimit
                                 from:(NSString*)aSender
                            direction:(EMMessageSearchDirection)aDirection;
 
/*!
 *  从数据库获取包含指定内容的消息,取到的消息按时间排序,如果参考的时间戳为负数,则从最新消息向前取,如果 aLimit 是负数,则获取所有符合条件的消息
 *
 *  @param aKeywords    搜索关键字,如果为空则忽略
 *  @param aTimestamp   参考时间戳
 *  @param aLimit       获取的条数
 *  @param aSender      消息发送方,如果为空则忽略
 *  @param aDirection   消息搜索方向
 *
 *  @result 消息列表<EMMessage>
 */
- (NSArray *)loadMoreMessagesContain:(NSString*)aKeywords
                               before:(long long)aTimestamp
                                limit:(int)aLimit
                                 from:(NSString*)aSender
                            direction:(EMMessageSearchDirection)aDirection;
 
/*!
 *  从数据库获取指定时间段内的消息,取到的消息按时间排序,为了防止占用太多内存,用户应当制定加载消息的最大数
 *
 *  @param aStartTimestamp  毫秒级开始时间
 *  @param aEndTimestamp    结束时间
 *  @param aMaxCount        加载消息最大数
 *
 *  @result 消息列表<EMMessage>
 *
 */
- (NSArray *)loadMoreMessagesFrom:(long long)aStartTimestamp
                               to:(long long)aEndTimestamp
                         maxCount:(int)aMaxCount;

聊天

登录成功之后才能进行聊天操作。发消息时,单聊和群聊调用的是统一接口,区别只是要设置下 message.chatType。

发送消息

/*!
 @property
 @brief 发送消息
 @discussion
    异步方法
 */
- (void)asyncSendMessage:(EMMessage *)aMessage
                progress:(void (^)(int progress))aProgress
              completion:(void (^)(EMMessage *message,
                                   EMError *error))aProgressCompletion;
 
//调用:[[EMClient sharedClient].chatManager asyncSendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {}]; 

接收消息

注册消息回调

//消息回调:EMChatManagerChatDelegate
//注册消息回调
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
//移除消息回调
[[EMClient sharedClient].chatManager removeDelegate:self];

在线普通消息会走以下回调:

/*!
 @method
 @brief 接收到一条及以上非cmd消息
 */
- (void)didReceiveMessages:(NSArray *)aMessages;

透传(cmd)在线消息会走以下回调:

/*!
 @method
 @brief 接收到一条及以上cmd消息
 */
- (void)didReceiveCmdMessages:(NSArray *)aCmdMessages;

解析普通消息

// 收到消息的回调,带有附件类型的消息可以用 SDK 提供的下载附件方法下载(后面会讲到)
- (void)didReceiveMessages:(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;
    }
    }
}

解析透传消息

- (void)didReceiveCmdMessages:(NSArray *)aCmdMessages{
    for (EMMessage *message in aCmdMessages) {
        EMCmdMessageBody *body = (EMCmdMessageBody *)message.body;
         NSLog(@"收到的action是 -- %@",body.action);
    }
}

解析消息扩展属性

- (void)didReceiveCmdMessages:(NSArray *)aCmdMessages{
    for (EMMessage *message in aCmdMessages) {
        // cmd消息中的扩展属性
        NSDictionary *ext = message.ext;
        NSLog(@"cmd消息中的扩展属性是 -- %@",ext)
    }
}
// 收到消息回调
- (void)didReceiveMessages:(NSArray *)aMessages{
    for (EMMessage *message in aMessages) {
        // 消息中的扩展属性
        NSDictionary *ext = message.ext;
        NSLog(@"消息中的扩展属性是 -- %@",ext);
    }
}

自动下载消息中的附件

SDK 接收到消息后,会默认下载:图片消息的缩略图,语音消息的语音,视频消息的视频第一帧。

请先判断你要下载附件没有下载成功之后,在调用以下下载方法,否则SDK下载方法会再次从服务器上获取附件。

[[EMClient sharedClient].chatManager asyncDownloadMessageThumbnail:message progress:nil completion:^(EMMessage *message, EMError *error) {
    if (!error) {
        NSLog(@"下载成功,下载后的message是 -- %@",aMessage);
    }
}];

下载消息中的原始附件

[[EMClient sharedClient].chatManager asyncDownloadMessageAttachments:message progress:nil completion:^(EMMessage *message, EMError *error) {
    if (!error) {
        NSLog(@"下载成功,下载后的message是 -- %@",aMessage);
    }
}];

消息已送达回执

SDK提供了已送达回执,当对方收到您的消息后,您会收到以下回调。

/*!
 @method
 @brief 接收到一条及以上已送达回执
 */
- (void)didReceiveHasDeliveredAcks:(NSArray *)aMessages;

消息已读回执

已读回执需要开发者主动调用的。当用户读取消息后,由开发者主动调用方法。

发送已读回执

// 发送已读回执。在这里写只是为了演示发送,在APP中具体在哪里发送需要开发者自己决定。
[[EMClient sharedClient].chatManager asyncSendReadAckForMessage:message];

接收已读回执

/*!
 *  接收到一条及以上已读回执
 *
 *  @param aMessages  消息列表<EMMessage>
 */
- (void)didReceiveHasReadAcks:(NSArray *)aMessages;

好友管理



注:环信不是好友也可以聊天,不推荐使用环信的好友机制。如果你有自己的服务器或好友关系,请自己维护好友关系。

获取好友列表

获取好友列表,环信提供了两种方法。

从服务器获取所有的好友

EMError *error = nil;
NSArray *userlist = [[EMClient sharedClient].contactManager getContactsFromServerWithError:&error];
if (!error) {
    NSLog(@"获取成功 -- %@",buddyList);
}

从数据库获取所有的好友

NSArray *userlist = [[EMClient sharedClient].contactManager getContactsFromDB];

好友申请

发送加好友申请

环信 iOS SDK 提供了添加好友的方法。

注:如果您已经发过,并且对方没有处理,您将不能再次发送。

EMError *error = [[EMClient sharedClient].contactManager addContact:@"6001" message:@"我想加您为好友"];
if (!error) {
    NSLog(@"添加成功");
}

监听加好友请求

当您收到好友请求,如果您没有处理,请自己保存数据,新协议下不会每次都发送。

//注册好友回调
[[EMClient sharedClient].contactManager addDelegate:self delegateQueue:nil];
//移除好友回调
[[EMClient sharedClient].contactManager removeDelegate:self];

监听回调

/*!
 *  用户A发送加用户B为好友的申请,用户B会收到这个回调
 *
 *  @param aUsername   用户名
 *  @param aMessage    附属信息
 */
- (void)didReceiveFriendInvitationFromUsername:(NSString *)aUsername
                                       message:(NSString *)aMessage; 

同意加好友申请

EMError *error = [[EMClient sharedClient].contactManager acceptInvitationForUsername:@"8001"];
if (!error) {
    NSLog(@"发送同意成功");
}

拒绝加好友申请

EMError *error = [[EMClient sharedClient].contactManager declineInvitationForUsername:@"8001"];
if (!error) {
    NSLog(@"发送拒绝成功");
}

好友申请处理结果回调

监听回调

/*!
 @method
 @brief 用户A发送加用户B为好友的申请,用户B同意后,用户A会收到这个回调
 */
- (void)didReceiveAgreedFromUsername:(NSString *)aUsername;
 
/*!
 @method
 @brief 用户A发送加用户B为好友的申请,用户B拒绝后,用户A会收到这个回调
 */
- (void)didReceiveDeclinedFromUsername:(NSString *)aUsername;

删除好友

// 删除好友
EMError *error = [[EMClient sharedClient].contactManager deleteContact:@"6001"];
if (!error) {
    NSLog(@"删除成功");
}
  • deleteContact: 要删除的用户

黑名单

获取好友黑名单

环信的黑名单体系是独立的,与好友无任何关系。也就是说,您可以将任何人加入黑名单,不论他是否与您是好友关系。同时,如果您将好友好友加入黑名单,则他仍然是您的好友,只不过同时也在黑名单中。

查询黑名单列表,环信提供了两种方法。

同步方法

EMError *error = nil;
NSArray *blacklist = [[EMClient sharedClient].contactManager getBlackListFromServerWithError:&error];
if (!error) {
    NSLog(@"获取成功 -- %@",blockedList);
}

从数据库获取黑名单列表

NSArray *blockList = [[EMClient sharedClient].contactManager getBlackListFromDB];

加入黑名单

接口调用

//	将6001加入黑名单
EMError *error = [[EMClient sharedClient].contactManager addUserToBlackList:@"6001" relationshipBoth:YES];
if (!error) {
	NSLog(@"发送成功");
}

移出黑名单

接口调用

// 将6001移除黑名单
EMError *error = [[EMClient sharedClient].contactManager removeUserFromBlackList:@"6001"];
if (!error) {
	NSLog(@"发送成功");
}

群组管理



群组分为四种类型。

/*!
 @enum
 @brief 群组类型
 @constant EMGroupStylePrivateOnlyOwnerInvite 私有群组,创建完成后,只允许 Owner 邀请用户加入
 @constant EMGroupStylePrivateMemberCanInvite 私有群组,创建完成后,只允许 Owner 和群成员邀请用户加入
 @constant EMGroupStylePublicJoinNeedApproval 公开群组,创建完成后,只允许 Owner 邀请用户加入; 非群成员用户需发送入群申请,Owner 同意后才能入组
 @constant EMGroupStylePublicOpenJoin         公开群组,创建完成后,允许非群组成员加入,不需要管理员同意
 @discussion
    eGroupStyle+Private:私有群组,只允许群组成员邀请人进入
    eGroupStyle+Public: 公有群组,允许非群组成员加入
 */
typedef NS_ENUM(NSInteger, EMGroupStyle){
    EMGroupStylePrivateOnlyOwnerInvite  = 0,
    EMGroupStylePrivateMemberCanInvite,
    EMGroupStylePublicJoinNeedApproval,
    EMGroupStylePublicOpenJoin,
};

群组操作

创建群组

目前创建群组支持的配置属性有:

  • 群名称
  • 群描述
  • 群人数(不支持修改,目前上限为2000人)
  • 群类型(即上面提到的四种群组类型)

同步方法:

EMError *error = nil;
EMGroupOptions *setting = [[EMGroupOptions alloc] init];
setting.maxUsersCount = 500;
setting.style = EMGroupStylePublicOpenJoin;// 创建不同类型的群组,这里需要才传入不同的类型
EMGroup *group = [[EMClient sharedClient].groupManager createGroupWithSubject:@"群组名称" description:@"群组描述" invitees:@[@"6001",@"6002"] message:@"邀请您加入群组" setting:setting error:&error];
if(!error){
    NSLog(@"创建成功 -- %@",group);
}

获取群详情

/*!
 @method
 @brief 获取群组信息
 @param aGroupId              群组ID
 @param aIncludeMembersList   是否获取成员列表
 @param pError                错误信息
 @return    群组
 @discussion
    同步方法,会阻塞当前线程
 */
- (EMGroup *)fetchGroupInfo:(NSString *)aGroupId
         includeMembersList:(BOOL)aIncludeMembersList
                      error:(EMError **)pError;
//调用:
//EMError *error = nil;
//EMGroup *group = [[EMClient sharedClient].groupManager fetchGroupInfo:@"groupId" includeMembersList:YES error:&error];                   

加入群组

群组分4种类型,目前 SDK 不支持自主选择是否进群。我们将针对每种类型讲解加入群组要进行的操作。

  • EMGroupStylePrivateOnlyOwnerInvite: 该类型的群组只允许群主(Owner)添加人进群,其他人无法主动加入。
  • EMGroupStylePrivateMemberCanInvite: (推荐使用)该类型的群组允许所有群成员添加人进群,其他人无法主动加入。
  • EMGroupStylePublicJoinNeedApproval: (推荐使用)该类型的群组只允许群主(Owner)添加人进群;其他人想进入群组的话,需要先发送申请,群主同意申请之后才能进群;其他人无法主动加入。
  • EMGroupStylePublicOpenJoin: (不推荐使用)该类型的群组允许任何人主动加入群组。

添加人进群

注册群组回调:

//EMChatManagerDelegate
//注册群组回调
[[EMClient sharedClient].groupManager addDelegate:self delegateQueue:nil];
//移除群组回调
[[EMClient sharedClient].groupManager removeDelegate:self];

被添加的人会收到回调:

/*!
 @method
 @brief 用户B设置了自动同意,用户A邀请用户B入群,SDK 内部进行同意操作之后,用户B接收到该回调
 */
- (void)didJoinedGroup:(EMGroup *)aGroup
               inviter:(NSString *)aInviter
               message:(NSString *)aMessage;       

加人接口如下:

EMError *error = nil;
[[EMClient sharedClient].groupManager addOccupants:@[@"user1"] toGroup:@"groupId" welcomeMessage:@"message" error:&error];

发送进群申请

// 申请加入需要审核的公开群组
EMError *error = nil;
[[EMClient sharedClient].groupManager applyJoinPublicGroup:@"groupId" message:@"" error:nil];

处理进群申请

只有 Owner 有权限处理进群申请。

1. 收到进群申请。

/*!
 @method
 @brief 用户A向群组G发送入群申请,群组G的群主O会接收到该回调
 */
- (void)didReceiveJoinGroupApplication:(EMGroup *)aGroup
                             applicant:(NSString *)aApplicant
                                reason:(NSString *)aReason;

2. 同意进群申请。

/*!
 @method
 @brief 同意加入群组的申请
 @param aGroupId   所申请的群组 ID
 @param aGroupname 申请的群组名称
 @param aUsername  申请人的 username
 @discussion
     需要 Owner 权限
     同步方法,会阻塞当前线程
 */
- (EMError *)acceptJoinApplication:(NSString *)aGroupId
                         groupname:(NSString *)aGroupname
                         applicant:(NSString *)aUsername;
 
//调用:
//EMError *error = [[EMClient sharedClient].groupManager acceptJoinApplication:@"groupId" groupname:@"subject" applicant:@"user1"];

3. 拒绝加群申请。

EMError *error = [[EMClient sharedClient].groupManager declineJoinApplication:@"groupId" groupname:@"subject" applicant:@"user1" reason:@"拒绝的原因"];

加入 eGroupStyle_PublicOpenJoin 类型的群组

EMError *error = nil;
[[EMClient sharedClient].groupManager joinPublicGroup:@"1410329312753" error:&error];

退出群组

群主(Owner)不支持退群操作,只能解散群。

退出群组分为主动退群和被动退群。被动退群即为被 Owner 踢出群组。

主动退群

EMError *error = nil;
[[EMClient sharedClient].groupManager leaveGroup:@"1410329312753" error:&error];

被动退群

会通过以下回调通知被踢者。

/*!
 @method
 @brief 接收到离开群组,群组被销毁或者被从群中移除
 */
- (void)didReceiveLeavedGroup:(EMGroup *)aGroup
                       reason:(EMGroupLeaveReason)aReason;

解散群组

解散群组需要 Owner 权限。

EMError *error = nil;
[[EMClient sharedClient].groupManager destroyGroup:@"groupId" error:&error];
if (!error) {
    NSLog(@"解散成功");
}

修改群名称

只有 Owner 有权限修改。

EMError *error = nil;
// 修改群名称
[[EMClient sharedClient].groupManager changeGroupSubject:@"要修改的名称" forGroup:@"1410329312753" error:&error];
if (!error) {
    NSLog(@"修改成功");
}

修改群描述

不推荐使用 ,只有 Owner 有权限操作。

EMError *error = nil;
// 修改群描述
EMGroup* group = [[EMClient sharedClient].groupManager changeDescription:@"修改的群描述" forGroup:@"1410329312753" error:&error];
if (!error) {
    NSLog(@"修改成功");
}

群成员管理

移除群成员

只有 Owner 权限才能调用。

/*!
 @method
 @brief 将群成员移出群组
 @param aOccupants 要请出群组的人的用户名列表
 @param aGroupId   群组ID
 @param pError     错误信息
 @result    返回群组对象
 @discussion
     此操作需要 Owner 权限
     同步方法,会阻塞当前线程
 */
- (EMGroup *)removeOccupants:(NSArray *)aOccupants
                   fromGroup:(NSString *)aGroupId
                       error:(EMError **)pError;
 
//调用:
//EMError *error = nil;
//[[EMClient sharedClient].groupManager removeOccupants:@[@"user1"] fromGroup:@"1410329312753" error:&error];                        

加入群黑名单

只有 Owner 权限才能调用该接口,并且只有 Owner 权限的才能查看群黑名单。

可以将群成员和非群成员的人加入群黑名单。

/*!
 @method
 @brief 将某些人加入群组黑名单
 @param aOccupants 要加入黑名单的用户名列表
 @param aGroupId   群组ID
 @param pError     错误信息
 @result    返回群组对象
 @discussion
     此操作需要 Owner 权限。被加入黑名单的人,不会再被允许进入群组。
     同步方法,会阻塞当前线程
 */
- (EMGroup *)blockOccupants:(NSArray *)aOccupants
                  fromGroup:(NSString *)aGroupId
                      error:(EMError **)pError;
//调用:
//EMError *error = nil;
//EMGroup *group = [[EMClient sharedClient].groupManager blockOccupants:@[@"user1"] fromGroup:@"1410329312753" error:&error];

移出群黑名单

只有 Owner 权限才能调用该接口,并且只有 Owner 权限的才能查看群黑名单。

从群黑名单移除出去,该用户已经不在群组里了,需要重新加入群组。

/*!
 @method
 @brief 将某些人从群组黑名单中解除
 @param aOccupants 要从黑名单中移除的用户名列表
 @param aGroupId   群组ID
 @param pError     错误信息
 @result    返回群组对象
 @discussion
     此操作需要 Owner 权限。从黑名单中移除后不再是群组成员,需要重新加入。
     同步方法,会阻塞当前线程
 */
- (EMGroup *)unblockOccupants:(NSArray *)aOccupants
                     forGroup:(NSString *)aGroupId
                        error:(EMError **)pError;
//调用:
//EMError *error = nil;
//EMGroup *group = [[EMClient sharedClient].groupManager unblockOccupants:@[@"user1"] forGroup:@"1410329312753" error:&error];

群消息

屏蔽/取消屏蔽群组推送

不允许 Owner 权限的调用。

/*!
 @method
 @brief 屏蔽/取消屏蔽群组推送
 @param aGroupId    群组ID
 @param aIgnore     是否屏蔽
 @result 错误信息
 @discussion
    同步方法,会阻塞当前线程
 */
- (EMError *)ignoreGroupPush:(NSString *)aGroupId
                      ignore:(BOOL)aIgnore;
//调用:
//EMError *error = [[EMClient sharedClient].groupManager ignoreGroupPush:@"1410329312753" ignore:YES];

管理群组的 APNS 离线推送

见 APNS离线推送-设置指定群组是否接收APNS

获取与登录者相关的群组

查看所有当前登录账号所在群组,包括创建的和加入的群组,提供了三种方法。

1.从服务器获取与我相关的群组列表

EMError *error = nil;
NSArray *myGroups = [[EMClient sharedClient].groupManager getMyGroupsFromServerWithError:&error];
if (!error) {
    NSLog(@"获取成功 -- %@",myGroups);
}

2. 获取数据库中所有的群组

NSArray *groupList = [[EMClient sharedClient].groupManager loadAllMyGroupsFromDB];

3. 取内存中的值

从内存中获取所有群组。

NSArray *groupList = [[EMClient sharedClient].groupManager getAllGroups];

获取公开群组

获取指定范围内的公开群。

EMError *error = nil;
EMCursorResult *result = [[EMClient sharedClient].groupManager getPublicGroupsFromServerWithCursor:nil pageSize:50 error:&error];
if (!error) {
    NSLog(@"获取成功 -- %@",result);
}
时间: 2024-10-13 15:11:32

环信SDK的相关文章

李洪强iOS开发之-环信02.2_环信官网下载环信 SDK

李洪强iOS开发之-环信02.2_环信官网下载环信 SDK 移动客服即时通讯云 iOS SDK 当前版本:V3.1.4 2016-07-08 [ 版本历史 ] | 开发指南 | 知识库 | Demo源码 | 最新SDK下载Demo扫码安装 切换至v2.x版本 iOS SDK v2.x 当前版本:V2.2.6 2016-06-28 [ 版本历史 ] | 开发指南 | 知识库 | Demo源码 | 最新SDK下载Demo扫码安装 返回v3.x版本 Android SDK 当前版本:V3.1.4 20

李洪强iOS开发之-环信02.1_环信 SDK 2.x到3.0升级文档

李洪强iOS开发之-环信02.1_环信 SDK 2.x到3.0升级文档 SDK 2.x 至 3.0 升级指南 环信 SDK 3.0 升级文档 3.0 中的核心类为 EMClient 类,通过 EMClient 类可以获取到 chatManager.groupManager.contactManager.roomManager对象.原来 2.0 版本的 SDK 很多方法提供了同步.异步回调.异步(block)三种方法,3.0 版只提供同步方法(async开头的方法为异步方法). 例如: //2.0

环信SDK与Apple Watch的结合(2)

这一篇主要是介绍怎么拖apple watch上的相关页面,附源码EMWatchOCDemo. 需要在工程中的“EMWatchOCDemo WatchKit App”中进行操作,该文件夹的 WatchKit几乎不允许直接coding页面,只能在storyboard上拖来拖去,对于我这种习惯直接coding 页面的人来说,真真是极痛苦的. 一.确定apple watch上的操作流程 首先,我想要一个菜单页面,跟iPhone程序对应,在环信SDK未登录情况下,显示登录选项;在环信 SDK登录情况下,有

环信SDK与Apple Watch的结合(3)

第3章主要介绍怎样在Watch App的页面上显示iPhone程序里的数据.主要操作的是“EMWatchOCDemo WatchKit Extension”这个文件夹. 如果你已经看过我在第1章推荐的blog,应该明白这个target主要是负责逻辑的,从iPhone App中获取数据,调动Watch App显示数据. 默认是这个样子的 一.WathKit定义了一些专门用于Watch App的类,与UIKit的对比如下图 二.整合Watch App和iPhone App 1.新建Controlle

iOS环信3.0集成 (一)SDK的集成

一.准备工作 1.注册环信帐号 注册一个环信账号之后,我们用注册的帐号登陆.然后创建一个应用,会得到一个对应的AppKey,这个AppKey在初始化环信SDK的时候需要用到. 点击查看注册环信帐号教程 2.制作推送证书 如果需要做离线推送的功能,需要制作一个推送证书.如果只是需要实现单聊.群聊等功能,可以跳过此步骤.个人建议刚开始接触环信的开发者可以忽略此步骤. 点击查看制作推送证书教程 3.下载环信SDK 点击下载环信iOS版的SDK 二.集成环信的SDK 1.把环信SDK添加到工程中 从环信

iOS 环信集成问题(连文档都不说明的坑。。)

首先,关于环信SDK的下载和一些依赖库的添加,在此我就不做详细介绍,(http://www.easemob.com/download/im)附上环信官网文档,可以看一下,上面都可以下载,也有相关配置介绍. 今天主要说一下,环信集成遇到的各种坑,各种问题,有的连文档都不说明的坑..(主要是讲解完全集成环信,UI的聊天界面,单聊功能也是环信的这种情况) 各位可能刚在官网下载下来ChatDemo-UI3.0这个版本,会发现HyphenateFullSDK和官网文档有个不一样的地方,少了个文件(libH

IOS开发 EaseMobSDK 环信快速集成

一.新建工程,将下载好环信SDK的<EaseMobSDK>文件夹添加到工程中. 二.添加依赖 三.将EaseMobSDK文件夹中include文件夹路径添加到Header Search Paths中. Other Linker Flags 中添加-ObjC 都在Build Settings中. 四.完成后在 AppDelegate.m中 启动文件 中写入代码 [[EaseMob sharedInstance] registerSDKWithAppKey:@"easemob-demo#

2015.01.16工作笔记 环信方法整理

以下方法都基于环信SDK 2.1.4 所带的示例demo. 添加好友 EMContactManager.getInstance().addContact(用户账号, "验证信息"); 创建自由进入的公开群 EMGroupManager.getInstance().createPrivateGroup(群组名称, 群组描述, 群成员数组, memberCheckbox.isChecked()); 创建不公开的群(无法查找只能通过群内邀请) EMGroupManager.getInstan

环信 集成 笔记

环信的教程: 没有初始化SDK 去AppDelegate里面初始化 密码 User not exist         ?????????? 每一个应用都有自己的注册用户  去你的后台管理   去看你的注册的用户数 为什么demo的可以跑起来???????? 是在它的应用下注册的 怎么去注册用户  -注册用户 用户名字可以相同   不同的应用 那个打印的loginInfo 是这个字典的也就是用户的登录信息 你会发现打印的loginInfo上面还有一坨恶心的东西,那个是环信SDK自己打印的日志信息