环信3.0ios客户端的集成(十三)

版本记录

版本号 时间
V1.0 2017.06.10

前言

很多app种都集成环信做第三方信息通讯工具,这里我们就看一下环信的主要功能和集成方法。先给出环信3.0的地址。
感兴趣的可以参考:
1. 环信ios客户端的集成(一)
2. 环信ios客户端的集成(二)
3. 环信ios客户端的集成(三)
4. 环信ios客户端的集成(四)
5. 环信ios客户端的集成(五)
6. 环信ios客户端的集成(六)
7. 环信ios客户端的集成(七)
8. 环信ios客户端的集成(八)
9. 环信ios客户端的集成(九)
10. 环信ios客户端的集成(十)
11. 环信ios客户端的集成(十一)
12. 环信ios客户端的集成(十二)
这一篇主要说一下环信的 EaseUI 使用

一、简介

EaseUI 封装了 IM 功能常用的控件(如聊天会话、会话列表、联系人列表)。旨在帮助开发者快速集成环信 SDK。

源码地址:


二、视频教程

以下是EaseUI集成参考视频,您可以通过视频学习如何集成环信SDK。


三、快速集成

1. 方法一:

  • 通过 Cocoapods 来集成 EaseUI:
//集成环信SDK
pod 'Hyphenate'
//集成环信EaseUI
pod 'EaseUI', :git => 'https://github.com/easemob/easeui-ios-hyphenate-cocoapods.git'

注意: 由于SDK改成了动态库,EaseUI引入的头文件Full版本和Lite版本不同,导致集成EaseUI失败。代码中包含了宏ENABLE_LITE的定义这个是为了区分集成Lite版本SDK还是Full版本SDK,当通过pod在集成EaseUILite时会在Build Settings> GCC_PREPROCESSOR_DEFINITIONS >ENABLE_LITE=1中定义ENABLE_LITE,集成EaseUI时则不会定义,所以开发者不需要关注这个字段,如果集成Lite版本SDK,建议使用

//集成环信Lite版SDK
pod 'HyphenateLite'
//集成环信EaseUI
pod 'EaseUILite', :git =>'https://github.com/easemob/easeui-ios-hyphenate-cocoapods.git'

2.方法二:

  • 集成 EaseUI 前,首先需要集成环信 iOS SDK,参考:集成文档。
  • 参考ChatDemo3.0 导入的方式,直接将EaseUI拖入已经集成SDK的项目中。

四、初始化

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

第 2 步:在工程的 AppDelegate 中的以下方法中,调用 EaseUI 对应方法。(注: 此方法不需要重复调用)

[[EaseSDKHelper shareHelper] hyphenateApplication:application
                    didFinishLaunchingWithOptions:launchOptions
                                               appkey:appkey
                                     apnsCertName:apnsCertName
                                      otherConfig:@{kSDKConfigEnableConsoleLogger:[NSNumber numberWithBool:YES]}];


五、聊天会话

创建聊天会话、传递用户或群 ID 和会话类型(EMConversationType)。

EaseMessageViewController *chatController = [[EaseMessageViewController alloc] initWithConversationChatter:@"8001" conversationType:EMConversationTypeChat];


六、聊天页面刷新

EaseRefreshTableViewController提供了列表上拉加载、下拉刷新(加载)功能的UIViewController,其中已添加控件UITableView,默认未开启上拉加载、下来刷新(加载)的功能

1.实现上拉加载功能

继承自EaseRefreshTableViewController的子类,开启上拉加载需要设置showRefreshFooter为YES,并重写父类方法- (void)tableViewDidTriggerFooterRefresh;,如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    self.showRefreshFooter = YES;
}

- (void)tableViewDidTriggerFooterRefresh {
   //子类需要重写此方法
   
}

2.实现下拉加载(刷新)功能

继承自EaseRefreshTableViewController的子类,开启下拉加载(刷新)需要设置showRefreshHeader为YES,并重写父类方法- (void)tableViewDidTriggerHeaderRefresh;,如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    self.showRefreshHeader = YES;
}

