前言:
環信的SDK在公司的項目中有用到,現在用到的是群聊的部分,這里我們分析總結一下自己對環信給的DEMO大概的拆解一下,說說我們怎么樣充分的利用這個demo來寫我們所需要的業務。這個也由於篇幅的原因,實在沒辦法寫成一篇博客,我們今天先說說它的一個文件解析昵稱頭像的實現。寫這篇博客環信也是更新到3.0版本了,我們就按照3.0的版本分析一下,先看看這整個Demo的大概的文件;

剛開始,使用這個Demo的時候,有些人不知道自己需要的到底是什么文件,一個勁的恨不得連整個Demo全都拉進來,建議大家千萬不要這樣子做,你花點時間好好研究一些,看一下整個Demo有哪些你是用的着的,有哪些你是用不着的,找有用的拉進自己的項目中!給大家看看我覺得你用的着的一下文件,先看這整個大文件夾EaseUI,環信的文件我用到的全都在這里了。

我自己拉到項目中的就這么多,當然這個也因需求有個具體的不同,說兩個地方:
一: 關於3rdparty這個文件,這里面是第三方的文件,有些事環信二次封裝的,你一定要看清楚,已經在你項目中的,建議不要再拉進來!!環信封裝的一些,比如圖片瀏覽三方這些,你要自己項目中已經存在這樣功能的第三方就不要再重復拉進來。保持整個項目代碼的整潔,避免混亂和一些不懂也沒用的代碼出現,給以后造成困難!
二:Resources這個文件,這里面的圖片我幾乎是已經刪除干凈了,我們自己項目中的UI肯定是要自己重新寫的,不能直接連圖片就不改動的用環信的Demo,建議這里這樣做,等你們的設計師做好相應的UI切圖之后,你拿到圖片再找環信對應的是那張,全局搜索這張圖片的名字,找到位置,看清楚了再把自己的UI切圖名稱換上去!
三:說說環信SDK,因為自己的項目中還是有網易雲直播SDK和支付寶微信的SDK,比較的多,這時候你一定要注意靜態文件!避免這里面出現沖突!其實只要仔細點,集成環信這一步我相信大部分人都沒啥問題,集成這個也不是我們今天說的重點,我們把重點放在功能解析Demo上面!
重點是這兩個文件:Class 和 EaseUI
恩,是的,重點就是這個文件,重點都在這個文件夾當中,我們先看看Class這個文件夾當中的內容:

說這么幾點,先看到這里的話,我的給大家說一下,
一:這里的三個文件CoreData文件就是本地化的一些存儲,ChatGroup是關於群聊的一些文件,剩下的幾乎都在Chat這個文件夾當中了。
二:APPDelegate的幾個類別,寫的還是不錯的,這說的不是說代碼多精簡,看着這里我也真的是學習到了,以后這樣的話我們的支付,聊天,推送等等都可以一個功能一個功能的區分開了,簡單,明了!!看看下面我們項目中的真實按照這思路寫的,希望大家看了都可以學到思路,具體怎么寫的,你可以看看Demo里面的代碼,有問題也可以來找我!我盡我所能!

在說說這個 EaseUI,這么說吧,只要和界面相關的東西都在這個文件夾里面!!EaseUI這里面最重要的是ViewController這個文件夾了:
箭頭標注出來的地方,大家注意這個繼承關系!
仔細說說下面的功能:
一:頭像和昵稱
給大家看看下面的效果圖,這是自己我們項目中的界面截圖:

