iOS開發(fā)之融云IM集成

首先去融云開發(fā)者注冊(cè)一波賬號(hào),獲取AppKey :


AppKey.png

然后拉取融云SDK:

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

然后pod install友鼻,會(huì)發(fā)現(xiàn)SDK已經(jīng)被你拉取下來了,首先在程序入口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;
        //根據(jù)userId去查找相對(duì)應(yīng)的頭像和昵稱,緩存
        [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的登錄那里將后臺(tái)獲取到的融云token信息拿過來去連接融云服務(wù)器:

// MARK: - 融云服務(wù)器連接狀態(tài)監(jiān)聽
- (void)onRCIMConnectionStatusChanged:(RCConnectionStatus)status {
   if (status == ConnectionStatus_Connected) {
       NSLog(@"融云服務(wù)器連接成功!");
   } else  {
       if (status == ConnectionStatus_SignUp) {
           NSLog(@"融云服務(wù)器斷開連接!");
       } else {
           NSLog(@"融云服務(wù)器連接失敗!");
       }
   }
}
// MARK: - 連接融云服務(wù)器
- (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) {
                                                              //設(shè)置當(dāng)前用戶信息
                                                              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) {
                          
                      }];
}

在登錄的頁(yè)面那里發(fā)一個(gè)通知給App廊谓,拿到Token去連接融云的服務(wù)器:

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

看融云給出的打印日志會(huì)發(fā)現(xiàn)梳猪,融云的集成是成功了:


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

接下來就是聊天模塊了,仔細(xì)看SDK的頭文件你會(huì)發(fā)現(xiàn)蒸痹,其實(shí)融云的程序猿早就寫好了這些模塊春弥,如果不是高度自定義的話,完全可以new一個(gè)VController繼承他寫好的控制器电抚,其中最核心的兩個(gè)viewController:RCConversationViewController惕稻、RCConversationListViewController,顧明思義,第一個(gè)是用來展示聊天會(huì)話的蝙叛,第二個(gè)是用來展示繪畫列表的俺祠。
具體的實(shí)現(xiàn)代碼如下:

@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: - 接收到消息的回調(diào)
- (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
    //已讀已發(fā)送
    _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 = @"送達(dá)";
    }
    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 = @"送達(dá)";
    }
//    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,從而達(dá)到增加自定義cell的效果:

-(NSMutableArray *)willReloadTableData:(NSMutableArray *)dataSource {
    NSArray *customItems = @[@"系統(tǒng)消息1",@"系統(tǒng)消息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的點(diǎn)擊
    } else  {
        //系統(tǒng)會(huì)話列表cell的點(diǎn)擊
    }
}

- (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];
    }
    //系統(tǒng)消息cell的配置
    return cell;
}

這個(gè)剛開始發(fā)現(xiàn)的時(shí)候借帘,感覺有點(diǎn)坑蜘渣,他不像環(huán)信那樣可以直接去重寫baseCell里面的東西(只能添加,而不能修改肺然,因?yàn)檫@個(gè)VC繼承了RCConversationListViewController)蔫缸,各位大兄弟要注意這個(gè)地方。
在聊天室要用到自定義的cell际起,所有我們要重寫一個(gè)message消息類集成于RCMessageContent拾碌,重寫一個(gè)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;
}

//存儲(chǔ)狀態(tài)和是否計(jì)入未讀數(shù)
+(RCMessagePersistent)persistentFlag {
    //存儲(chǔ)并計(jì)入未讀數(shù)
    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
///將消息內(nèi)容編碼成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解碼生成消息內(nèi)容
-(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;
    }
    
}
//您定義的消息類型名,需要在各個(gè)平臺(tái)上保持一致街望,以保證消息互通,別以 RC 開頭校翔,以免和融云系統(tǒng)沖突
+(NSString *)getObjectName {
    return @"JobMessageType";
}

//最后一條消息是自定義消息的時(shí)候,可以更改在會(huì)話列表顯示的類型灾前,為了區(qū)分消息類型
- (NSString *)conversationDigest {
    NSString *contentStr = @"[職位信息]";
    return contentStr;
}

@end

然后在ChatVC里注冊(cè)對(duì)應(yīng)的message消息類和messageCell類:

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

在AppDelegate里面注冊(cè)一波自定義message類型:

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