- (void)tableViewDidTriggerHeaderRefresh {
   //子类需要重写此方法
   
}

七、聊天会话功能扩展

EaseUI 提供现成的聊天会话 ViewController,可以通过继承 EaseMessageViewController 方式(参考 ChatDemo-UI3.0 中 ChatViewController)实现对聊天会话的扩展。也可以直接使用 EaseMessageViewController,通过 EaseMessageViewControllerDelegate 和 EaseMessageViewControllerDataSource 两个协议实现对 EaseMessageViewController 的扩展。

1.实现自定义聊天样式

EaseMessageViewControllerDelegate

获取自定义消息 cell,根据 messageModel,用户自己判断是否显示自定义消息 cell。如果返回 nil 会显示默认;如果返回 cell 会显示用户自定义消息cell。

/*!
 @method
 @brief 获取消息自定义cell
 @discussion 用户根据messageModel判断是否显示自定义cell。返回nil显示默认cell,否则显示用户自定义cell
 @param tableView 当前消息视图的tableView
 @param messageModel 消息模型
 @result 返回用户自定义cell
 */
- (UITableViewCell *)messageViewController:(UITableView *)tableView
                       cellForMessageModel:(id<IMessageModel>)messageModel;

/*!
 @method
 @brief 获取消息cell高度
 @discussion 用户根据messageModel判断,是否自定义显示cell的高度
 @param viewController 当前消息视图
 @param messageModel 消息模型
 @param cellWidth 视图宽度
 @result 返回用户自定义cell
 */
- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
           heightForMessageModel:(id<IMessageModel>)messageModel
                   withCellWidth:(CGFloat)cellWidth;
                   
//具体创建自定义Cell的样例:
- (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id<IMessageModel>)model
{
    //样例为如果消息是文本消息显示用户自定义cell
    if (model.bodyType == eMessageBodyType_Text) {
        NSString *CellIdentifier = [CustomMessageCell cellIdentifierWithModel:model];
        //CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
        CustomMessageCell *cell = (CustomMessageCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[CustomMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model];
            cell.selectionStyle = UITableViewCellSelectionStyleNone;
        }
        cell.model = model;
        return cell;
    }
    return nil;
}

- (CGFloat)messageViewController:(EaseMessageViewController *)viewController
           heightForMessageModel:(id<IMessageModel>)messageModel
                   withCellWidth:(CGFloat)cellWidth
{
    //样例为如果消息是文本消息使用用户自定义cell的高度
    if (messageModel.bodyType == EMMessageBodyTypeText) {
        //CustomMessageCell为用户自定义cell,继承了EaseBaseMessageCell
        return [CustomMessageCell cellHeightWithModel:messageModel];
    }
    return 0.f;
}

下面是效果图

效果图

选中消息的回调


/*!
 @method
 @brief 选中消息的回调
 @discussion 用户根据messageModel判断,是否自定义处理消息选中时间。返回YES为自定义处理,返回NO为默认处理
 @param viewController 当前消息视图
 @param messageModel 消息模型
 @result 是否采用自定义处理
 */
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
        didSelectMessageModel:(id<IMessageModel>)messageModel;
        
//选中消息回调的样例:
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
        didSelectMessageModel:(id<IMessageModel>)messageModel
{
    BOOL flag = NO;
    //样例为如果消息是文件消息用户自定义处理选中逻辑
    switch (messageModel.bodyType) {
        case EMMessageBodyTypeImage:
        case EMMessageBodyTypeLocation:
        case EMMessageBodyTypeVideo:
        case EMMessageBodyTypeVoice:
            break;
        case EMMessageBodyTypeFile:
        {
            flag = YES;
            NSLog(@"用户自定义实现");
        }
            break;
        default:
            break;
    }
    return flag;
}

用户选中头像的回调


/*!
 @method
 @brief 点击消息头像
 @discussion 获取用户点击头像回调
 @param viewController 当前消息视图
 @param messageModel 消息模型
 @result
 */
- (void)messageViewController:(EaseMessageViewController *)viewController
    didSelectAvatarMessageModel:(id<IMessageModel>)messageModel;
    
