使用环信EaseUI,遇到的一些问题

环信的EaseUI里,实现了微信的消息,通讯录两大模块的UI,功能,可说老少兼宜,对比下两者的ui:

enter image description here

enter image description here

基本上集成来EaseUI就相当于集成了微信通讯功能,好友功能。具体集成,详见环信官网

Q1.环信好友关系维护

环信维护了一个好友体系,在时间比较紧促的情况下,我们可以使用环信的好友体系,但是,在时间比较充足的情况下,还是建议由我们自己服务器去维护好友体系,因为环信维护的好友体系,仅在需要控制消息发送权限时才启动,而且环信保存的只是环信id,没有头像,昵称这些信息

两者对比:

  • 环信好友体系,需要使用环信的id去访问自己的服务器,以便获取好友的基本信息(基本的头像,昵称….)
  • 自己服务器好友体系,获取好友的时候,直接访问服务器接口,不用访问环信服务器,比较方便

Q2.头像昵称

环信服务器保存的只是我们的环信id,不支持保存其它信息,我们也不会希望它保存着我们的其它信息,在环信的demo里面,其实已经使用了Parse来保存用户的头像昵称,主要代码在UserProfileManager这个类里面:

enter image description here

其中是以环信的id(username)作为key,将头像昵称保存到Parse,使用的时候从Parse读取,保存在本地的一个NSMutableDictionary中,需要展示的时候,通过环信id(username)来获取对应的信息,具体可以看下UserProfileManager.m的实现

不过我们还是使用我们自己服务器来保存这些信息,防止数据错乱,如果使用Parse,在更新自己服务器头像昵称的同时还需要更新Parse上的信息,而且Parse也快到期了,比较麻烦,所以我们可以参照UserProfileManager,自己实现好友头像昵称的本地缓存,在环信的论坛已经有人发表了相关的文章:iOS开发小记:关于环信Demo3.0的使用总结以及昵称和头像问题的研究与解决,以下是在这文章的基础上,自己增加了两个更新本地头像昵称的方法,目前这些信息是存储在NSUserDefaults

#define dUserDefaults_Dic_NickName  @"dUserDefaults_Dic_NickName"    
#define dUserDefaults_Dic_HeadImage @"dUserDefaults_Dic_HeadImage"    

@interface CacheData()   

@property (strong, nonatomic) NSMutableDictionary *NickNames;  
@property (strong, nonatomic) NSMutableDictionary *HeadImages;  
@property (nonatomic) BOOL LoadFromLocalDickDone;  

@end  

@implementation CacheData    

static CacheData* _instance = nil;    

+(instancetype) shareInstance
{
    static dispatch_once_t onceToken ;
    dispatch_once(&onceToken, ^{
        _instance = [[self alloc] init] ;
    }) ;

    return _instance ;
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        _DownloadHasDone = NO;
        _LoadFromLocalDickDone = NO;

        NSMutableDictionary *dic = [[NSUserDefaults standardUserDefaults] objectForKey:dUserDefaults_Dic_NickName];

        if (dic == nil || [dic count] == 0) {
            _NickNames = [NSMutableDictionary dictionary];
            _HeadImages= [NSMutableDictionary dictionary];
            _LoadFromLocalDickDone = YES;
        }
        else
        {
            _LoadFromLocalDickDone = YES;
            _NickNames = [NSMutableDictionary dictionaryWithDictionary:dic];
            _HeadImages= [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] objectForKey:dUserDefaults_Dic_HeadImage]];
        }


    }
    return self;
}

- (void)clearParse
{
    [_NickNames removeAllObjects];
    [_HeadImages removeAllObjects];

    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    [ud setObject:_NickNames forKey:dUserDefaults_Dic_NickName];
    [ud setObject:_HeadImages forKey:dUserDefaults_Dic_HeadImage];
    [ud synchronize];
}

- (void)loadUserProfileInBackgroundCompletion:(void (^)())completion
{
    _DownloadHasDone = NO;

    GetUserFriendParam *param = [GetUserFriendParam new];
    param.SNSID = userId;

    [[[FriendCircle_GetUserFriend_BLController alloc] initWithParam:param] startWithCompletionBlockWithSuccess:^(ZQBLBaseController *blController) {

        _LoadFromLocalDickDone = NO;

        if ([blController.responseObject isKindOfClass:[NSArray class]]) {
            NSArray *arr = (NSArray *)blController.responseObject;

            for (GetUserFriendModel *model in arr) {
                [_NickNames setObject:model.NickName forKey:[NSString stringWithFormat:@"%@",model.userId]];
                [_HeadImages setObject:model.FaceImg forKey:[NSString stringWithFormat:@"%@",model.userId]];
            }

            NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
            [ud setObject:_NickNames forKey:dUserDefaults_Dic_NickName];
            [ud setObject:_HeadImages forKey:dUserDefaults_Dic_HeadImage];
            [ud synchronize];
        }
        _LoadFromLocalDickDone = YES;

        _DownloadHasDone = YES;

        if (completion) {
            completion();
        }

    } failure:^(ZQBLBaseController *blController) {
        _DownloadHasDone = NO;
        if (completion) {
            completion();
        }
    }];
}