好,我們說說這個昵稱和頭像,官方有給出這兩個方法來處理頭像;
方法一 從APP服務器獲取昵稱和頭像
-
昵稱和頭像的獲取:當收到一條消息(群消息)時,得到發送者的用戶ID,然后查找手機本地數據庫是否有此用戶ID的昵稱和頭像,如沒有則調用APP服務器接口通過用戶ID查詢出昵稱和頭像,然后保存到本地數據庫和緩存,下次此用戶發來信息即可直接查詢緩存或者本地數據庫,不需要再次向APP服務器發起請求
-
昵稱和頭像的更新:當點擊發送者頭像時加載用戶詳情時從APP服務器查詢此用戶的具體信息然后更新本地數據庫和緩存。當用戶自己更新昵稱或頭像時,也可以發送一條透傳消息到其他用戶和用戶所在的群,來更新該用戶的昵稱和頭像。
方法二 從消息擴展中獲取昵稱和頭像
-
昵稱和頭像的獲取:把用戶基本的昵稱和頭像的URL放到消息的擴展中,通過消息傳遞給接收方,當收到一條消息時,則能通過消息的擴展得到發送者的昵稱和頭像URL,然后保存到本地數據庫和緩存。當顯示昵稱和頭像時,請從本地或者緩存中讀取,不要直接從消息中把賦值拿給界面(否則當用戶昵稱改變后,同一個人會顯示不同的昵稱)。
-
昵稱和頭像的更新:當擴展消息中的昵稱和頭像URI與當前本地數據庫和緩存中的相應數據不同的時候,需要把新的昵稱保存到本地數據庫和緩存,並下載新的頭像並保存到本地數據庫和緩存。
這里項目采用的是方法二,通過擴展消息來添加頭像和昵稱:我們一句一句的實現上面的話,先實現這一條:當收到一條消息時,則能通過消息的擴展得到發送者的昵稱和頭像URL,然后保存到本地數據庫和緩存。
下面的兩個文件是通過FMDB緩存的,通過CoreData肯定也是沒有問題的,下面是緩存文件的源碼文件ChatUserDataManagerHelper.h
#import <Foundation/Foundation.h> #import "UserInfoModel.h" #import "FMDB.h" @interface ChatUserDataManagerHelper : NSObject /** 保存用戶數據,登錄創建Model保存 @param userinfoDic 用戶數據字典 */ +(void)saveUserInfoModel:(UserInfoModel*)userInfo; /** 保存用戶數據,收到消息的擴展是字典類型,用這個方法直接保存。 @param userinfoDic 用戶數據字典 */ +(void)saveUserInfoDictionary:(NSDictionary *)userinfoDic; /** 根據一個userID 查詢一個用戶數據 @param userid 用戶id @return UserInfoModel 返回一個用戶Model */ +(UserInfoModel *)queryByuserEaseMobId:(NSString *)userid; @end
還有就是ChatUserDataManagerHelper.m文件了:
#import "ChatUserDataManagerHelper.h"
#define DBNAME @"cache_data.db"
@implementation ChatUserDataManagerHelper
/**
類方法創建一張表單
@param FMDBTable FMDBTable表
*/
+(void)createTable:(FMDatabase *)Database
{
// 打開
if ([Database open]) {
// 要是不存在UserInfo表單
if (![Database tableExists :@"userinfo"]) {
// 創建這張表單,參數(用戶ID,用戶名稱,用戶頭像)
if ([Database executeUpdate:@"create table userinfo (userid text, username text, userimage text)"]) {
// NSLog(@"create table success");
}else{
// NSLog(@"fail to create table");
}
}else {
// NSLog(@"table is already exist");
}
// 打開失敗
}else{
// NSLog(@"fail to open");
}
}
/**
從userinfo清除所有信息
@param FMDBTable FMDBTable表
*/
+ (void)clearTableData:(FMDatabase *)Database
{
if ([Database executeUpdate:@"DELETE FROM userinfo"]) {
//NSLog(@"clear successed");
}else{
// NSLog(@"fail to clear");
}
}
/**
獲取FMDatabase
@return FMDatabase
*/
+(FMDatabase*)getFMDB{
NSString * docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString * FMDBPath = [docsPath stringByAppendingPathComponent:DBNAME];
FMDatabase * Database = [FMDatabase databaseWithPath:FMDBPath];
[self createTable:Database];
return Database;
}
/**
保存用戶Model
@param userInfo userInfo description
*/
+(void)saveUserInfoModel:(UserInfoModel*)userInfo{
[ChatUserDataManagerHelper SaveUserInfoWithUserEaseMobId:userInfo.userEaseMobId andUserHeaderImageUrl:userInfo.userHeaderImageUrl andUserNickName:userInfo.usernickName];
}
/**
根據創建的用戶數據Model,保存用戶信息
@param easeMobId 用戶ID
@param imageUrl 用戶頭像
@param nickName 用戶昵稱
*/
+(void)SaveUserInfoWithUserEaseMobId:(NSString *)easeMobId andUserHeaderImageUrl:(NSString*)imageUrl andUserNickName:(NSString*)nickName{
NSMutableDictionary * userDic = [NSMutableDictionary dictionary];
[userDic setValue:easeMobId forKey:CHATUSERID];
[userDic setValue:imageUrl forKey:CHATUSRTHEADIMAGE];
[userDic setValue:nickName forKey:CHATUSERNICK];
[ChatUserDataManagerHelper saveUserInfoDictionary:userDic];
}
/**
保存用戶數據
@param userinfoDic 用戶數據字典
*/
+(void)saveUserInfoDictionary:(NSDictionary *)userinfoDic{
FMDatabase * dataBase = [self getFMDB];
NSString * userid = [userinfoDic objectForKey:CHATUSERID];
if ([dataBase executeUpdate:@"DELETE FROM userinfo where userid = ?", userid]) {
debugLog(@"刪除成功");
}else{
debugLog(@"刪除失敗");
}
NSString *username = [userinfoDic objectForKey:CHATUSERNICK];
NSString *userimage = [userinfoDic objectForKey:CHATUSRTHEADIMAGE];
if ([dataBase executeUpdate:@"INSERT INTO userinfo (userid, username, userimage) VALUES (?, ?, ?)", userid,username,userimage]) {
debugLog(@"插入成功");
}else{
debugLog(@"插入失敗");
}
// NSLog(@"%d: %@", [db lastErrorCode], [db lastErrorMessage]);
FMResultSet *rs = [dataBase executeQuery:@"SELECT userid, username, userimage FROM userinfo where userid = ?",userid];
if ([rs next]) {
NSString * userid = [rs stringForColumn:@"userid"];
NSString * username = [rs stringForColumn:@"username"];
NSString * userimage = [rs stringForColumn:@"userimage"];
debugLog(@"查詢一個 %@ %@ %@",userid,username,userimage);
}
rs = [dataBase executeQuery:@"SELECT userid, username, userimage FROM userinfo"];
while ([rs next]) {
NSString * userid = [rs stringForColumn:@"userid"];
NSString * username = [rs stringForColumn:@"username"];
NSString * userimage = [rs stringForColumn:@"userimage"];
debugLog(@"查詢所有 %@ %@ %@",userid,username,userimage);
}
[rs close];
// NSLog(@"%d: %@", [db lastErrorCode], [db lastErrorMessage]);
[dataBase close];
}
/**
根據一個userID 查詢一個用戶數據
@param userid 用戶id
@return UserInfoModel 返回一個用戶Model
*/
+(UserInfoModel *)queryByuserEaseMobId:(NSString *)userid {
FMDatabase * dataBase = [self getFMDB];
if ([dataBase open]) {
FMResultSet *rs = [dataBase executeQuery:@"SELECT userid, username, userimage FROM userinfo where userid = ?",userid];
if ([rs next]) {
UserInfoModel * userInfo = [[UserInfoModel alloc] init];
userInfo.userEaseMobId = [rs stringForColumn:@"userid"];
userInfo.usernickName = [rs stringForColumn:@"username"];
userInfo.userHeaderImageUrl = [rs stringForColumn:@"userimage"];
debugLog(@"查詢一個 %@",userInfo);
return userInfo;
}else{
return nil;
}
}else{
return nil;
}
}
@end
注意: 通過上面的代碼,你就實現了存儲的功能。不過你的記着,在登錄成功之后你得先把自己的信息存儲起來,在更改了個人資料之后,你要更新這里的存儲信息。
我們再說這個發送消息的時候,把自己的個人信息附加在擴展消息當中發送出去,這里我們就用發送文本消息為例子,其他的都一樣:
你找到EaseSDKHelper.m這個文件,這里面有這個方法
+(EMMessage *)sendTextMessage:(NSString *)text to:(NSString *)toUser messageType:(EMChatType)messageType messageExt:(NSDictionary *)messageExt
說說這里,這個你看看Demo的話你就可以看到,所有的信息發送都是EaseSDKHelper這個類發送的,由於這個EaseMessageViewController控制器已經代碼行數夠多了,就不要再在這里添加了,寫在EaseSDKHelper,在EaseMessageViewController中有下面這個方法,這個方法就是發送消息的
- (void)_sendMessage:(EMMessage *)message
看看EaseSDKHelper.m中我們怎樣添加擴展消息發送的,
#pragma mark - send message
+(EMMessage *)sendTextMessage:(NSString *)text
to:(NSString *)toUser
messageType:(EMChatType)messageType
messageExt:(NSDictionary *)messageExt{
NSMutableDictionary * extDictionary = nil;
// 這里要加判斷,因為群聊消息的擴展和直播聊天室的擴展會沖突
if (messageType == EMChatTypeGroupChat) {
//這是為了區分一下表情的擴展消息
if (!messageExt) {
extDictionary = [self reGetMessageExt];
}else{
//擴展消息字典
extDictionary = [[NSMutableDictionary alloc]initWithDictionary:messageExt];
[extDictionary addEntriesFromDictionary:[self reGetMessageExt]];
}
}
NSString *willSendText = [EaseConvertToCommonEmoticonsHelper convertToCommonEmoticons:text];
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:willSendText];
NSString *from = [[EMClient sharedClient] currentUsername];
EMMessage *message = [[EMMessage alloc] initWithConversationID:toUser from:from to:toUser body:body ext:extDictionary];
message.chatType = messageType;
return message;
}
// 獲取消息擴展,這里不要糾結,我這里只是去了一下自己本地存儲的個人信息,你把自己的取出來拼成一個字 // 典返回就可以了
+(NSMutableDictionary*)reGetMessageExt{
NSMutableDictionary *extDic = [NSMutableDictionary dictionary];
NSString * userId = [NSString stringWithFormat:@"%@",READUSERDEFAULTS(UserId)];
[extDic setValue:userId forKey:CHATUSERID];
[extDic setValue:READUSERDEFAULTS(UserName) forKey:CHATUSERNICK];
[extDic setValue:READUSERDEFAULTS(UserHeadImage) forKey:CHATUSRTHEADIMAGE];
return extDic;
}
最后就是接收到之后的賦值了,在這里進行ChatViewController.m中來寫,這里面又有一個方法
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController modelForMessage:(EMMessage *)message
看下面這個方法的完整代理:
#pragma mark - EaseMessageViewControllerDataSource
// 數據源方法
- (id<IMessageModel>)messageViewController:(EaseMessageViewController *)viewController
modelForMessage:(EMMessage *)message{
id<IMessageModel> model = nil;
// 根據聊天消息生成一個數據源Model
//NSLog(@"-======%@",message.from);
//debugObj(message.ext);
model = [[EaseMessageModel alloc] initWithMessage:message];
NSDictionary * messageDic = message.ext;
UserInfoModel * userinfoModel = [ChatUserDataManagerHelper queryByuserEaseMobId:messageDic[CHATUSERID]];
if (userinfoModel != nil) {
model.nickname = userinfoModel.usernickName;
model.avatarURLPath = userinfoModel.userHeaderImageUrl;
}
// 默認頭像
//model.avatarImage = [UIImage imageNamed:@"EaseUIResource.bundle/user"];
//Placeholder image for network error
//項目圖片取出錯誤的時候就用這張代替
model.failImageName = @"icon_Default-Avatar";
return model;
}
其實到這里頭像和昵稱差不多可以了,在具體的Cell中,你不需要給它再去賦值,因為這些Demo當中已經寫好了,你要一直寫到這里了,你可以試試效果了!剩下的部分內容明天發出來,不然篇幅有點過長了!