//获取用户点击头像回调的样例:
- (void)messageViewController:(EaseMessageViewController *)viewController
   didSelectAvatarMessageModel:(id<IMessageModel>)messageModel
{
    //UserProfileViewController用户自定义的个人信息视图
    //样例的逻辑是选中消息头像后,进入该消息发送者的个人信息
    UserProfileViewController *userprofile = [[UserProfileViewController alloc] initWithUsername:messageModel.message.from];
    [self.navigationController pushViewController:userprofile animated:YES];
}

录音按钮状态的回调


/*!
 @method
 @brief 底部录音功能按钮状态回调
 @discussion 获取底部录音功能按钮状态回调,根据EaseRecordViewType,用户自定义处理UI的逻辑
 @param viewController 当前消息视图
 @param recordView 录音视图
 @param type 录音按钮当前状态
 @result
 */
- (void)messageViewController:(EaseMessageViewController *)viewController
              didSelectRecordView:(UIView *)recordView
                withEvenType:(EaseRecordViewType)type;
                
//录音按钮状态的回调样例:
- (void)messageViewController:(EaseMessageViewController *)viewController
          didSelectRecordView:(UIView *)recordView
                 withEvenType:(EaseRecordViewType)type
{
    /*
        EaseRecordViewTypeTouchDown,//录音按钮按下
        EaseRecordViewTypeTouchUpInside,//手指在录音按钮内部时离开
        EaseRecordViewTypeTouchUpOutside,//手指在录音按钮外部时离开
        EaseRecordViewTypeDragInside,//手指移动到录音按钮内部
        EaseRecordViewTypeDragOutside,//手指移动到录音按钮外部
    */
    //根据type类型,用户自定义处理UI的逻辑
    switch (type) {
        case EaseRecordViewTypeTouchDown:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView  recordButtonTouchDown];
            }
        }
            break;
        case EaseRecordViewTypeTouchUpInside:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView recordButtonTouchUpInside];
            }
            [self.recordView removeFromSuperview];
        }
            break;
        case EaseRecordViewTypeTouchUpOutside:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView recordButtonTouchUpOutside];
            }
            [self.recordView removeFromSuperview];
        }
            break;
        case EaseRecordViewTypeDragInside:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView recordButtonDragInside];
            }
        }
            break;
        case EaseRecordViewTypeDragOutside:
        {
            if ([self.recordView isKindOfClass:[EaseRecordView class]]) {
                [(EaseRecordView *)self.recordView recordButtonDragOutside];
            }
        }
            break;
        default:
            break;
    }
}

EaseMessageViewControllerDataSource

用户判断消息是否允许长按,返回布尔值;如果用户允许长按,此方法为通知用户触发长按手势,返回布尔值,如果返回 NO 默认方式处理,返回 YES 采用用户自定义的处理方式。

/*!
 @method
 @brief 是否允许长按
 @discussion 获取是否允许长按的回调,默认是NO
 @param viewController 当前消息视图
 @param indexPath 长按消息对应的indexPath
 @result
 */
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
   canLongPressRowAtIndexPath:(NSIndexPath *)indexPath;

/*!
 @method
 @brief 触发长按手势
 @discussion 获取触发长按手势的回调,默认是NO
 @param viewController 当前消息视图
 @param indexPath 长按消息对应的indexPath
 @result
 */
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
   didLongPressRowAtIndexPath:(NSIndexPath *)indexPath;
   
//长按收拾回调样例:
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
   canLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
    //样例给出的逻辑是所有cell都允许长按
    return YES;
}

- (BOOL)messageViewController:(EaseMessageViewController *)viewController
   didLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
    //样例给出的逻辑是长按cell之后显示menu视图
    id object = [self.dataArray objectAtIndex:indexPath.row];
    if (![object isKindOfClass:[NSString class]]) {
        EaseMessageCell *cell = (EaseMessageCell *)[self.tableView cellForRowAtIndexPath:indexPath];
        [cell becomeFirstResponder];
        self.menuIndexPath = indexPath;
        [self _showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.model.bodyType];
    }
    return YES;
}

