環信SDK 頭像、昵稱、表情自定義和群聊設置的實現 一(附源碼)


前言:

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM