我是直接用的 环信的EaseUI的 UI, 关于导入就不多言了,添加了官网让添加的第三方库
然后运行没有报错
下面开始接入
1.注册和通知
在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 方法中添加
//注册环信
EMOptions *options = [EMOptions optionsWithAppkey:@"app 的 key"];
options.apnsCertName = @"上传的推送证书的名字";
[[EMClient sharedClient] initializeSDKWithOptions:options];
options.enableDeliveryAck = YES;
//添加监听在线推送消息
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
(注:要让 AppDelegate遵循EMChatManagerDelegate协议)
注:环信的通知只有在完全杀死 app 的情况下才会推送 如果只是app 在后台 是不会发推送通知的 所以要监听在线推送消息来发本地推送
下面来实现监听在线推送消息的方法
//监听环信在线推送消息
- (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;
UIApplicationState state = [UIApplication sharedApplication].applicationState;
//判断 app 是不是在后台
if (state == UIApplicationStateBackground) {
UILocalNotification *localNote = [[UILocalNotification alloc] init];
//设置通知发出的时间
localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.0];
//设置通知的内容
localNote.alertBody = txt;
//设置锁屏界面的文字
localNote.alertAction = txt;
//设置锁屏界面alertAction是否有效
localNote.hasAction = YES;
//设置应用程序图标右上角的数字
localNote.applicationIconBadgeNumber = 1;
// 调度通知
[[UIApplication sharedApplication] scheduleLocalNotification:localNote];
} else {
// 如果是在前台,这里可以选择增加角标或者其他提示
}
}
break;
case EMMessageBodyTypeImage: {
// 得到一个图片消息body
EMImageMessageBody *body = ((EMImageMessageBody *)msgBody);
UIApplicationState state = [UIApplication sharedApplication].applicationState;
if (state == UIApplicationStateBackground) {
UILocalNotification *localNote = [[UILocalNotification alloc] init];
//设置通知发出的时间
localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.0];
//设置通知的内容
localNote.alertBody = @"收到一张图片";
//设置锁屏界面的文字
localNote.alertAction = @"收到一张图片";
//设置锁屏界面alertAction是否有效
localNote.hasAction = YES;
//设置应用程序图标右上角的数字
localNote.applicationIconBadgeNumber = 1;
//调度通知
[[UIApplication sharedApplication] scheduleLocalNotification:localNote];
}
}
break;
case EMMessageBodyTypeLocation: {
EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody;
NSLog(@"纬度-- %f",body.latitude);
NSLog(@"经度-- %f",body.longitude);
NSLog(@"地址-- %@",body.address);
UIApplicationState state = [UIApplication sharedApplication].applicationState;
if (state == UIApplicationStateBackground) {
UILocalNotification *localNote = [[UILocalNotification alloc] init];
//设置通知发出的时间
localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.0];
//设置通知的内容
localNote.alertBody = @"收到一条消息";
//设置锁屏界面的文字
localNote.alertAction = @"收到一条消息";
//设置锁屏界面alertAction是否有效
localNote.hasAction = YES;
//设置应用程序图标右上角的数字
localNote.applicationIconBadgeNumber = 1;
// 调度通知
[[UIApplication sharedApplication] scheduleLocalNotification:localNote];
}
}
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(@"音频文件的下载状态 -- %u" ,body.downloadStatus);
NSLog(@"音频的时间长度 -- %u" ,body.duration);
UIApplicationState state = [UIApplication sharedApplication].applicationState;
if (state == UIApplicationStateBackground) {
UILocalNotification *localNote = [[UILocalNotification alloc] init];
//设置通知发出的时间
localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.0];
//设置通知的内容
localNote.alertBody = @"收到一条消息";
//设置锁屏界面的文字
localNote.alertAction = @"收到一条消息";
//设置锁屏界面alertAction是否有效
localNote.hasAction = YES;
//设置应用程序图标右上角的数字
localNote.applicationIconBadgeNumber = 1;
//调度通知
[[UIApplication sharedApplication] scheduleLocalNotification:localNote];
}
}
break;
case EMMessageBodyTypeVideo: {
//视频消息
EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody;
}
break;
case EMMessageBodyTypeFile: {
// 文件消息
EMFileMessageBody *body = (EMFileMessageBody *)msgBody;
}
break;
default:
break;
}
}
}
这里因为我是没有用到视频和文件的功能,所以这里收到之后并没有做处理
//当程序关闭后 通过点击推送弹出的通知
// iOS 10 支持的方法
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
//在这个方法中实现点击消息进入 app 之后的方法
//我这里是写了一个通知 让 app 进入消息列表界面
[[NSNotificationCenter defaultCenter] postNotificationName:@"jumpToChatListView" object:nil];
}
这里需要注意一点 导出 p12证书上传到环信的时候一定要设置密码 上传的时候的包名要写 app 的 boundleID 要不然接收不到通知
2.开始聊天
我这里做的是每次开始聊天都要登陆一下 ,也可以选择在用户登陆 app 的时候 或者在 appdelegate 里面登陆
EMError *error = [[EMClient sharedClient] loginWithUsername:@"用户名" password:@"密码"]; if (!error) {//我在这里做了一个只要和他说话就添加他为好友 这样在后面获取好友列表的时候就有好友啦 MYFMRequestBean* bean = [MyHttpRequest addFriendWithUserId:对方 id currntUserId:自己的 id]; [bean connect:nil success:^(id responseObject) { } failure:^(NSError *error) { }];
//这里自定义了一个聊天页面 继承于EaseMessageViewController 定义了两个属性 一个是 talkImg 是对方的头像 一个是 talkName 对方的名字 这个从当前页面就能获取到
ChatViewController *chatController = [[ChatViewController alloc] initWithConversationChatter:对方的环信 idconversationType:EMConversationTypeChat]; chatController.talkImg = 对方的头像的 url 地址; chatController.talkName = 对方的名字; chatController.hidesBottomBarWhenPushed=YES;//跳转时隐藏 tabbar [self.navigationController pushViewController:chatController animated:YES]; } else { [SVProgressHUD showErrorWithStatus:@"连接失败,请稍后重试"]; }
3.聊天页面
自定义了一个ChatViewController
.h 文件就是
@interface ChatViewController : EaseMessageViewController @property (nonatomic, copy)NSString *talkName; @property (nonatomic, copy)NSString *talkImg; @end
.m 文件:
//遵循EaseMessageViewController的 DataSource 协议
@interface ChatViewController ()<EaseMessageViewControllerDataSource>
@end
@implementation ChatViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSource = self;
[self.navigationItem setTitle:self.talkName];
}
//这里实现EaseMessageViewController的 DataSource 方法 来改变对方和自己的昵称和头像
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
modelForMessage:(EMMessage *)message
{
//用户可以根据自己的用户体系,根据message设置用户昵称和头像
id<IMessageModel> model = nil;
//EaseMessageModel是环信EaseUI提供的model
model = [[EaseMessageModel alloc] initWithMessage:message];
//分两种情况 一种是当为当前用户的时候
if ([model.nickname isEqualToString:[EMClient sharedClient].currentUsername]) {
//默认图
// model.avatarImage = [UIImage imageNamed:@"baseInfo"];
//网络图
model.avatarURLPath = [UserManager userImg];
model.nickname = [UserManager userName];
} else {//当为对方的时候
model.avatarURLPath = _talkImg;//网络图
// model.avatarImage = [UIImage imageNamed:@"baseInfo"];//默认图
model.nickname = _talkName;//用户昵称
}
return model;
}
4.消息列表
自定义了一个ChatListViewController 继承于环信的EaseConversationListViewController
.h文件:
@interface ChatListViewController : EaseConversationListViewController
-(void)reloadData;//这里我加了一个刷新方法 如果单击消息进入 app 的时候是在当前页面 要刷新一下,默认是不会刷新的,即使在 viewWillAppear 里面写了也不刷新
@end
.m文件:
#import "ChatListViewController.h"
#import "HPChatListDataModel.h"
#import "NSDate+Category.h"//环信时间分类
#import "ChatViewController.h"
#import "ChatListDataModel.h"//这是自定义的一个 model 类 存放好友的头像昵称和 id
#import "EaseUsersListViewController.h"
@interface ChatListViewController ()<EaseConversationListViewControllerDataSource,EaseConversationListViewControllerDelegate>
@property (nonatomic, strong)NSMutableArray *imageAndNameArray;
@end
@implementation ChatListViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self sendFriendsList];
self.dataSource = self;
self.delegate = self;
[self.navigationItem setTitle:@"聊天列表"];
//打开下来刷新
self.showRefreshHeader = YES;
[self tableViewDidTriggerHeaderRefresh];
}
#pragma mark - 好友列表
- (void)sendFriendsList {
[SVProgressHUD showWithStatus:@"加载中..."];
MYFMRequestBean* bean = [MyHttpRequest friendsListWithUserId:[UserManager userId]];
self.imageAndNameArray = [NSMutableArray array];
__weak typeof(self) weakSelf = self;
[bean connect:nil success:^(id responseObject) {
[SVProgressHUD dismiss];
NSDictionary* dic = responseObject;
if ([dic optIntKey:@"status"] == 1) {
NSArray* arr = dic[@"data"];
for (NSDictionary* dict in arr) {
HPChatListDataModel *model = [[HPChatListDataModel alloc]initWithDictionary:dict];
[weakSelf.imageAndNameArray addObject:model];
}
[self tableViewDidTriggerHeaderRefresh];
} else {
[SVProgressHUD showErrorWithStatus:[dic optStringKey:@"msg"]];
}
} failure:^(NSError *error) {
[SVProgressHUD showErrorWithStatus:@"网络错误"];
}];
}
- (id<IConversationModel>)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
modelForConversation:(EMConversation *)conversation{
//用环信提供的model就可以了
EaseConversationModel *model = [[EaseConversationModel alloc] initWithConversation:conversation];
//然后根据用户名 往上面赋值
//self.imageAndNameArray为自定义的数组,其中存储的是从自己服务器上请求下来的数据
//数据包括,昵称,头像
for (HPChatListDataModel *dataModel in self.imageAndNameArray) {
if ([dataModel.mobile isEqualToString:model.conversation.conversationId]) {//根据用户名对应起来
model.avatarURLPath = dataModel.pic;//头像的网络图片
model.title = dataModel.name;//昵称
}
}
return model;
}
//下拉刷新
- (void)tableViewDidTriggerHeaderRefresh{
//super必须要有 要不会有问题
[super tableViewDidTriggerHeaderRefresh];
}
#pragma mark delegate
- (void)conversationListViewController:(EaseConversationListViewController *)conversationListViewController
didSelectConversationModel:(id<IConversationModel>)conversationModel{
EaseConversationModel *model = (EaseConversationModel *)conversationModel;
//自定义点击cell推出的viewcontroller
ChatViewController *viewController = [[ChatViewController alloc]initWithConversationChatter:model.conversation.conversationId conversationType:(EMConversationTypeChat)];
viewController.talkImg = model.avatarURLPath;
viewController.talkName = model.title;
[self.navigationController pushViewController:viewController animated:YES];
}
- (void)viewWillAppear:(BOOL)animated {
[self tableViewDidTriggerHeaderRefresh];
}
- (void)reloadData {
[self tableViewDidTriggerHeaderRefresh];
}
5. 获取未读消息数量 用来然后显示小红点
NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
NSInteger unreadCount = 0;
for (EMConversation *converstaion in conversations) {
unreadCount += converstaion.unreadMessagesCount;
}
用 forin 的方式来获取数量
6.单击聊天的头像然后显示个人信息的功能
让ChatViewController 遵循EaseMessageCellDelegate
然后别忘了 self.delegate = self;
然后实现代理方法
- (void)messageViewController:(EaseMessageViewController *)viewController
didSelectAvatarMessageModel:(id<IMessageModel>)messageModel {
//判断 model 的 nickname 是不是本人的 name 这里因为上面修改昵称的时候把这个 nickname 从 id 改成 name 了 所以这里判断的时候要用 name 来判断 不能用 id 了
if ([messageModel.nickname isEqualToString:@"本人名字"]) {
//跳转到个人信息
} else {
//跳转到对方信息
}
}