Demo3.0实现的消息长按效果演示:

长按效果展示

将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像。

/*!
 @method
 @brief 将EMMessage类型转换为符合<IMessageModel>协议的类型
 @discussion 将EMMessage类型转换为符合<IMessageModel>协议的类型,设置用户信息,消息显示用户昵称和头像
 @param viewController 当前消息视图
 @param EMMessage 聊天消息对象类型
 @result 返回<IMessageModel>协议的类型
 */
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
                           modelForMessage:(EMMessage *)message;
                           
//具体样例:
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
                           modelForMessage:(EMMessage *)message
{
    //用户可以根据自己的用户体系,根据message设置用户昵称和头像
    id<IMessageModel> model = nil;
    model = [[EaseMessageModel alloc] initWithMessage:message];
    model.avatarImage = [UIImage imageNamed:@"EaseUIResource.bundle/user"];//默认头像
    model.avatarURLPath = @"";//头像网络地址
    model.nickname = @"昵称";//用户昵称
    return model;
}

聊天会话页面头像和昵称的效果演示:

效果图

2. 聊天会话样式自定义

聊天样式的自定义需要在 EaseMessageViewController 中 viewDidload 结束前设置。
@property中带有UI_APPEARANCE_SELECTOR,都可以通过set的形式设置样式,具体可以参考EaseBaseMessageCell.h,EaseMessageCell.h

发送气泡图片设置

[[EaseBaseMessageCell appearance] setSendBubbleBackgroundImage:[[UIImage imageNamed:@"chat_sender_bg"] stretchableImageWithLeftCapWidth:5 topCapHeight:35]];//设置发送气泡

[[EaseBaseMessageCell appearance] setRecvBubbleBackgroundImage:[[UIImage imageNamed:@"chat_receiver_bg"] stretchableImageWithLeftCapWidth:35 topCapHeight:35]];//设置接收气泡

头像设置

[[EaseBaseMessageCell appearance] setAvatarSize:40.f];//设置头像大小

[[EaseBaseMessageCell appearance] setAvatarCornerRadius:20.f];//设置头像圆角

消息字体颜色设置

[[EaseMessageCell appearance] setMessageTextFont:[UIFont systemFontOfSize:15]];//消息显示字体

[[EaseMessageCell appearance] setMessageTextColor:[UIColor blackColor]];//消息显示颜色

[[EaseMessageCell appearance] setMessageLocationFont:[UIFont systemFontOfSize:12]];//位置消息显示字体

[[EaseMessageCell appearance] setMessageLocationColor:[UIColor whiteColor]];//位置消息显示颜色

语音消息图片样式设置

[[EaseBaseMessageCell appearance] setSendMessageVoiceAnimationImages:@[[UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_full"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_000"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_001"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_002"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_sender_audio_playing_003"]]];//发送者语音消息播放图片

[[EaseBaseMessageCell appearance] setRecvMessageVoiceAnimationImages:@[[UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing_full"],[UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing000"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing001"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing002"], [UIImage imageNamed:@"EaseUIResource.bundle/chat_receiver_audio_playing003"]]];//接收者语音消息播放图片

3. 聊天会话输入框自定义

继承EaseMessageViewController,或者EaseMessageViewController的实例调用以下方法设置底部输入框

CustomerInputView *inputView = [[CustomerInputView alloc] init];//CustomerInputView用户自定义底部输入框
[self setChatToolbar:inputView];

实现默认底部输入框delegate

@interface CustomerInputView : UIView

@property (weak, nonatomic) id<EMChatToolbarDelegate> delegate;

@end

自定义输入框发送消息

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text{
    if ([text isEqualToString:@"\n"]){
        if(self.delegate && [self.delegate respondsToSelector:@selector(didSendText:)]) {
            [self.delegate didSendText:self.textView.text];
        }
        self.textView.text = @"";
        self.placeholderLabel.text = @"说点什么吧...";
        return NO;
    }
    return YES;
}

自定义输入框高度变化


//这是一个举例,初始化输入框的时候注册监听键盘高度变化
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:)name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:)name:UIKeyboardWillHideNotification object:nil];

