去年曾为了项目的一个即时通信功能集成过环信,因为考虑开发的低成本,就直接使用了环信的 EaseUI
环信的文档提供了很多好友管理、群聊操作的API,但当你看到下图后,这些api直接可以无视掉
所以环信当作工具来使用即可,千万别用他的后台系统(我的公司安卓那边莫名的相信环信后台,白白浪费了近两个多星期)
因为环信的EaseUI,是根据环信自己后台开发的,所以需要让EaseUI更好地跟我们自己的后台关联起来
红色圈出来的就是我接下来所做的优化的内容
ps:一开始我以为,在拉取好友列表的时候判断好,就基本没有大碍!但是后面经测试,在聊天的过程中,如果对方把你删除,聊天依旧可以继续,所以就需要对 EaseUI 的源码开刀。
EaseUI 使用起来十分便捷,只需要自己创建一个继承于 EaseMessageViewController 的控制器即可
接着实现 EaseMessageViewControllerDataSource 该协议的
- (id)messageViewController:(EaseMessageViewController *)viewController
modelForMessage:(EMMessage *)message;
便可以对聊天内容的环信用户设置自定义头像和名字
接来下便开始修改他的源码:
打开 EaseUI 里面的 EaseMessageViewController.h 文件
在 EaseMessageViewControllerDelegate 下添加以下代码
/**
* 是否需要发送这条消息 return false 将会阻止该消息的发送 - pfboy add
*
* @param viewController _
* @param message 自己发送出去的消息
* @param block 对发出去的数据的,进行校验,通过block的参数isDataRight返回数据的正确性
*
*/
- (void) messageViewController:(EaseMessageViewController *)viewController willSendMessage:(EMMessage *)message resultBlock:(void(^)(BOOL isDataRight)) block;
/**
* 是否需要发送这条消息 return false 将会阻止该消息的发送 - pfboy add
*
* @param viewController _
* @param message 接收到的数据
* @param block 对接收到的数据,进行校验,通过block的参数isDataRight返回数据的正确性
*
*/
- (void) messageViewController:(EaseMessageViewController *)viewController willReceiveMessage:(EMMessage *)message resultBlock:(void(^)(BOOL isDataRight)) block;
这个是为了最后,我们可以在自己的 Controller 通过这两个方法,来判断发收信息的是否来自好友或者群聊
因为需要通过http请求来判断好友的真实性,所以使用block 进行控制
接着打开文件 EaseMessageViewController.m 并滑动到1721行
将原 _sendMessage 函数
- (void)_sendMessage:(EMMessage *)message
{
if (self.conversation.type == EMConversationTypeGroupChat){
message.chatType = EMChatTypeGroupChat;
}
else if (self.conversation.type == EMConversationTypeChatRoom){
message.chatType = EMChatTypeChatRoom;
}
[self addMessageToDataSource:message
progress:nil];
__weak typeof(self) weakself = self;
[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {
if (!aError) {
[weakself _refreshAfterSentMessage:aMessage];
}
else {
[weakself.tableView reloadData];
}
}];
}
改成以下代码
/判断该消息是否需要截断 pfboy add
- (void) _sendCorrectMessage:(EMMessage *)message{
__weak typeof(self) weakself = self;
[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {
if (!aError) {
[weakself _refreshAfterSentMessage:aMessage];
}
else {
[weakself.tableView reloadData];
}
}];
}
// hook 这个地址
- (void) _sendMessage:(EMMessage *)message
{
if (self.conversation.type == EMConversationTypeGroupChat){
message.chatType = EMChatTypeGroupChat;
}
else if (self.conversation.type == EMConversationTypeChatRoom){
message.chatType = EMChatTypeChatRoom;
}
[self addMessageToDataSource:message
progress:nil];
//判断该消息是否需要截断 pfboy add
if ([self.delegate respondsToSelector:@selector(messageViewController:willSendMessage:resultBlock:)]) {
__weak typeof(self) weakself = self;
[self.delegate messageViewController:self willSendMessage:message resultBlock:^(BOOL isDataRight) {
if (isDataRight) {
[weakself _sendCorrectMessage:message];
}
}];
} else {
// 如果没有实现该代理,则不会更改源码的流程
[self _sendCorrectMessage:message];
}
}
EaseMessageViewController.h 滑动到 1137 行将方法 statusButtonSelcted 替换成以下代码
- (void) _resendMessage:(id)model{
__weak typeof(self) weakself = self;
[[[EMClient sharedClient] chatManager] resendMessage:model.message progress:nil completion:^(EMMessage *message, EMError *error) {
if (!error) {
[weakself _refreshAfterSentMessage:message];
}
else {
[weakself.tableView reloadData];
}
}];
[self.tableView reloadData];
}
// hook 重发地址
- (void)statusButtonSelcted:(id)model withMessageCell:(EaseMessageCell*)messageCell
{
if ((model.messageStatus != EMMessageStatusFailed) && (model.messageStatus != EMMessageStatusPending))
{
return;
}
//判断该消息是否需要截断 pfboy add
if ([self.delegate respondsToSelector:@selector(messageViewController:willSendMessage:resultBlock:)]) {
__weak typeof(self) weakself = self;
[self.delegate messageViewController:self willSendMessage:model.message resultBlock:^(BOOL isDataRight) {
if (isDataRight) {
[weakself _resendMessage:model];
}
}];
} else {
// 如果没有实现该代理,则不会更改源码的流程
[self _resendMessage:model];
}
}
EaseMessageViewController.h 滑动到 1442 行,将 didReceiveMessages 替换成以下代码
- (void) _didReceiveMessages:(EMMessage *)message {
[self addMessageToDataSource:message progress:nil];
[self _sendHasReadResponseForMessages:@[message]
isRead:NO];
if ([self _shouldMarkMessageAsRead])
{
[self.conversation markMessageAsReadWithId:message.messageId error:nil];
}
}
// hook 这里
- (void)didReceiveMessages:(NSArray *)aMessages
{
for (EMMessage *message in aMessages) {
if ([self.conversation.conversationId isEqualToString:message.conversationId]) {
//判断该消息是否需要截断
if ([self.delegate respondsToSelector:@selector(messageViewController:willReceiveMessage:resultBlock:)]) {
__weak typeof(self) weakself = self;
[self.delegate messageViewController:self willReceiveMessage:message resultBlock:^(BOOL isDataRight) {
//判断是否需要接受该数据
if (isDataRight) {
[weakself _didReceiveMessages:message];
}
}];
} else {
// 如果没有实现该代理,则不会更改源码的流程
[self _didReceiveMessages:message];
}
}
}
}
通过以上四步,便可以在消息发送或接收前将消息截取下来,再通过protocol,返回到我们自己的控制器进行管理
最后在自己的 Controller 内,便可以将发送的消息与自己服务器的数据关联起来,实现对 EaseUI 的优化
// MARK: -EaseMessageViewControllerDelegate
func messageViewController(_ viewController: EaseMessageViewController!, willSend message: EMMessage!, resultBlock block: ((Bool) -> Void)!) {
checkAccountCorrect(hx_account: message.conversationId) { (value) in
block(value)
}
}
func messageViewController(_ viewController: EaseMessageViewController!, willReceive message: EMMessage!, resultBlock block: ((Bool) -> Void)!) {
checkAccountCorrect(hx_account: message.conversationId) { (value) in
block(value)
}
}
ps:方法 checkAccountCorrect 的内容主要与我们自己的服务器交互校验数据
本人能力有限,如果有什么更好的方法或者建议,欢迎指正