這里特別補(bǔ)充一下關(guān)于用戶頭像和昵稱的問題防症,由于和環(huán)信一樣,這種IM三方并不負(fù)責(zé)存儲(chǔ)用戶或群組信息哎甲,這些東西一般是用來存放在自己App的后臺(tái)服務(wù)器上蔫敲,在加載會(huì)話列表的時(shí)候需要去后臺(tái)根據(jù)targetId去拉取聊天對(duì)話的用戶信息,但是有一種更為巧妙的方法就是將發(fā)送者的信息(昵稱炭玫、頭像奈嘿、職位名稱等等)存放在消息體中,消息體中有一個(gè)字段叫做extra:

{"content":"測(cè)試","extra":{
     "name":"Chan",
     "avatar":"http://xxxx/pic_201808241707108698543.png"}
     }

然后根據(jù)每條消息的latestMessage.extra字段獲取最新一條消息的用戶信息吞加,但是注意裙犹,這里有一個(gè)問題就是加入我一直給一個(gè)用戶發(fā)送消息酝惧,但是對(duì)方?jīng)]回復(fù),這時(shí)候就不管用了伯诬,所以讀者也注意到了我上面的代碼,用了一個(gè)單利對(duì)象專門用來緩存對(duì)話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;
}

由于自己的項(xiàng)目是招聘類App巫财,在和企業(yè)溝通的時(shí)候盗似,進(jìn)入聊天室的時(shí)候,會(huì)出現(xiàn)一條企業(yè)發(fā)送過來的職位消息,也就是上面自定義的messageCell:

CustomChatVC *conversationVC = [[CustomChatVC alloc]initWithConversationType:ConversationType_PRIVATE targetId:@"1392428"];
            JobInfoModel *jobModel = [JobInfoModel mj_objectWithKeyValues:jsonValue[@"data"]];
            conversationVC.jobInfoModel = jobModel;
            //插入一條對(duì)方發(fā)送過來的消息
            [[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];

具體的簡(jiǎn)單實(shí)現(xiàn)就到這里,大致效果如下:


ChatListCell.png

ChatCell.png

由于聊天室使用的是融云的控制器庄吼,也可以進(jìn)行自定義前痘,但是UI界面方面處理起來比較麻煩,后續(xù)再完善一波昧绣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缺猛,更是在濱河造成了極大的恐慌,老刑警劉巖椭符,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荔燎,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡销钝,警方通過查閱死者的電腦和手機(jī)有咨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蒸健,“玉大人座享,你說我怎么就攤上這事∷朴牵” “怎么了渣叛?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)橡娄。 經(jīng)常有香客問我诗箍,道長(zhǎng),這世上最難降的妖魔是什么挽唉? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任滤祖,我火速辦了婚禮,結(jié)果婚禮上瓶籽,老公的妹妹穿的比我還像新娘匠童。我一直安慰自己,他們只是感情好塑顺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布汤求。 她就那樣靜靜地躺著俏险,像睡著了一般。 火紅的嫁衣襯著肌膚如雪扬绪。 梳的紋絲不亂的頭發(fā)上竖独,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天,我揣著相機(jī)與錄音挤牛,去河邊找鬼莹痢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛墓赴,可吹牛的內(nèi)容都是我干的竞膳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼诫硕,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼坦辟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起章办,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤锉走,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后纲菌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挠日,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年翰舌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚣潜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡椅贱,死狀恐怖懂算,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情庇麦,我是刑警寧澤计技,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站山橄,受9級(jí)特大地震影響垮媒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜航棱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一睡雇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饮醇,春花似錦它抱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽混移。三九已至,卻和暖如春侮穿,著一層夾襖步出監(jiān)牢的瞬間歌径,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工亲茅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沮脖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓芯急,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親驶俊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娶耍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 一、iOS 直播聊天室 Demo 說明 1饼酿、源碼結(jié)構(gòu) 2榕酒、AppDelegate 在 AppDelegate 中初...
    ajiao焦閱讀 2,837評(píng)論 2 7
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,096評(píng)論 1 32
  • 見君第一眼,羞澀情怯臉微紅故俐。 見君第二眼想鹰,恐別后相思甚苦。 見君第三眼药版,滿眼情波意難容辑舷。 見君第四眼,已是真心愛相...
    木南楠欣閱讀 353評(píng)論 0 1
  • 醒來覺得甚是愛你 原創(chuàng)作者:王清華 一 醒來覺得甚是愛你 這句話槽片,是朱生豪寫給妻子宋清如的何缓。 直...
    王清華閱讀 408評(píng)論 3 9
  • 機(jī)會(huì)是難得的,對(duì)于其他人还栓,或許只是一次機(jī)遇碌廓,而對(duì)于我,卻是安心與立命剩盒」绕牛看不清前方的路,只有祈禱了辽聊,愿上天護(hù)佑纪挎,一切順利!
    一言一瑾閱讀 615評(píng)論 0 0