- (void)keyboardWillShow:(NSNotification *)aNotification{
    //获取键盘的高度
    NSValue *aValue = [[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
    CGRect keyboardRect = [aValue CGRectValue];
    if (keyboardRect.size.height > self.keyboardHeight) {
        self.keyboardHeight = keyboardRect.size.height;
    }
    self.frame = CGRectMake(0, _originY - self.keyboardHeight - 64, App_Width, self.inputH + self.keyboardHeight);
    if (self.delegate && [self.delegate respondsToSelector:@selector(chatToolbarDidChangeFrameToHeight:)]) {
        [self.delegate chatToolbarDidChangeFrameToHeight:self.frame.size.height];
    }
}

- (void)keyboardWillHide:(NSNotification *)aNotification{
    self.frame = CGRectMake(0, _originY - 64, App_Width, self.inputH) ;
    if (self.delegate && [self.delegate respondsToSelector:@selector(chatToolbarDidChangeFrameToHeight:)]) {
        [self.delegate chatToolbarDidChangeFrameToHeight:self.frame.size.height];
    }
}

4.聊天会话底部菜单自定义

EaseChatBarMoreView为自定义的功能菜单选择视图,目前已添加的功能有:

/*!
 @method
 @brief 新增一个新的功能按钮
 @discussion
 @param image 按钮图片
 @param highLightedImage 高亮图片
 @param title 按钮标题
 @result
 */
- (void)insertItemWithImage:(UIImage*)image
           highlightedImage:(UIImage*)highLightedImage
                      title:(NSString*)title;

/*!
 @method
 @brief 修改功能按钮图片
 @discussion
 @param image 按钮图片
 @param highLightedImage 高亮图片
 @param title 按钮标题
 @param index 按钮索引
 @result
 */
- (void)updateItemWithImage:(UIImage*)image
           highlightedImage:(UIImage*)highLightedImage
                      title:(NSString*)title
                    atIndex:(NSInteger)index;

/*!
 @method
 @brief 根据索引删除功能按钮
 @discussion
 @param index 按钮索引
 @result
 */
- (void)removeItematIndex:(NSInteger)index;

各个选项的功能需要ViewController实现EaseChatBarMoreViewDelegate协议中的回调方法来编写或调整.


八、消息发送

EaseSDKHelper 封装了发送消息的方法。

具体发送消息样例:


/*
 EMChatTypeChat            单聊消息
 EMChatTypeGroupChat       群聊消息
 EMChatTypeChatRoom        聊天室消息
*/

//发送文字消息
EMMessage *message = [EaseSDKHelper sendTextMessage:@"要发送的消息"
                                                 to:@"6001"//接收方
                                        messageType:EMChatTypeChat//消息类型
                                         messageExt:nil]; //扩展信息                                          
//发送位置消息
EMMessage *message = [EaseSDKHelper sendLocationMessageWithLatitude:35.1//经度
                                                          longitude:35.1//纬度
                                                            address:"地址"
                                                                 to:@"6001"//接收方
                                                        messageType:EMChatTypeChat//消息类型
                                                         messageExt:nil];//扩展信息                                         

//发送图片消息      
EMMessage *message = [EaseSDKHelper sendImageMessageWithImageData:imageData//发送的图片数据NSData
                                                               to:@"6001"//接收方
                                                      messageType:EMChatTypeChat//消息类型
                                                       messageExt:nil];//扩展信息                                                    

//发送音频消息                                           
EMMessage *message = [EaseSDKHelper sendVoiceMessageWithLocalPath:localPath//音频本地地址
                                                         duration:duration//语音的时长,单位是秒
                                                               to:@"6001"//接收方
                                                      messageType:EMChatTypeChat//消息类型
                                                       messageExt:nil];//扩展信息

//发送视频文件消息
EMMessage *message = [EaseSDKHelper sendVideoMessageWithURL:url//发送的视频地址
                                                         to:@"6001"//接收方
                                                messageType:EMChatTypeChat//消息类型
                                                 messageExt:nil];//扩展信息

//发送构造成功的消息                                                   
[[EMClient sharedClient].chatManager asyncSendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {

}];        


九、会话列表

1.会话列表初始化

EaseConversationListViewController *chatListVC = [[EaseConversationListViewController alloc] init];

2. 会话列表下拉刷新

需要继承EaseConversationListViewController的子类,在viewDidLoad中加入

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    self.showRefreshHeader = YES;
    //首次进入加载数据
    [self tableViewDidTriggerHeaderRefresh];
}

3.会话列表扩展

EaseConversationListViewControllerDataSource

用户根据 conversationModel 实现,实现自定义会话中最后一条消息文案的显示内容。

/*!
 @method
 @brief 获取最后一条消息显示的内容
 @discussion 用户根据conversationModel实现,实现自定义会话中最后一条消息文案的显示内容
 @param conversationListViewController 当前会话列表视图
 @param IConversationModel 会话模型
 @result 返回用户最后一条消息显示的内容
 */
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
      latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel;


/*!
 @method
 @brief 获取最后一条消息显示的时间
 @discussion 用户可以根据conversationModel,自定义实现会话列表中时间文案的显示内容
 @param conversationListViewController 当前会话列表视图
 @param IConversationModel 会话模型
 @result 返回用户最后一条消息时间的显示文案
 */
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
       latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel;
       
//最后一条消息展示内容样例    
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
      latestMessageTitleForConversationModel:(id<IConversationModel>)conversationModel
{
    NSString *latestMessageTitle = @"";
    EMMessage *lastMessage = [conversationModel.conversation latestMessage];
    if (lastMessage) {
        EMMessageBody *messageBody = lastMessage.body;
        switch (messageBody.type) {
            case EMMessageBodyTypeImage:{
                latestMessageTitle = NSLocalizedString(@"message.image1", @"[image]");
            } break;
            case EMMessageBodyTypeText:{
                // 表情映射。
                NSString *didReceiveText = [EaseConvertToCommonEmoticonsHelper
                                            convertToSystemEmoticons:((EMTextMessageBody *)messageBody).text];
                latestMessageTitle = didReceiveText;
                if ([lastMessage.ext objectForKey:MESSAGE_ATTR_IS_BIG_EXPRESSION]) {
                    latestMessageTitle = @"[动画表情]";
                }
            } break;
            case EMMessageBodyTypeVoice:{
                latestMessageTitle = NSLocalizedString(@"message.voice1", @"[voice]");
            } break;
            case EMMessageBodyTypeLocation: {
                latestMessageTitle = NSLocalizedString(@"message.location1", @"[location]");
            } break;
            case EMMessageBodyTypeVideo: {
                latestMessageTitle = NSLocalizedString(@"message.video1", @"[video]");
            } break;
            case EMMessageBodyTypeFile: {
                latestMessageTitle = NSLocalizedString(@"message.file1", @"[file]");
            } break;
            default: {
            } break;
        }
    }
    
    return latestMessageTitle;
}

//最后一条消息展示时间样例  
- (NSString *)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
       latestMessageTimeForConversationModel:(id<IConversationModel>)conversationModel
{
    NSString *latestMessageTime = @"";
    EMMessage *lastMessage = [conversationModel.conversation latestMessage];;
    if (lastMessage) {
        latestMessageTime = [NSDate formattedTimeFromTimeInterval:lastMessage.timestamp];
    }
    return latestMessageTime;
}

会话列表最后一条消息和时间显示的效果演示

效果图

EaseConversationListViewControllerDelegate

点击会话列表用户可以根据 conversationModel 自定义处理逻辑。

/*!
 @method
 @brief 获取点击会话列表的回调
 @discussion 获取点击会话列表的回调后,点击会话列表用户可以根据conversationModel自定义处理逻辑
 @param conversationListViewController 当前会话列表视图
 @param IConversationModel 会话模型
 @result
 */
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
            didSelectConversationModel:(id<IConversationModel>)conversationModel;
            
//会话列表点击的回调样例
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
            didSelectConversationModel:(id<IConversationModel>)conversationModel
{
    //样例展示为根据conversationModel,进入不同的会话ViewController
        if (conversationModel) {
        EMConversation *conversation = conversationModel.conversation;
        if (conversation) {
            if ([[RobotManager sharedInstance] isRobotWithUsername:conversation.conversationId]) {
                RobotChatViewController *chatController = [[RobotChatViewController alloc] initWithConversationChatter:conversation.conversationId conversationType:conversation.type];
                chatController.title = [[RobotManager sharedInstance] getRobotNickWithUsername:conversation.conversationId];
                [self.navigationController pushViewController:chatController animated:YES];
            } else {
                ChatViewController *chatController = [[ChatViewController alloc] initWithConversationChatter:conversation.conversationId conversationType:conversation.type];
                chatController.title = conversationModel.title;
                [self.navigationController pushViewController:chatController animated:YES];
            }
        }
        [[NSNotificationCenter defaultCenter] postNotificationName:@"setupUnreadMessageCount" object:nil];
        [self.tableView reloadData];
    }
}


十、联系人列表

1.联系人列表初始化

EaseUsersListViewController *listViewController = [[EaseUsersListViewController alloc] init];

2.联系人列表下拉刷新

需要继承EaseUsersListViewController的子类,在viewDidLoad中加入

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // Do any additional setup after loading the view.
    self.showRefreshHeader = YES;
}

