iOS:集成环信EaseMobSDK单聊功能

当然在集成环信之前需要一些准备操作:

1、首先注册环信开发者账号,直接进入环信官网注册即可:http://www.easemob.com

2、按照文档一步一步将需要的文件全部拖入工程中:http://docs.easemob.com/start/start

以下是我集成的文件:使用

  EaseUI集成:http://docs.easemob.com/start/300iosclientintegration/140easeuiuseguide

  libEaseMobClientSDK.a包

  ChatDemo-UI3.0中的ChatView中的聊天控制器

我主要使用EaseMob中这个EaseSDKHelper单例类来注册、登录、获取最新消息、推送等

在App启动程序时:

进入EaseSDKHelper单例类中,添加一些自定义的方法

#pragma mark - init easemob  注册环信

- (void)easemobApplication:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
                    appkey:(NSString *)appkey
              apnsCertName:(NSString *)apnsCertName
               otherConfig:(NSDictionary *)otherConfig
{
    //注册登录状态监听
//    [[NSNotificationCenter defaultCenter] addObserver:self
//                                             selector:@selector(loginStateChange:)
//                                                 name:KNOTIFICATION_LOGINCHANGE
//                                               object:nil];

    //注册AppDelegate默认回调监听
    [self _setupAppDelegateNotifications];

    //注册apns
    [self _registerRemoteNotification];

    //注册easemob sdk
    [[EaseMob sharedInstance] registerSDKWithAppKey:appkey
                                       apnsCertName:apnsCertName
                                        otherConfig:otherConfig];
    // 注册环信监听
    [self registerEaseMobLiteNotification];

    //启动easemob sdk
    [[EaseMob sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions];
    [[EaseMob sharedInstance].chatManager setIsAutoFetchBuddyList:YES];
}

#pragma mark - EMChatManagerLoginDelegate  自动登录代理回调

// 自动登录开始回调
-(void)willAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error
{
//    UIAlertView *alertView = nil;
    if (error) {
//        alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"prompt", @"Prompt") message:NSLocalizedString(@"login.errorAutoLogin", @"Automatic logon failure") delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil];

        //发送自动登陆状态通知
        [[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_LOGINCHANGE object:@NO];
    }
    else{
//        alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"prompt", @"Prompt") message:NSLocalizedString(@"login.beginAutoLogin", @"Start automatic login...") delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil];

        //将旧版的coredata数据导入新的数据库
        EMError *error = [[EaseMob sharedInstance].chatManager importDataToNewDatabase];
        if (!error) {
            [[EaseMob sharedInstance].chatManager loadDataFromDatabase];

            //获取数据
            [self loadConversations];
        }
    }
//    [alertView show];
}

// 自动登录结束回调
-(void)didAutoLoginWithInfo:(NSDictionary *)loginInfo error:(EMError *)error
{
//    UIAlertView *alertView = nil;
    if (error) {
//        alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"prompt", @"Prompt") message:NSLocalizedString(@"login.errorAutoLogin", @"Automatic logon failure") delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil];

        //发送自动登陆状态通知
        [[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_LOGINCHANGE object:@NO];
    }
    else{
        //获取群组列表
        [[EaseMob sharedInstance].chatManager asyncFetchMyGroupsList];

//        alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"prompt", @"Prompt") message:NSLocalizedString(@"login.endAutoLogin", @"End automatic login...") delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", @"OK") otherButtonTitles:nil, nil];
    }

//    [alertView show];
}

#pragma make - login easemob  用户登录

- (void)loginWithUsername:(NSString *)username
                 password:(NSString *)password
{
    [[EaseMob sharedInstance].chatManager asyncLoginWithUsername:username password:password completion:^(NSDictionary *loginInfo, EMError *error) {
        if (!error) {
            //设置自动登录
            [[EaseMob sharedInstance].chatManager setIsAutoLoginEnabled:YES];

            //获取数据
            [self loadConversations];

            //发送自动登陆状态通知
            [[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_LOGINCHANGE object:@YES];
        }
    } onQueue:nil];
}

#pragma mark - load conversations 加载会话列表
-(void)loadConversations{

//    [[EaseMob sharedInstance].chatManager importDataToNewDatabase];

    //获取数据库中数据
    [[EaseMob sharedInstance].chatManager loadDataFromDatabase];

    // 当前登录用户回话对象列表
    NSArray *conversations = [[EaseMob sharedInstance].chatManager conversations];
    if (conversations.count == 0) {
         //从数据库conversation表获取
        conversations = [[EaseMob sharedInstance].chatManager loadAllConversationsFromDatabaseWithAppend2Chat:YES];
    }
    _conversations = conversations;
}

在会话列表控制器中:

@interface KJAnswerQuestionController ()<UITableViewDataSource,UITableViewDelegate>
/** 所有会话 */
@property (strong,nonatomic)NSArray *arrConversations;
/** 提示视图 */
@property (strong,nonatomic)UIView *showingView;
@end

@implementation KJAnswerQuestionController

- (void)viewDidLoad {
    [super viewDidLoad];

     //创建tableView
    self.view.backgroundColor = HMColor(250, 250, 250);
    self.tableView = [[UITableView alloc]initWithFrame:self.view.bounds];
    self.tableView.dataSource =  self;
    self.tableView.delegate = self;
    self.tableView.tableFooterView = [[UIView alloc]initWithFrame:CGRectZero];
    [self.view addSubview:self.tableView];
    MoveUnderLine(self.tableView);

    //创建提示视图
    self.showingView = [UIView createViewWithShowingTitle:@"没有聊天记录哟!"];
    [self.view addSubview:self.showingView];

    //获取数据库中数据
    self.arrConversations = [EaseSDKHelper shareHelper].conversations;
    [self.tableView reloadData];

    //显示隐藏
    if (self.arrConversations.count == 0) {
        [self.showingView setHidden:NO];
        [self.tableView setHidden:YES];
    }else{
        [self.showingView setHidden:YES];
        [self.tableView setHidden:NO];
    }
}

//消息刷新
-(void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];

    NSArray *conversations = [[EaseMob sharedInstance].chatManager conversations];
    if (conversations == 0) {
        conversations = [[EaseMob sharedInstance].chatManager loadAllConversationsFromDatabaseWithAppend2Chat:YES];
    }
    if (conversations > self.arrConversations) {
        self.arrConversations = conversations;
    }
    [self.tableView reloadData];
}

#pragma Mark- 数据源方法
//返回行数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return self.arrConversations.count;
}

//返回cell
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    //取出单个会话
    KJContactCell *cell = [KJContactCell createCellWithTableView:tableView];
    EMConversation *conversation = [self.arrConversations objectAtIndex:indexPath.row];
    cell.conversation = conversation;
    return cell;
}

#pragma mark - 代理方法
//设置cell的高度
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 60;
}