- (void)updateNicknameWithUsername:(NSString *)username nickname:(NSString *)nickname
{
    [_NickNames setObject:nickname forKey:[NSString stringWithFormat:@"%@",username]];
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    [ud setObject:_NickNames forKey:dUserDefaults_Dic_NickName];
    [ud synchronize];
}

- (void)updateHeadImageWithUsername:(NSString *)username headimage:(NSString *)headimage
{
    [_HeadImages setObject:headimage forKey:[NSString stringWithFormat:@"%@",username]];
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    [ud setObject:_HeadImages forKey:dUserDefaults_Dic_HeadImage];
    [ud synchronize];
}

- (NSString*)getNicknameByUserName:(NSString*)username
{
    if(_DownloadHasDone == YES)
    {
        NSString *string = [_NickNames objectForKey:username];
        if (string == nil || [string length] == 0) {
            return username;
        }
        return string;
    }

    else if(_LoadFromLocalDickDone == YES)
    {
        NSMutableDictionary *dic = [[NSUserDefaults standardUserDefaults] objectForKey:dUserDefaults_Dic_NickName];
        NSString *string = [dic objectForKey:username];
        if (string == nil || [string length] == 0) {
            return username;
        }
        return string;
    }
    return username;
}

- (NSString*)getHeadImageUrlByUserName:(NSString*)username
{
    if(_DownloadHasDone == YES)
    {
        NSString *string = [_HeadImages objectForKey:username];
        if (string == nil || [string length] == 0) {
            return @"";
        }
        return string;
    }

    else if(_LoadFromLocalDickDone == YES)
    {
        NSMutableDictionary *dic = [[NSUserDefaults standardUserDefaults] objectForKey:dUserDefaults_Dic_HeadImage];
        NSString *string = [dic objectForKey:username];
        if (string == nil || [string length] == 0) {
            return @"";
        }
        return string;
    }
    return @"";
}

@end

在app刚运行的时候,调用loadUserProfileInBackgroundCompletion加载并缓存好友头像的url以及好友昵称,然后将环信demo中的UserProfileEntitygetUserProfileByUsername换成CacheDatagetNicknameByUserName,如下面的聊天会话列表:

enter image description here

我们当前的项目,群聊都是使用默认头像,所以当聊天会话类型为单聊(EMConversationTypeChat)时才去加载头像昵称。

替换了所有的UserProfileEntity为我们自己的CacheData,基本可以在单聊会话中准确的显示昵称和头像,但是,当我们查看某个人的个人资料时,最好将获取到的最新资料对本地缓存进行更新,以保证数据统一,调用updateHeadImageWithUsernameupdateNicknameWithUsername即可更新本地缓存

下面看看关于在群聊聊天界面,我们如何展示昵称和头像:

enter image description here

enter image description here

是通过扩展消息去获取的,但是这有一个缺点,就是当对方更改了昵称或者头像的时候,之前的聊天记录的头像或者昵称还是旧的,并不会改变,由于项目比较赶,只能跟随着安卓端通过扩展消息去获取了,这个待到后面有时间必须优化

Q3.自动加入公开群后,提示XXX邀请你加入群组

//SDK自动同意了用户A的加B入群邀请后,用户B接收到该回调
- (void)didJoinedGroup:(EMGroup *)aGroup
               inviter:(NSString *)aInviter
               message:(NSString *)aMessage
{
//1
[self convertToNicknameWithUsrname:[NSString stringWithFormat:@"%@",aInviter] finish:^(NSString *nickname,NSString *imgUrl) {

    //发送的消息体
    NSString *willSendText = [EaseConvertToCommonEmoticonsHelper convertToCommonEmoticons:[NSString stringWithFormat:@"%@ 邀请你加入群组: %@",nickname,aGroup.subject]];
    EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:willSendText];

    //发送人
    NSString *from = aInviter;//[[EMClient sharedClient] currentUsername];

    //头像昵称
    NSMutableDictionary *ext = [[NSMutableDictionary alloc] init];
    [ext setValue:nickname forKey:@"group_nick_name"];
    [ext setValue:imgUrl forKey:@"avatar"];

    EMMessage *message = [[EMMessage alloc] initWithConversationID:aGroup.groupId from:from to:aGroup.groupId body:body ext:ext];
    message.chatType = EMChatTypeGroupChat;
    message.direction = EMMessageDirectionReceive;

    EMConversation *conversation = [[EMClient sharedClient].chatManager getConversation:aGroup.groupId type:EMConversationTypeGroupChat createIfNotExist:YES];
    [conversation insertMessage:message];

    [[ChatDemoHelper shareHelper].conversationListVC tableViewDidTriggerHeaderRefresh];

}];
}

convertToNicknameWithUsrname是通过环信id去获取用户的昵称

Q4.使用po查看一些变量时use of undeclared identifier ‘XX’

How to debug member variable (ie., Array, Dictionary) in LLDB?