3.联系人列表扩展

需要实现 EMUserListViewControllerDataSource。

根据 buddy 获取用户自定信息,联系人列表里展示昵称和头像。

/*!
 @method
 @brief 获取用户模型
 @discussion 根据buddy获取用户自定信息,联系人列表里展示昵称和头像
 @param userListViewController 当前联系人视图
 @param buddy 好友的信息描述类
 @result 返回用户模型
 */
- (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
                           modelForBuddy:(NSString *)buddy;
                           
//联系人列表扩展样例
- (id<IUserModel>)userListViewController:(EaseUsersListViewController *)userListViewController
                           modelForBuddy:(NSString *)buddy
{
    //用户可以根据自己的用户体系,根据buddy设置用户昵称和头像
    id<IUserModel> model = nil;
    model = [[EaseUserModel alloc] initWithBuddy:buddy];
    model.avatarURLPath = @"";//头像网络地址
    model.nickname = @"昵称";//用户昵称
    return model;
}

联系人列表头像和昵称的效果演示:

效果图

十一、EaseUI中使用的第三方库

  • MBProgressHUD
  • MJRefresh
  • MWPhotoBrowser
  • SDWebImage
  • DACircularProgressView

EaseUI中第三方库冲突问题

目前推荐Pod的方式集成EaseUI。如果集成了EaseUI,而且上述第三方依赖在开发者的代码中也有引用,会造成冲突,无法编译,针对此问题有如下两种场景:

  • 开发者使用的第三方依赖也是通过pod方式集成,这样pod只会安装一份,不会重复安装多个版本。如果是依赖版本不兼容,例如开发者依赖了'MBProgressHUD', '~> 1.0.0' ,而EaseUI通过MWPhotoBrowser间接依赖了'MBProgressHUD', '~> 0.9' ,这样会导致pod install失败,开发者可以改变MBProgressHUD的依赖版本。EaseUI也会在后续版本中尽量减少使用第三方依赖。

  • 如果是手动导入了上述第三方库,建议直接删除手动导入的部分,避免冲突的产生,如果EaseUI使用第三方库的版本不能满足开发者的需求,开发者也可以手动将第三方库进行重命名,保证兼容(手动方式集成EaseUI也可以参考此解决方案)。

后记

  关于环信3.0所有的基本理论差不多就这么多了,下一篇主要就是结合具体示例,完成基于环信3.0的及时通信。待续~~

风景图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,158评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,600评论 1 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,785评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,655评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,075评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,002评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,146评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,918评论 0 211
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,671评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,838评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,318评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,636评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,343评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,187评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,982评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,126评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,934评论 2 279

推荐阅读更多精彩内容