Skip to content

V3.1.0

Latest
Compare
Choose a tag to compare
@huangminlinux huangminlinux released this 06 Apr 07:38
· 3 commits to master since this release

JChat 适配 SDK v3.1.0

一、SDK v3.1.0 主要变动

1. 消息同步功能

1.1 漫游消息
漫游消息不是必须的,开发者若需要APP实现漫游消息,需要在初始化SDK时调用新的初始化方法;
开启漫游:+ (void)setupJMessage:appKey:channel:apsForProduction:category:messageRoaming:
代理方法:- (void)onSyncRoamingMessageConversation:
1.2 离线消息
实现离线消息的代理方法,这个是必须的
代理方法:- (void)onSyncOfflineMessageConversation:offlineMessages:

2. 用户信息自动更新功能

这个功能是体现在,如果对方修改了用户信息(如:头像)之后,当对方再次发送消息时,SDK 内部会自动更新对方的用户信息;
这个更新不是立马就体现,网络慢时可能会要一小会;APP上层需要做的就是刷新一下就ok

3. 群组@功能

这个功能大家查看下相关API文档就应该知道用了,[文档链接](https://docs-test.jiguang.cn/jmessage/client/im_sdk_ios/)

4. 群消息屏蔽功能

这个功能大家查看下相关API文档就应该知道用了,[文档链接](https://docs-test.jiguang.cn/jmessage/client/im_sdk_ios/)

二、JChat 需要调整的地方

下面按 【启动 --> 会话列表界面 --> 聊天界面】 这个顺序进行相关调整说明。

1. SDK 启动 AppDelegate.m

1.1 设置漫游(非必须)
将 AppDelegate.m 里面初始化SDK的方法替换成新的

[JMessage setupJMessage:launchOptions
             appKey:@"用户的AppKey"
            channel:@"应用的渠道名称"
   apsForProduction:NO
           category:nil 
     messageRoaming:YES];
     
最后一个参数 isRoaming  是否启用消息漫游,默认关闭   

2. 会话列表界面

2.1 实现监听 <漫游消息> 代理方法
- (void)onSyncRoamingMessageConversation:(JMSGConversation *)conversation {
	// do something
	// 一般情况这个漫游消息代理,只有在切换设备登录时才会有
	// 当有某个会话有漫游消息时,会触发这个代理方法,UI 层需要根据自己逻辑去刷新会话列表
}
2.2 实现监听 <漫游消息> 代理方法
- (void)onSyncOfflineMessageConversation:(JMSGConversation *)conversation
                         offlineMessages:(NSArray<__kindof JMSGMessage *> *)offlineMessages { 
	// do something
	// 这个代理方法,一般是在有离线消息前提下,启动、从后台唤起、长连接断开又重连 这些情况下APP时会触发这个方法
	// 当某个会话有离线消息时,会触发这个代理方法,UI 层需要根据自己逻辑去刷新会话列表                    
}
2.3 关于UI层性能方面的建议

在会话列表这个界面,建议各位开发者不要每次监听到有消息下发、群组信息改变等就直接去调用 [allConversations:]这个接口,应该做一定的逻辑处理.

下面是一个简单的例子,可能不是很完美,大家可以自己做更好的优化,不要简单无脑的都直接去调用API,应该做一些相应的缓存:

#pragma mark JMSGMessageDelegate
- (void)onReceiveMessage:(JMSGMessage *)message error:(NSError *)error {
    [self getConversationList];
}

- (void)onConversationChanged:(JMSGConversation *)conversation {
    [self onSyncReloadConversationListWithConversation:conversation];
}

- (void)onGroupInfoChanged:(JMSGGroup *)group {
    [self getConversationList];
}

- (void)onSyncOfflineMessageConversation:(JMSGConversation *)conversation
                         offlineMessages:(NSArray<__kindof JMSGMessage *> *)offlineMessages {
    [self onSyncReloadConversationListWithConversation:conversation];
}

- (void)onSyncRoamingMessageConversation:(JMSGConversation *)conversation {
    [self onSyncReloadConversationListWithConversation:conversation];
}

// 添加一个简单的逻辑处理,
//如果代理有传 conversation 就直接插入 _conversationArr 数组中,不去调用API接口获取列表
- (void)onSyncReloadConversationListWithConversation:(JMSGConversation *)conversation {
	if(!conversation) {
		return ;
	}
    BOOL isHave = NO;
    if (conversation.conversationType == kJMSGConversationTypeSingle) {
        JMSGUser *newUser = (JMSGUser *)conversation.target;
        for (int i = 0; i < _conversationArr.count; i++) {
            JMSGConversation *oldConversation = _conversationArr[i];
            if (oldConversation.conversationType == kJMSGConversationTypeSingle) {
                JMSGUser *oldUser = (JMSGUser *)oldConversation.target;
                if ([newUser.username isEqualToString:oldUser.username] && [newUser.appKey isEqualToString:oldUser.appKey]) {
                    [_conversationArr replaceObjectAtIndex:i withObject:conversation];
                    isHave = YES;
                    break ;
                }
            }
        }
    }else{
        JMSGGroup *newGroup = (JMSGGroup *)conversation.target;
        for (int i = 0; i < _conversationArr.count; i++) {
            JMSGConversation *oldConversation = _conversationArr[i];
            if (oldConversation.conversationType == kJMSGConversationTypeGroup) {
                JMSGGroup *oldGroup = (JMSGGroup *)oldConversation.target;
                if ([newGroup.gid isEqualToString:oldGroup.gid]) {
                    [_conversationArr replaceObjectAtIndex:i withObject:conversation];
                    isHave = YES;
                    break ;
                }
            }
        }
    }
    if (!isHave) {
        [_conversationArr insertObject:conversation atIndex:0];
    }
    _conversationArr = [self sortConversation:_conversationArr];
    _unreadCount = _unreadCount + [conversation.unreadCount integerValue];
    [self saveBadge:_unreadCount];
    [self.chatTableView reloadData];
}

// 获取所有会话的方法,做一个简单的缓存,不要每次都直接去调用 API ,
// 如果已经在获取中就不要再次调用API,当获取成功之后如果有缓存,就再次去获取一次会话列表
- (void)getConversationList {
    
    if (isGetingAllConversation) {
        NSLog(@"is loading conversation list");
        cacheCount++;
        return ;
    }
    
    NSLog(@"get allConversation -- start");
    isGetingAllConversation = YES;
    
    [self.addBgView setHidden:YES];
    [JMSGConversation allConversations:^(id resultObject, NSError *error) {
        JCHATMAINTHREAD(^{
            isGetingAllConversation = NO;
            if (error == nil) {
                _conversationArr = [self sortConversation:resultObject];
                _unreadCount = 0;
                for (NSInteger i=0; i < [_conversationArr count]; i++) {
                    JMSGConversation *conversation = [_conversationArr objectAtIndex:i];
                    _unreadCount = _unreadCount + [conversation.unreadCount integerValue];
                }
                [self saveBadge:_unreadCount];
            } else {
                _conversationArr = nil;
            }
            [self.chatTableView reloadData];
            NSLog(@"get allConversation -- end");
            isGetingAllConversation = NO;
            [self checkCacheGetAllConversationAction];
        });
    }];
}
- (void)checkCacheGetAllConversationAction {
    if (cacheCount > 0) {
        NSLog(@"is have cache ,once again get all conversation");
        cacheCount = 0;
        [self getConversationList];
    }
}

3. 聊天界面

3.1 实现监听 <漫游消息> 代理方法
- (void)onSyncRoamingMessageConversation:(JMSGConversation *)conversation {
	// do something
	// 一般情况这个漫游消息代理,只有才切换设备登录时才会有
	// 当有某个会话有漫游消息时,会触发这个代理方法,UI 层需要根据自己逻辑去刷新聊天列表
}
3.2 实现监听 <漫游消息> 代理方法
- (void)onSyncOfflineMessageConversation:(JMSGConversation *)conversation
                         offlineMessages:(NSArray<__kindof JMSGMessage *> *)offlineMessages { 
	// do something
	// 这个代理方法,一般是在有离线消息前提下,启动、从后台唤起、长连接断开又重连 这些情况下APP时会触发这个方法
	// 当某个会话有离线消息时,会触发这个代理方法,UI 层需要根据自己逻辑去刷新聊天列表                    
}
3.3 用户信息更新、多媒体消息刷新
  • 因为增加了用户信息自动更新功能,所以在聊天界面需要考虑刷新头像的逻辑处理;
  • 因为消息同步是以会话为单位下发消息,所以最新的多媒体消息可能还在下载中,而此时聊天界面已经显示了这条消息,所以此时也应该考虑到刷新多媒体消息;
3.4 关于聊天界面UI层刷新的一些建议

JChat 中原来就有的一个 JCHATChatModel ,现在给这个model 增加几个属性

//是否是默认头像
@property (nonatomic, assign) BOOL isDefaultAvatar;
//头像图片的data.length
@property (nonatomic, assign) NSUInteger avatarDataLength;
//多媒体消息data.length(缩略图、语音)
@property (nonatomic, assign) NSUInteger messageMediaDataLength;

然后,在修改下 JCHATChatModel 类里的这个方法[-(void)setChatModelWith:conversationType:],

修改其中的 语音 和 图片  这两个case
case kJMSGContentTypeVoice:
{
  [self setupVoiceSize:((JMSGVoiceContent *)message.content).duration];
  //原来这里有下载语音的代码,把里面下载语音的方法注释掉,不要在这里下载,直接这样就好 
}
break;
case kJMSGContentTypeImage:
{
 [self setupImageSize];//修改一下这个方法,如下
}
break;
	
	
- (void)setupImageSize {
  if (self.message.status == kJMSGMessageStatusReceiveDownloadFailed) {
    _contentSize = CGSizeMake(77, 57);
    return;
  }
  
    JMSGImageContent *imageContent = (JMSGImageContent *)self.message.content;
    float imgHeight;
    float imgWidth;
    
    if (imageContent.imageSize.height >= imageContent.imageSize.width) {
        imgHeight = 135;
        imgWidth = (imageContent.imageSize.width/imageContent.imageSize.height) *imgHeight;
    } else {
        imgWidth = 135;
        imgHeight = (imageContent.imageSize.height/imageContent.imageSize.width) *imgWidth;
    }
    
    if ((imgWidth > imgHeight?imgHeight/imgWidth:imgWidth/imgHeight)<0.47) {
        self.imageSize = imgWidth > imgHeight?CGSizeMake(135, 55):CGSizeMake(55, 135);
        _contentSize = imgWidth > imgHeight?CGSizeMake(135, 55):CGSizeMake(55, 135);
        return;
    }
    self.imageSize = CGSizeMake(imgWidth, imgHeight);
    _contentSize = CGSizeMake(imgWidth, imgHeight);
}
          

针对代理方法,下面几个代理方法在 JChat demo 里有做了相应的调整和优化,这里就不一一写出来,直接去Demo里查看

- (void)onSendMessageResponse:(JMSGMessage *)message error:(NSError *)error{
}
- (void)onReceiveMessage:(JMSGMessage *)message error:(NSError *)error{
}
- (void)onSyncOfflineMessageConversation:(JMSGConversation *)conversation offlineMessages:(NSArray<__kindof JMSGMessage *> *)offlineMessages{ 
}
- (void)onSyncRoamingMessageConversation:(JMSGConversation *)conversation{
}

对于 JCHATMessageContentView 这个类,做了优化

//原来的
- (void)setMessageContentWith:(JMSGMessage *)message
// 换成这个,增加一个block
- (void)setMessageContentWith:(JMSGMessage *)message handler:(void(^)(NSUInteger messageMediaDataLength))block;

对于 JCHATMessageTableViewCell 这个类里也做了优化,具体请查看demo

// 增加了一个刷新多媒体消息的block
@property(strong, nonatomic) JCHATMessageTableViewCellRefreshMediaMessage  messageTableViewCellRefreshMediaMessage;

// JCHATMessageTableViewCell.m 里的这个方法里面 contentview 调用的方法要改成上面优化的那个方法
- (void)updateFrameWithContentFrame:(CGSize)contentSize {
  /*
  ····此处省略一些未变动的代码
  */
  __weak __typeof__(self) weakSelf = self;
  [_messageContent setMessageContentWith:_model.message handler:^(NSUInteger messageMediaDataLength) {
      __strong __typeof__(weakSelf) strongSelf = weakSelf;
      BOOL isShouldRefresh = NO;
      if (weakSelf.model.messageMediaDataLength != messageMediaDataLength) {
          isShouldRefresh = YES;
          weakSelf.model.messageMediaDataLength = messageMediaDataLength;
          
          if (strongSelf.messageTableViewCellRefreshMediaMessage) {
              strongSelf.messageTableViewCellRefreshMediaMessage(strongSelf.model,isShouldRefresh);
          }
      }
  }];
}

在聊天界面的 cellForRowAtIndexPath:函数里的 cellIdentifier = @"MessageCell" 这个里增加了刷新多媒体消息的block,如下:

static NSString *cellIdentifier = @"MessageCell";
JCHATMessageTableViewCell *cell = (JCHATMessageTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (cell == nil) {
  cell = [[JCHATMessageTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
  cell.conversation = _conversation;
}

[cell setCellData:model delegate:self indexPath:indexPath];
    
__weak __typeof(self)weakSelf = self;    
cell.messageTableViewCellRefreshMediaMessage = ^(JCHATChatModel *cellModel,BOOL isShouldRefresh){
    __strong __typeof(weakSelf)strongSelf = weakSelf;
    if (isShouldRefresh) {
        [strongSelf refreshCellMessageMediaWithChatModel:cellModel];
    }
};

具体的修改,可以到JChat里去查看,有些增加的函数没有写到这里,大家通过上面写的方法点击跟进去函数里查看就可以看到。

以上的修改和优化,可能还存在一定的问题,还需要继续优化,各位开发者可以自己进行修改。

JChat里的代码都是针对JChat这个简单的demo所写的,所以开发者不要完全依赖这里的代码,不要直接简单的复制粘贴拿去去使用,最好要根据自己APP的实际情况来加以分解和优化