//选中cell时的处理
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    //取出单个会话
    EMConversation *conversation = [self.arrConversations objectAtIndex:indexPath.row];
    KJChatViewController *chatVC = [[KJChatViewController alloc]initWithConversationChatter:conversation.chatter conversationType:eConversationTypeChat];
    chatVC.title = conversation.chatter;
    chatVC.conversation = conversation;
    chatVC.conversation.enableUnreadMessagesCountEvent = YES;
    [self.navigationController pushViewController:chatVC animated:YES];
}
@end

在聊天控制器中,直接集成ChatViewController

#import "ChatViewController.h"

@interface KJChatViewController : ChatViewController

@end

#import "KJChatViewController.h"

@interface KJChatViewController ()

@end

@implementation KJChatViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

//将未读消息标记为已读
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//    [self.conversation markMessageWithId:self.conversation.chatter asRead:YES];
    [self.conversation markAllMessagesAsRead:YES];
}

@end

在自定义的会话列表cell中,显示会话联系人、最后一条记录、时间

#import <UIKit/UIKit.h>

@class KJBadgeButton;
@interface KJContactCell : UITableViewCell
//创建cell
+(instancetype)createCellWithTableView:(UITableView *)tableView;
@property (strong,nonatomic)EMConversation *conversation;
@property (strong,nonatomic)KJBadgeButton *badgeBtn; //提示数字
@end

#import "KJContactCell.h"
#import "KJContact.h"
#import "KJBadgeButton.h"

