iOS开发之融云IM集成

作者: mrChan1234 | 来源:发表于2019-01-14 19:37 被阅读0次

    首先去融云开发者注册一波账号,获取AppKey :


    AppKey.png

    然后拉取融云SDK:

    platform :ios, '8.0'
    inhibit_all_warnings!
    target 'your projectName' do
    pod 'RongCloudIM/IMKit'
    end
    

    然后pod install,会发现SDK已经被你拉取下来了,首先在程序入口AppDelegate.m里初始化融云SDK:

        [[RCIM sharedRCIM]initWithAppKey:kRongCloudKey];
        [RCIM sharedRCIM].connectionStatusDelegate = self;
        [RCIM sharedRCIM].enablePersistentUserInfoCache = YES;
        [RCIM sharedRCIM].globalConversationAvatarStyle = RC_USER_AVATAR_CYCLE;
        [RCIM sharedRCIM].globalMessageAvatarStyle =RC_USER_AVATAR_CYCLE;
        [RCIM sharedRCIM].showUnkownMessageNotificaiton = YES;
        [RCIM sharedRCIM].enableMessageAttachUserInfo = YES;
        [RCIM sharedRCIM].userInfoDataSource = self;
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectToRongCloud) name:kLoginSucessNotification object:nil];
    
    
    // MARK: - RCIMUserInfoDataSource
    - (void)getUserInfoWithUserId:(NSString *)userId completion:(void (^)(RCUserInfo *userInfo))completion {
        NSLog(@"Rong cloud userID: %@", userId);
        if ([userId isEqualToString:kAppUserInfo.userId]) {
            RCUserInfo *user = [[RCUserInfo alloc] initWithUserId:userId
                                                             name:kAppUserInfo.name
                                                         portrait:nil];
           //缓存至用户信息
            [kRongCloudManager insertWithUser:user];
            completion(user);
        } else {
            __block RCUserInfo *user;
            //根据userId去查找相对应的头像和昵称,缓存
            [NetTool postWithURLString:[NSString stringWithFormat:@"%@%@",kBaseURL,@"rongCloud/getUserNameAndImage"]
                            parameters: [UtilityHelper encryptParmar:@{@"uid":userId}]
                               success:^(NSDictionary *data) {
                if ([data[@"reCode"] isEqualToString:@"X0000"]) {
                    user = [[RCUserInfo alloc] initWithUserId:userId
                                                                     name:data[@"rel"][@"name"]
                                                                 portrait:[data[@"rel"][@"image"]length] > 2 ? data[@"rel"][@"image"]: nil];
                 //缓存至用户信息
                    [kRongCloudManager insertWithUser:user];
                    completion(user);
                } else {
                    completion(user);
                }
            } failure:^(NSError *error) {
                completion(user);
            }];
        }
    }
    

    然后在App的登录那里将后台获取到的融云token信息拿过来去连接融云服务器:

    // MARK: - 融云服务器连接状态监听
    - (void)onRCIMConnectionStatusChanged:(RCConnectionStatus)status {
       if (status == ConnectionStatus_Connected) {
           NSLog(@"融云服务器连接成功!");
       } else  {
           if (status == ConnectionStatus_SignUp) {
               NSLog(@"融云服务器断开连接!");
           } else {
               NSLog(@"融云服务器连接失败!");
           }
       }
    }
    // MARK: - 连接融云服务器
    - (void)connectToRongCloud {
       [NetTool postWithURLString:[NSString stringWithFormat:@"%@%@",kBaseURL,@"rongCloud/getRongCloudToken"]
                       parameters:@{@"token":kUserToken}
                          success:^(NSDictionary *data) {
                              if ([data[@"reCode"] isEqualToString:@"X0000"]) {
                                  NSString *rongCloudToken = data[@"rel"];
                                  [[NSUserDefaults standardUserDefaults] setObject:rongCloudToken forKey:@"RCToken"];
                                  [[NSUserDefaults standardUserDefaults] synchronize];
                                  [[RCIM sharedRCIM] connectWithToken:rongCloudToken
                                                              success:^(NSString *userId) {
                                                                  //设置当前用户信息
                                                                  RCUserInfo *currentUserInfo = [[RCUserInfo alloc] initWithUserId:kAppUserInfo.userId
                                                                                                                              name:kAppUserInfo.name
                                                                                                                          portrait:kRandomAvatar];
                                                                  [RCIM sharedRCIM].currentUserInfo = currentUserInfo;
                                                                  [RCIM sharedRCIM].enablePersistentUserInfoCache = YES;
                                                              } error:^(RCConnectErrorCode status) {
                                                                  
                                                              } tokenIncorrect:^{
                                                                  
                                                              }];
                              }
                          } failure:^(NSError *error) {
                              
                          }];
    }
    

    在登录的页面那里发一个通知给App,拿到Token去连接融云的服务器:

      [[NSNotificationCenter defaultCenter] postNotificationName:kLoginSucessNotification object:nil];
    

    看融云给出的打印日志会发现,融云的集成是成功了:


    屏幕快照 2019-01-14 下午5.38.02.png

    接下来就是聊天模块了,仔细看SDK的头文件你会发现,其实融云的程序猿早就写好了这些模块,如果不是高度自定义的话,完全可以new一个VController继承他写好的控制器,其中最核心的两个viewController:RCConversationViewController、RCConversationListViewController,顾明思义,第一个是用来展示聊天会话的,第二个是用来展示绘画列表的。
    具体的实现代码如下:

    @interface CustomChatListVC () <RCIMReceiveMessageDelegate,UITableViewDataSource,UITableViewDelegate> {
        UITableView *_tableView;
        NSMutableArray <RCConversation *> * _conversationListArray;
    }
    
    @end
    
    @implementation CustomChatListVC
    
    -(void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        [self refresh];
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        self.view.backgroundColor = [UIColor whiteColor];
        _conversationListArray = [NSMutableArray arrayWithArray:[[RCIMClient sharedRCIMClient] getConversationList:@[@(ConversationType_PRIVATE)]]];
        [RCIM sharedRCIM].receiveMessageDelegate = self;
        _tableView = kTableViewWithConfiguration(self.view, CGRectZero, 0, self, self, nil);
        [_tableView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.edges.equalTo(self.view);
        }];
    }
    
    // MARK: - refreshAction
    - (void)refresh {
        _conversationListArray = [NSMutableArray arrayWithArray:[[RCIMClient sharedRCIMClient] getConversationList:@[@(ConversationType_PRIVATE)]]];
        for (RCConversation *conversation in _conversationListArray) {
            __block RCUserInfo *user;
            [NetTool postWithURLString:[NSString stringWithFormat:@"%@%@",kBaseURL,@"rongCloud/getUserNameAndImage"]
                            parameters: [UtilityHelper encryptParmar:@{@"uid":conversation.targetId}]
                               success:^(NSDictionary *data) {
                                   if ([data[@"reCode"] isEqualToString:@"X0000"]) {
                                       user = [[RCUserInfo alloc] initWithUserId:conversation.targetId
                                                                            name:data[@"rel"][@"name"]
                                                                        portrait:[data[@"rel"][@"image"]length] > 2 ? data[@"rel"][@"image"]: nil];
                                       [kRongCloudManager insertWithUser:user];
                                       dispatch_async(dispatch_get_main_queue(), ^{
                                           [_tableView reloadData];
                                       });
                                   }
                               } failure:^(NSError *error) {
                               }];
        }
    }
    
    - (RCUserInfo *)getSenderInfoWithExtra:(NSString *)extraStr targetId:(NSString *)targetId {
        NSDictionary *json = [extraStr mj_JSONObject];
        return [[RCUserInfo alloc] initWithUserId:targetId name:json[@"name"] portrait:json[@"avatar"]];
    }
    
    
    // MARK: - 接收到消息的回调
    - (void)onRCIMReceiveMessage:(RCMessage *)message left:(int)left {
        /*NSInteger index = 0;
        BOOL exsit = NO;
        
        for (int i = 0 ; i < _conversationListArray.count; i ++) {
            RCConversation *conversation = _conversationListArray[i];
            if ([conversation.targetId isEqualToString:message.targetId]) {
                exsit = YES;
                index = i;
                break;
            }
        }
        if (exsit) {
            //存在
            RCConversation *conversation = _conversationListArray[index];
            conversation.lastestMessage = message.content;
            conversation.unreadMessageCount ++;
            [_conversationListArray replaceObjectAtIndex:index withObject:conversation];
            dispatch_async(dispatch_get_main_queue(), ^{
                [_tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationFade];
            });
        } else {
            RCConversation *newConversation = [RCConversation new];
            newConversation.lastestMessage = message.content;
            newConversation.targetId = message.targetId;
            newConversation.senderUserId = message.senderUserId;
            newConversation.receivedTime = message.receivedTime;
            newConversation.unreadMessageCount ++;
            [_conversationListArray addObject:newConversation];
            dispatch_async(dispatch_get_main_queue(), ^{
                [_tableView reloadData];
            });
        }*/
        [self refresh];
    }
    
    // MARK: - UITableVieDataSource &Delegate
    
    -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        return 1;
    }
    
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return _conversationListArray.count;
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        ChatListCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([ChatListCell class])];
        if (!cell) {
            cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([ChatListCell class]) owner:self options:nil] firstObject];
        }
        [cell setConversationListModel:_conversationListArray[indexPath.row]];
        return cell;
    }
    
    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
        RCConversation *model = _conversationListArray[indexPath.row];
        model.unreadMessageCount = 0;
        [_conversationListArray replaceObjectAtIndex:indexPath.row withObject:model];
        CustomChatVC *conversationVC = [[CustomChatVC alloc]initWithConversationType:model.conversationType targetId:model.targetId];
        conversationVC.title = [kRongCloudManager getUserWithTargetId:model.targetId].name;
        [self.navigationController pushViewController:conversationVC animated:YES];
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return 80;
    }
    

    自定义列表cell:

    @implementation ChatListCell
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        // Initialization code
        //已读已发送
        _tip.clipsToBounds = YES;
        _tip.layer.borderWidth = 1.0;
        _tip.layer.cornerRadius = 4.0;
        //头像
        _avatar.clipsToBounds = YES;
        _avatar.layer.cornerRadius = _avatar.height / 2.0;
        //未读消息
        _remindCount.clipsToBounds = YES;
        _remindCount.layer.cornerRadius = _remindCount.height / 2.0;
        _remindCount.hidden = YES;
    }
    
    /*
    - (void)setDataWithConversationListModel:(ConversationListModel *)conversationListModel {
        RCConversation *model = conversationListModel.conversation;
        if (model.unreadMessageCount == 0 ) {
            _remindCount.hidden = YES;
        } else {
            _remindCount.hidden = NO;
            _remindCount.text = [NSString stringWithFormat:@"%i",model.unreadMessageCount];
        }
        if (model.receivedStatus == ReceivedStatus_READ) {
            //已读
            _tip.layer.borderColor = [UIColor greenColor].CGColor;
            _tip.textColor = [UIColor greenColor];
            _tip.text = @"已读";
        } else {
            _tip.layer.borderColor = [UIColor redColor].CGColor;
            _tip.textColor = [UIColor redColor];
            _tip.text = @"送达";
        }
        RCUserInfo *sender = [kRongCloudManager getUserWithTargetId:model.targetId];
        [_avatar sd_setImageWithURL:[NSURL URLWithString:sender.portraitUri] placeholderImage:[UIImage imageWithColor:[UIColor grayColor] withSize:CGSizeMake(60, 60)]];
        //名字
        _name.text = sender.name;
        //职位名称
        _position.text = sender.name;
        _message.text = [model.lastestMessage valueForKey:@"_content"];
        NSDateFormatter *format = [NSDateFormatter new];
        BOOL today = [[NSCalendar currentCalendar] isDateInToday:[NSDate dateWithTimeIntervalSince1970:model.receivedTime/1000]];
        if (today) {
            [format setDateFormat:@"HH:MM"];
        } else {
            [format setDateFormat:@"yyyy-MM-dd"];
        }
        _time.text = [format stringFromDate:[NSDate dateWithTimeIntervalSince1970:model.receivedTime/1000]];
    }
    */
    
    // MARK: - private Method
    - (void)setConversationListModel:(RCConversation *)model {
        if (model.unreadMessageCount == 0 ) {
            _remindCount.hidden = YES;
        } else {
            _remindCount.hidden = NO;
            _remindCount.text = [NSString stringWithFormat:@"%i",model.unreadMessageCount];
        }
        if (model.receivedStatus == ReceivedStatus_READ) {
            //已读
            _tip.layer.borderColor = [UIColor greenColor].CGColor;
            _tip.textColor = [UIColor greenColor];
            _tip.text = @"已读";
        } else {
            _tip.layer.borderColor = [UIColor redColor].CGColor;
            _tip.textColor = [UIColor redColor];
            _tip.text = @"送达";
        }
    //    RCUserInfo *sender = [self getSenderInfoWithExtra:[model.lastestMessage valueForKey:@"_extra"] targetId:model.targetId];
        RCUserInfo *sender = [kRongCloudManager getUserWithTargetId:model.targetId];
        //头像
        [_avatar sd_setImageWithURL:[NSURL URLWithString:sender.portraitUri] placeholderImage:[UIImage imageWithColor:[UIColor grayColor] withSize:CGSizeMake(60, 60)]];
        //名字
        _name.text = sender.name;
        //职位名称
        _position.text = sender.name;
        BOOL isMe = [model.lastestMessage.senderUserInfo.userId isEqualToString:kAppUserInfo.userId];
        NSString *messageContent = [MessageConvert messageConvertWithMessageContent:model.lastestMessage];
        _message.text = isMe?[NSString stringWithFormat:@"我:%@",messageContent]: messageContent;
        NSDateFormatter *format = [NSDateFormatter new];
       BOOL today = [[NSCalendar currentCalendar] isDateInToday:[NSDate dateWithTimeIntervalSince1970:model.receivedTime/1000]];
        if (today) {
            [format setDateFormat:@"HH:MM"];
        } else {
            [format setDateFormat:@"yyyy-MM-dd"];
        }
        _time.text = [format stringFromDate:[NSDate dateWithTimeIntervalSince1970:model.receivedTime/1000]];
    }
    
    - (RCUserInfo *)getSenderInfoWithExtra:(NSString *)extraStr targetId:(NSString *)targetId {
        NSDictionary *json = [extraStr mj_JSONObject];
        return [[RCUserInfo alloc] initWithUserId:targetId name:json[@"name"] portrait:json[@"avatar"]];
    }
    
    

    MessageConvert.m:

    +(NSString *)messageConvertWithMessageContent:(RCMessageContent *)messageContent {
        NSString *value = @"";
        if ([messageContent isKindOfClass:[RCTextMessage class]]) {
            //文本
            value = ((RCTextMessage *)messageContent).content;
        } else if ([messageContent isKindOfClass:[RCLocationMessage class]]) {
            //位置
            value = @"[位置]";
        } else if ([messageContent isKindOfClass:[RCImageMessage class]]) {
            //图片
            value = @"[图片]";
        } else if ([messageContent isKindOfClass:[RCVoiceMessage class]]) {
            //语音
            value = @"[语音]";
        } else if ([messageContent isKindOfClass:[RCSightMessage class]]) {
            //小视频
            value = @"[小视频]";
        }
        return value;
    }
    

    由于继承自RCConversationListViewController的ViewController只能在dataSource里面添加custom样式的model,从而达到增加自定义cell的效果:

    -(NSMutableArray *)willReloadTableData:(NSMutableArray *)dataSource {
        NSArray *customItems = @[@"系统消息1",@"系统消息2"];
        for (int i = 0; i<customItems.count; i++) {
            RCConversationModel *model = [RCConversationModel new];
            model.conversationTitle = customItems[i];
            model.conversationModelType = RC_CONVERSATION_MODEL_TYPE_CUSTOMIZATION;
            model.isTop = YES;
            if (dataSource.count) {
                //插入自定义cell
                [dataSource insertObject:model atIndex:i];
            }
        }
        return dataSource;
    }
    
    - (void)onSelectedTableRow:(RCConversationModelType)conversationModelType
             conversationModel:(RCConversationModel *)model
                   atIndexPath:(NSIndexPath *)indexPath {
        if (model.conversationModelType == RC_CONVERSATION_MODEL_TYPE_CUSTOMIZATION) {
            //自定义消息cell的点击
        } else  {
            //系统会话列表cell的点击
        }
    }
    
    - (RCConversationBaseCell *)rcConversationListTableView:(UITableView *)tableView
                                      cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        SystemChatListCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([SystemChatListCell class])];
        if (!cell) {
            cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([SystemChatListCell class]) owner:self options:nil] firstObject];
        }
        //系统消息cell的配置
        return cell;
    }
    

    这个刚开始发现的时候,感觉有点坑,他不像环信那样可以直接去重写baseCell里面的东西(只能添加,而不能修改,因为这个VC继承了RCConversationListViewController),各位大兄弟要注意这个地方。
    在聊天室要用到自定义的cell,所有我们要重写一个message消息类集成于RCMessageContent,重写一个Cell继承RCMessageCell,具体如下:

    #import <RongIMKit/RongIMKit.h>
    #import "JobMessage.h"
    NS_ASSUME_NONNULL_BEGIN
    
    @interface JobCell : RCMessageCell
    
    @property(nonatomic, strong) UIImageView *bubbleBackgroundView;
    
    -(void)setDataModel:(RCMessageModel *)model;
    
    //+ (CGSize)bubbleSizeWithJobMessageModel:(JobMessage *)model;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "JobCell.h"
    
    @interface JobCell () {
        UILabel *_titles[7];
    }
    
    @end
    @implementation JobCell
    
    + (CGSize)sizeForMessageModel:(RCMessageModel *)model
          withCollectionViewWidth:(CGFloat)collectionViewWidth
             referenceExtraHeight:(CGFloat)extraHeight {
        return CGSizeMake(kScreenWidth, 300 + extraHeight);
    }
    
    - (instancetype)initWithFrame:(CGRect)frame {
        self = [super initWithFrame:frame];
        if (self) {
            [self initialize];
        }
        return self;
    }
    
    - (id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        if (self) {
            [self initialize];
        }
        return self;
    }
    
    - (void)initialize {
        self.bubbleBackgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 300, 300)];
        self.bubbleBackgroundView.backgroundColor = [UIColor whiteColor];
        self.bubbleBackgroundView.clipsToBounds = YES;
        self.bubbleBackgroundView.layer.cornerRadius = 5.0;
        [self.messageContentView addSubview:self.bubbleBackgroundView];
        
        for (int i = 0 ; i < 7; i ++) {
            _titles[i] =  kLabelWithCornerRadius(self.bubbleBackgroundView, CGRectMake(20, i == 0 ? 30 :_titles[i - 1].bottom + 10, 280, 35), [UIColor whiteColor], [UIColor blackColor], 0, kFont(14),@"" , 0.0);
        }
        self.bubbleBackgroundView.userInteractionEnabled = YES;
        UITapGestureRecognizer *longPress =
        [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
        [self.bubbleBackgroundView addGestureRecognizer:longPress];
    }
    
    - (void)tapAction:(UIGestureRecognizer *)gestureRecognizer {
        if ([self.delegate respondsToSelector:@selector(didTapMessageCell:)]) {
            [self.delegate didTapMessageCell:self.model];
        }
    }
    
    - (void)setDataModel:(RCMessageModel *)model {
        [super setDataModel:model];
        JobMessage *message = (JobMessage *)model.content;
        NSDictionary *value = [message.content mj_JSONObject][@"data"];
        for (int i = 0; i < 7; i ++) {
            _titles[i].text =  [NSString stringWithFormat:@"%@:%@\n",[value allKeys][i],[value valueForKey:[value allKeys][i]]];
        }
        
        if (message) {
            
        }
        //拉伸图片
        if (MessageDirection_RECEIVE == self.messageDirection) {
            
            
        } else {
            
        }
    }
    
    + (CGSize)bubbleSizeWithJobMessageModel:(JobMessage *)message {
        return CGSizeMake(300, 300);
    }
    

    JobMessage类:

    #import <RongIMLib/RongIMLib.h>
    #import <RongIMLib/RCMessageContent.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface JobMessage : RCMessageContent <NSCoding,RCMessageContentView>
    
    @property(nonatomic,strong)NSString *content;
    
    @property(nonatomic, strong) NSString* extra;
    
    +(instancetype)messageWithContent:(NSString *)jsonContent;
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    @implementation JobMessage
    
    + (instancetype)messageWithContent:(NSString *)jsonContent {
        JobMessage *model = [JobMessage new];
        if (model) {
            model.content = jsonContent;
        }
        
        return model;
    }
    
    //存储状态和是否计入未读数
    +(RCMessagePersistent)persistentFlag {
        //存储并计入未读数
        return (MessagePersistent_ISCOUNTED);
    }
    
    #pragma mark – NSCoding protocol methods
    #define KEY_TXTMSG_CONTENT @"content"
    #define KEY_TXTMSG_EXTRA @"extra"
    
    - (instancetype)initWithCoder:(NSCoder *)aDecoder
    {
        self = [super init];
        if (self) {
            self.content = [aDecoder decodeObjectForKey:KEY_TXTMSG_CONTENT];
            self.extra = [aDecoder decodeObjectForKey:KEY_TXTMSG_EXTRA]; }
        return self;
    }
    
    - (void)encodeWithCoder:(NSCoder *)aCoder
    {
        [aCoder encodeObject:self.content forKey:KEY_TXTMSG_CONTENT];
        [aCoder encodeObject:self.extra forKey:KEY_TXTMSG_EXTRA];
        
    }
    
    #pragma mark – RCMessageCoding delegate methods
    ///将消息内容编码成json
    -(NSData *)encode {
        
        NSMutableDictionary *dataDict=[NSMutableDictionary dictionary];
        [dataDict setObject:self.content forKey:@"content"];
        if (self.extra) {
            [dataDict setObject:self.extra forKey:@"extra"];
        }
        
        NSData *data = [NSJSONSerialization dataWithJSONObject:dataDict
                                                       options:kNilOptions
                                                         error:nil];
        
        return data;
    }
    
    //将json解码生成消息内容
    -(void)decodeWithData:(NSData *)data {
        __autoreleasing NSError* __error = nil;
        if (!data) {
            return;
        }
        NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data
                                                                   options:kNilOptions
                                                                     error:&__error];
        NSLog(@"dictionary == %@",dictionary);
        if ([dictionary objectForKey:@"content"]) {
            self.content = dictionary[@"content"];
            NSLog(@"dictionary1111 == %@",dictionary[@"content"]);
            self.extra = dictionary[@"extra"];
        }else{
            NSError *error;
            NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:kNilOptions error:nil];
            NSString *content ;
            if (!data) {
                NSLog(@"%@",error);
            }else{
                content = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
            }
            self.content = content;
        }
        
    }
    //您定义的消息类型名,需要在各个平台上保持一致,以保证消息互通,别以 RC 开头,以免和融云系统冲突
    +(NSString *)getObjectName {
        return @"JobMessageType";
    }
    
    //最后一条消息是自定义消息的时候,可以更改在会话列表显示的类型,为了区分消息类型
    - (NSString *)conversationDigest {
        NSString *contentStr = @"[职位信息]";
        return contentStr;
    }
    
    @end
    

    然后在ChatVC里注册对应的message消息类和messageCell类:

     [self registerClass:[JobCell class] forMessageClass:[JobMessage class]];
    

    在AppDelegate里面注册一波自定义message类型:

        [[RCIM sharedRCIM] registerMessageType:[JobMessage class]];
    

    这里特别补充一下关于用户头像和昵称的问题,由于和环信一样,这种IM三方并不负责存储用户或群组信息,这些东西一般是用来存放在自己App的后台服务器上,在加载会话列表的时候需要去后台根据targetId去拉取聊天对话的用户信息,但是有一种更为巧妙的方法就是将发送者的信息(昵称、头像、职位名称等等)存放在消息体中,消息体中有一个字段叫做extra:

    {"content":"测试","extra":{
         "name":"Chan",
         "avatar":"http://xxxx/pic_201808241707108698543.png"}
         }
    

    然后根据每条消息的latestMessage.extra字段获取最新一条消息的用户信息,但是注意,这里有一个问题就是加入我一直给一个用户发送消息,但是对方没回复,这时候就不管用了,所以读者也注意到了我上面的代码,用了一个单利对象专门用来缓存对话targeId的RCUserInfo用户信息:

    #import "RCUserManager.h"
    
    @implementation RCUserManager
    
    + (instancetype)shareManager {
        static RCUserManager *manager = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            manager = [[RCUserManager alloc] init];
        });
        return manager;
    }
    
    - (instancetype)init {
        if (self = [super init]) {
            _users = [NSMutableArray new];
        }
        return self;
    }
    
    - (void)insertWithUser:(RCUserInfo *)user {
        if (_users) {
            BOOL exsit = NO;
            int index = 0;
            for (int i = 0 ; i < _users.count; i ++) {
                if ([((RCUserInfo *)_users[i]).userId isEqualToString:user.userId]) {
                    exsit = YES;
                    index = i;
                    break;
                }
            }
            if (exsit) {
                [_users replaceObjectAtIndex:index withObject:user];
            } else {
                [_users  addObject:user];
            }
        }
    }
    
    - (RCUserInfo *)getUserWithTargetId:(NSString *)targetId {
        RCUserInfo *user;
        if (_users.count) {
            for (int i = 0 ; i < _users.count; i ++) {
                RCUserInfo *user = _users[i];
                if ([user.userId isEqualToString:targetId]) {
                    return user;
                    break;
                }
            }
        }
        return user;
    }
    

    由于自己的项目是招聘类App,在和企业沟通的时候,进入聊天室的时候,会出现一条企业发送过来的职位消息,也就是上面自定义的messageCell:

    CustomChatVC *conversationVC = [[CustomChatVC alloc]initWithConversationType:ConversationType_PRIVATE targetId:@"1392428"];
                JobInfoModel *jobModel = [JobInfoModel mj_objectWithKeyValues:jsonValue[@"data"]];
                conversationVC.jobInfoModel = jobModel;
                //插入一条对方发送过来的消息
                [[RCIMClient sharedRCIMClient] insertIncomingMessage:ConversationType_PRIVATE
                                                            targetId:@"1392428"
                                                        senderUserId:@"1392428"
                                                      receivedStatus:ReceivedStatus_READ
                                                             content:[JobMessage messageWithContent:[jsonValue mj_JSONString]]
                                                            sentTime:0];
                conversationVC.title = @"Chan";
                [self.navigationController pushViewController:conversationVC animated:YES];
    

    具体的简单实现就到这里,大致效果如下:


    ChatListCell.png
    ChatCell.png

    由于聊天室使用的是融云的控制器,也可以进行自定义,但是UI界面方面处理起来比较麻烦,后续再完善一波。

    相关文章

      网友评论

        本文标题:iOS开发之融云IM集成

        本文链接:https://www.haomeiwen.com/subject/zzsjdqtx.html