前言:
環信的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當中已經寫好了,你要一直寫到這里了,你可以試試效果了!剩下的部分內容明天發出來,不然篇幅有點過長了!