#define cellBorder 10
#define iconWidth  40
#define textHeight 30

@interface KJContactCell()
@property (strong,nonatomic)UIImageView *iconView;   //头像
@property (strong,nonatomic)UILabel *MainTextLabel;  //姓名
@property (strong,nonatomic)UILabel *subTextLabel;   //消息
@end

@implementation KJContactCell

static NSString *reuseIdentifier = @"Cell";

+(instancetype)createCellWithTableView:(UITableView *)tableView{

    KJContactCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
    if (!cell) {
        cell = [[KJContactCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier];
    }
    cell.detailTextLabel.textColor = HMColor(153, 153, 153);
    cell.detailTextLabel.font = fontSize_13;
    return cell;
}

-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {

        //1.头像
        self.iconView = [[UIImageView alloc]init];
        [self.contentView addSubview:self.iconView];

        //2.提示badge
        self.badgeBtn = [[KJBadgeButton alloc]initWithFrame:CGRectMake(cellBorder+iconWidth-10, 5, 15, 15)];
        [self.contentView addSubview:self.badgeBtn];

        //3.姓名
        self.MainTextLabel = [[UILabel alloc]init];
        self.MainTextLabel.textColor = HMColor(51, 51, 51);
        self.MainTextLabel.font = fontSize_14;
        [self.contentView addSubview:self.MainTextLabel];

        //4.消息
        self.subTextLabel = [[UILabel alloc]init];
        self.subTextLabel.textColor = HMColor(153, 153, 153);
        self.subTextLabel.font = fontSize_13;
        [self.contentView addSubview:self.subTextLabel];
    }
    return self;
}

-(void)layoutSubviews{
    [super layoutSubviews];

    //1.头像
    self.iconView.frame = CGRectMake(cellBorder, cellBorder, iconWidth, iconWidth);

    //2.姓名
    self.MainTextLabel.frame = CGRectMake(CGRectGetMaxX(self.iconView.frame)+2*cellBorder, 2, 100, textHeight);

    //3.消息
    self.subTextLabel.frame  =CGRectMake(CGRectGetMaxX(self.iconView.frame)+2*cellBorder, CGRectGetMaxY(self.MainTextLabel.frame), SCREEN_WIDTH-CGRectGetMaxX(self.iconView.frame)-cellBorder, textHeight);
}

//接收联系人数据
-(void)setConversation:(EMConversation *)conversation{
    _conversation = conversation;

    //设置头像
    self.iconView.image = [UIImage imageNamed:@"head"];

    //设置姓名
    self.MainTextLabel.text = conversation.chatter;

    //设置提示数字
    [self.badgeBtn setBadgeValue:[NSString stringWithFormat:@"%ld",conversation.unreadMessagesCount]];

    //设置历史消息
    self.subTextLabel.text = [self latestMessageTitleForConversation:conversation];

    //设置历史消息时间
    self.detailTextLabel.text = [self latestMessageTimeForConversation:conversation];
}

#pragma mark - 最后一条消息展示内容
-(NSString *)latestMessageTitleForConversation:(EMConversation *)conversation
{
    //用户获取最后一条message,根据message的messageBodyType展示显示最后一条message对应的文案
    NSString *latestMessageTitle = @"";
    EMMessage *lastMessage = [conversation latestMessage];
    if (lastMessage) {
        id<IEMMessageBody> messageBody = lastMessage.messageBodies.lastObject;
        switch (messageBody.messageBodyType) {
            case eMessageBodyType_Image:{
                latestMessageTitle = NSLocalizedString(@"message.image1", @"[image]");
            } break;
            case eMessageBodyType_Text:{
                // 表情映射。
                NSString *didReceiveText = [EaseConvertToCommonEmoticonsHelper
                                            convertToSystemEmoticons:((EMTextMessageBody *)messageBody).text];
                latestMessageTitle = didReceiveText;
            } break;
            case eMessageBodyType_Voice:{
                latestMessageTitle = NSLocalizedString(@"message.voice1", @"[voice]");
            } break;
            case eMessageBodyType_Location: {
                latestMessageTitle = NSLocalizedString(@"message.location1", @"[location]");
            } break;
            case eMessageBodyType_Video: {
                latestMessageTitle = NSLocalizedString(@"message.video1", @"[video]");
            } break;
            case eMessageBodyType_File: {
                latestMessageTitle = NSLocalizedString(@"message.file1", @"[file]");
            } break;
            default: {
            } break;
        }
    }
    return latestMessageTitle;
}

#pragma mark - 最后一条消息展示时间
- (NSString *)latestMessageTimeForConversation:(EMConversation *)conversation
{
    //用户获取最后一条message,根据lastMessage中timestamp,自定义时间文案显示(例如:"1分钟前","14:20")
    NSString *latestMessageTime = @"";
    EMMessage *lastMessage = [conversation latestMessage];;
    if (lastMessage) {
        latestMessageTime = [NSDate formattedTimeFromTimeInterval:lastMessage.timestamp];
    }
    return latestMessageTime;
}
@end

消息提醒按钮

#import <UIKit/UIKit.h>

@interface KJBadgeButton : UIButton
@property (nonatomic, copy) NSString *badgeValue;
@end

#import "KJBadgeButton.h"

@implementation KJBadgeButton

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.hidden = YES;
        self.userInteractionEnabled = NO;
        [self setBackgroundImage:[UIImage resizedImageWithName:@"main_badge"] forState:UIControlStateNormal];
        self.titleLabel.font = [UIFont systemFontOfSize:11];
    }
    return self;
}

- (void)setBadgeValue:(NSString *)badgeValue
{
#warning copy
//    _badgeValue = badgeValue;
    _badgeValue = [badgeValue copy];

    if (badgeValue && [badgeValue intValue] != 0) {
        self.hidden = NO;
        // 设置文字
        [self setTitle:badgeValue forState:UIControlStateNormal];

        // 设置frame
        CGRect frame = self.frame;
        CGFloat badgeH = self.currentBackgroundImage.size.height;
        CGFloat badgeW = self.currentBackgroundImage.size.width;
        if (badgeValue.length > 1) {
            // 文字的尺寸
            CGSize badgeSize = [badgeValue sizeWithFont:self.titleLabel.font];
            badgeW = badgeSize.width + 10;
        }
        frame.size.width = badgeW;
        frame.size.height = badgeH;
        self.frame = frame;
    } else {
        self.hidden = YES;
    }
}

@end

最后在TabbarController中检测未读消息

 //注册代理,监听未读消息数
    [[EaseMob sharedInstance].chatManager addDelegate:self delegateQueue:nil];
#pragma mark - EMChatManagerChatDelegate
/**
 *  历史会话列表更新了会调用
 */
- (void)didUpdateConversationList:(NSArray *)conversationList
{
    // 给数据源重新赋值
    self.arrConversations = conversationList;

    //刷新表格
    [self.messageVc.tableView reloadData];

    // 显示总的未读数
    [self showTabBarBadge];
}

/**
 *  未读消息数改变了会调用
 */
- (void)didUnreadMessagesCountChanged
{
    //刷新表格
    [self.messageVc.tableView reloadData];

    // 显示总的未读数
    [self showTabBarBadge];
}

/**
 *  将总的未读消息数显示到tabBar上
 */
- (void)showTabBarBadge
{
    NSInteger totalUnreadCount = 0;
    for (EMConversation *conversation in self.arrConversations) {

        //获取所有的联系人发来的未读消息
        totalUnreadCount += [conversation unreadMessagesCount];

    }
    if (totalUnreadCount > 0) {
        self.messageVc.tabBarItem.badgeValue = [NSString stringWithFormat:@"%ld",totalUnreadCount];
        UIApplication *application = [UIApplication sharedApplication];
        [application setApplicationIconBadgeNumber:totalUnreadCount];
    }else{
        self.messageVc.tabBarItem.badgeValue = nil;
        UIApplication *application = [UIApplication sharedApplication];
        [application setApplicationIconBadgeNumber:0];
    }
}
-(void)dealloc{
    [[EaseMob sharedInstance].chatManager removeDelegate:self];
}

测试后:

 

时间: 2024-08-04 13:00:45

iOS:集成环信EaseMobSDK单聊功能的相关文章

[iOS]集成环信SDK然后运行时候crash了-[NSBundle initWithURL:]: nil URL argument&#39;

Crash的reason是-[NSBundle initWithURL:]: nil URL argument' 1.首先我是用cocoapods导入的环信的SDK.然后怎么运行怎么crash. 2.后来我就把cocoapods里的环信SDK拖到桌面,然后删除工程cocoapods里面的环信SDK,改成手动拖入,然后编译,运行,不crash了! 有错误还忘您指出,如果这篇文章帮助到您了,或者您有什么建议和补充,都可以留言告诉我哦! [iOS]集成环信SDK然后运行时候crash了-[NSBund

iOS集成环信推送,最详细流程(证书创建、环信集成)

这篇博客是我从我的CSDN上办过来的,排版有些混论,不知道为什么博客园不支持MarkDown编辑,想看原文排版的话传送门在这里http://blog.csdn.net/mumubumaopao/article/details/53423393 这几天项目里又用到了环信的推送,虽然之前做过,但是很久不做还是有很多细节没有注意到,所以还是决定从头开始做一遍,把每一个环节都详细记录下来,同样的把每一个坑也记录下来.方便自己以后做的时候忘记哪个流程了可以在看一遍.我很能理解那种遇到问题网上百度一堆类同的

iOS 集成环信(三)

部分转载于环信官网 集成SDK基础功能 这节文章主要介绍了环信初始化.注册和登陆等功能.因为环信demo确实做得比较好,但是功能太多,想从里面提取部分功能比较困难,所以写这篇文章记录下集成环信的过程. EaseUI使用指南 EaseUI封装了IM功能常用的控件(如聊天会话,会话列表,联系人列表),旨在帮助开发者快速集成环信SDK.EaseUI里面的代码都是开源的,我们如果有兴趣可以研究下EaseUI的代码,看下他们是怎么封装代码的. 快速集成 在我们从官方下载下载好的SDK中,有一个文件夹叫Ea

iOS 集成环信聊天界面

现在即时通讯好多都是用的环信, 但是有些项目并不需要环信所有的界面, 比如登录, 我们一般放到后台 现在是把环信的聊天界面集成到我们的项目 1. 新建项目, 把环信的依赖库以及SDK导入到项目中, 添加pch文件, 把项目的Other Linker Flags 改成 -ObjC 2. 把环信demo的几个文件导入项目: 3rdparty, Category, Custom, Resources, Class ->Chat -> ChatView, 还有它的define文件ChatDemoUID

iOS 集成环信(四)

本节主要仿照环信demo来创建demo的界面. 我们在使用环信的demo可以看到环信的整个界面框架是UITabBarController作为主控制器,里面装了会话ConversationListController.通讯录ContactListViewController和设置SettingsViewController这三个控制器.现在我们来创建这三个控制器. 创建ConversationListController 我们通过环信demo可以看到,ConversationListControl

李洪强iOS开发本人集成环信的经验总结_09_处理好友请求

李洪强iOS开发本人集成环信的经验总结_09_处理好友请求 实现这种效果: 01 - 遵守处理好友请求的代理协议 02  - 设置代理 03 - 实现代理方法 04 - 实现代理中用到的方法 

集成环信 - 基础设置

环信集成基础设置: http://v.youku.com/v_show/id_XMTMwMDQ5MDA0NA==.html?from=s1.8-1-2.999&f=23630826&sf=10202 other link flag: libraries 集成环信UI, 引入文件

集成环信时遇到的问题file not found: libEaseMobClientSDK.a

集成环信时遇到的问题 build setting环信SDK集成libEaseMobClientSDKL file not found: libEaseMobClientSDK.a clang: er 今天集成环信,说编译的时候不能找到.a文件.在模拟器上出现此错误,现将我出现错误的原因及解决方法晒出,希望能够帮助将来跟我一样遇到困难的人. 原因例如以下:在Build Settings下Linking 下的other Linker Flags中加入了-ObjC.-all_load或-force_l

Websocket 单聊功能

单聊代码 import json from flask import Flask,request,render_template from geventwebsocket.handler import WebSocketHandler from gevent.pywsgi import WSGIServer from geventwebsocket.websocket import WebSocket app = Flask(__name__) user_socket_dict = {} @ap