iOS 云信IM 遇到的坑

云信IM在使用的过程中还是有蛮多的坑

1.离线消息云信只保存最近的100条 拉取历史消息时云信用的是本地的消息 如果App杀死进程时收到消息(离线消息)有可能丢失 在拉取消息时 应该换成拉取云端的消息 这样消息就可以完全的展示出来 但是在长按删除某一条数据时 只是删除本地的数据 在重新进入聊天页面下拉拉取时还会显示删除的消息(云信目前没有提供删除云端消息的接口 我给他们技术人员提了这个建议 当然他们没碉我 )

2.登陆问题 他们的登陆接口不能频繁调用 不然会出现登陆不成功的问题 云信接口返回错误吗 408 等等

3.在使用云信自带的UI控件时 如果需要在原来的基础上做修改时 首先你需要手动倒入他们的UI控件库 NIMKit 云信NIMKit下载地址

4.接下来讲解他们的控件及可以修改的地方:

NIMKitConfig 各个信息类型布局在 NIMKitConfig 中cell颜色背景 更多按钮下按钮的设置(照片,视频,拍摄等等)

#import "NIMKitConfig.h"
#import "NIMGlobalMacro.h"
#import "NIMMediaItem.h"
#import "UIImage+NIMKit.h"
#import 

@interface NIMKitSettings()
{
   BOOL _isRight;
}

- (instancetype)init:(BOOL)isRight;

@end


@implementation NIMKitConfig

- (instancetype) init
{
   self = [super init];
   if (self)
   {
       [self applyDefaultSettings];
       
       //设置cell背景色
       self.cellBackgroundColor = [UIColor clearColor];
   }
   return self;
}


- (NSArray *)defaultMediaItems
{
   
   return @[[NIMMediaItem item:@"onTapCustomMediaItemPicture:"
                   normalImage:[UIImage nim_imageInKit:@"timing_photo"]
                 selectedImage:[UIImage nim_imageInKit:@"timing_photo_hight"]
                         title:@" 相册"],
            
            [NIMMediaItem item:@"onTapMediaItemShowVideo:"
                   normalImage:[UIImage nim_imageInKit:@"timing_video"]
                 selectedImage:[UIImage nim_imageInKit:@"timing_video_hight"]
                         title:@" 视频"],
            
            [NIMMediaItem item:@"onTapMediaItemShoot:"
                   normalImage:[UIImage nim_imageInKit:@"timing_camera"]
                 selectedImage:[UIImage nim_imageInKit:@"timing_camera_hight"]
                         title:@" 拍摄"],
            
            //多加几个使布局经凑
            [NIMMediaItem item:@"empty:"
                   normalImage:nil
                 selectedImage:nil
                         title:@""],
            
            
            [NIMMediaItem item:@"empty:"
                   normalImage:nil
                 selectedImage:nil
                         title:nil],
            
            
            ];

}


- (CGFloat)maxNotificationTipPadding{
   
   return 20.f;
}


- (void)applyDefaultSettings
{
   _inputMaxLength = 1000; //输入框最大输入数
   _messageInterval = 300;
   _messageLimit    = 20;
   _recordMaxDuration = 60.f; //录音的最大时长
   _placeholder = @"请输入内容";
   _nickFont  = [UIFont systemFontOfSize:13.0];
   _nickColor = SharedColor.textLightBlack;
   
   _receiptFont  = [UIFont systemFontOfSize:13.0]; 
   _receiptColor = SharedColor.textLightBlack;
   
   _avatarType = NIMKitAvatarTypeRounded;
   _leftBubbleSettings  = [[NIMKitSettings alloc] init:NO];
   _rightBubbleSettings = [[NIMKitSettings alloc] init:YES];
}

- (NIMKitSetting *)setting:(NIMMessage *)message
{
   NIMKitSettings *settings = message.isOutgoingMsg? self.rightBubbleSettings : self.leftBubbleSettings;
   switch (message.messageType) {
       case NIMMessageTypeText:
           return settings.textSetting;
       case NIMMessageTypeImage:
           return settings.imageSetting;
       case NIMMessageTypeLocation:
           return settings.locationSetting;
       case NIMMessageTypeAudio:
           return settings.audioSetting;
       case NIMMessageTypeVideo:
           return settings.videoSetting;
       case NIMMessageTypeFile:
           return settings.fileSetting;
       case NIMMessageTypeTip:
           return settings.tipSetting;
       case NIMMessageTypeRobot:
           return settings.robotSetting;
       case NIMMessageTypeNotification:
       {
           NIMNotificationObject *object = (NIMNotificationObject *)message.messageObject;
           switch (object.notificationType)
           {
               case NIMNotificationTypeTeam:
                   return settings.teamNotificationSetting;
               case NIMNotificationTypeChatroom:
                   return settings.chatroomNotificationSetting;
               case NIMNotificationTypeNetCall:
                   return settings.netcallNotificationSetting;
               default:
                   break;
           }
           break;
       }
       default:
           break;
   }
   return settings.unsupportSetting;
}

@end


@implementation NIMKitSettings

- (instancetype)init:(BOOL)isRight
{
   self = [super init];
   if (self)
   {
       _isRight = isRight;
       [self applyDefaultSettings];
   }
   return self;
}

- (void)applyDefaultSettings
{
   [self applyDefaultTextSettings];
   [self applyDefaultAudioSettings];
   [self applyDefaultVideoSettings];
   [self applyDefaultFileSettings];
   [self applyDefaultImageSettings];
   [self applyDefaultLocationSettings];
   [self applyDefaultTipSettings];
   [self applyDefaultRobotSettings];
   [self applyDefaultUnsupportSettings];
   [self applyDefaultTeamNotificationSettings];
   [self applyDefaultChatroomNotificationSettings];
   [self applyDefaultNetcallNotificationSettings];
}
#pragma mark -文本
- (void)applyDefaultTextSettings
{
   _textSetting = [[NIMKitSetting alloc] init:_isRight];
   _textSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{11,11,9,11}") : UIEdgeInsetsFromString(@"{11,15,9,9}");
   _textSetting.textColor = _isRight? NIMKit_UIColorFromRGB(0x000000) : NIMKit_UIColorFromRGB(0x000000);
   _textSetting.font      = [UIFont systemFontOfSize:16];
   _textSetting.showAvatar = YES;
}
#pragma mark -视频
- (void)applyDefaultVideoSettings
{
   _videoSetting = [[NIMKitSetting alloc] init:_isRight];
   _videoSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{3,3,3,3}") : UIEdgeInsetsFromString(@"{3,3,3,3}");
   _videoSetting.font      = [UIFont systemFontOfSize:15];
   _videoSetting.showAvatar = YES;
}

#pragma mark -图片
- (void)applyDefaultImageSettings
{
   _imageSetting = [[NIMKitSetting alloc] init:_isRight];
   _imageSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{3,3,3,3}") : UIEdgeInsetsFromString(@"{3,3,3,3}");
   _imageSetting.showAvatar = YES;
}
#pragma mark -语音
- (void)applyDefaultAudioSettings
{
   _audioSetting = [[NIMKitSetting alloc] init:_isRight];
   _audioSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{8,12,9,14}") : UIEdgeInsetsFromString(@"{8,13,9,12}");
   _audioSetting.textColor = _isRight? NIMKit_UIColorFromRGB(0x000000) : NIMKit_UIColorFromRGB(0x000000);
   _audioSetting.font      = [UIFont systemFontOfSize:15];
   _audioSetting.showAvatar = YES;
}
#pragma mark -群通知消息
- (void)applyDefaultTeamNotificationSettings
{
   _teamNotificationSetting = [[NIMKitSetting alloc] init:_isRight];
   _teamNotificationSetting.contentInsets = UIEdgeInsetsZero;
   _teamNotificationSetting.textColor = SharedColor.textLightBlack;
   _teamNotificationSetting.font      = [UIFont systemFontOfSize:13];
   _teamNotificationSetting.showAvatar = NO;
   
   //    UIImage *backgroundImage = [[UIImage nim_imageInKit:@"icon_session_time_bg"] resizableImageWithCapInsets:UIEdgeInsetsFromString(@"{8,20,8,20}") resizingMode:UIImageResizingModeStretch];
   //    _teamNotificationSetting.normalBackgroundImage    = backgroundImage;
   //    _teamNotificationSetting.highLightBackgroundImage = backgroundImage;
}

- (void)applyDefaultFileSettings
{
   _fileSetting = [[NIMKitSetting alloc] init:_isRight];
   _fileSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{3,3,3,8}") : UIEdgeInsetsFromString(@"{3,8,3,3}");
   _fileSetting.font      = [UIFont systemFontOfSize:13];
   _fileSetting.showAvatar = YES;
}


- (void)applyDefaultLocationSettings
{
   _locationSetting = [[NIMKitSetting alloc] init:_isRight];
   _locationSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{3,3,3,8}") : UIEdgeInsetsFromString(@"{3,8,3,3}");
   _locationSetting.textColor = SharedColor.textLightBlack;
   _locationSetting.font      = [UIFont systemFontOfSize:13];
   _locationSetting.showAvatar = YES;
}

- (void)applyDefaultTipSettings
{
   _tipSetting = [[NIMKitSetting alloc] init:_isRight];
   _tipSetting.contentInsets = UIEdgeInsetsZero;
   _tipSetting.textColor = SharedColor.textLightBlack;
   _tipSetting.font  = [UIFont systemFontOfSize:13.f];
   _tipSetting.showAvatar = NO;

//    UIImage *backgroundImage = [[UIImage nim_imageInKit:@""] resizableImageWithCapInsets:UIEdgeInsetsFromString(@"{8,20,8,20}") resizingMode:UIImageResizingModeStretch];;
//    _tipSetting.normalBackgroundImage    = backgroundImage;
//    _tipSetting.highLightBackgroundImage = backgroundImage;
}


- (void)applyDefaultRobotSettings
{
   _robotSetting = [[NIMKitSetting alloc] init:_isRight];
   _robotSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{11,11,9,15}") : UIEdgeInsetsFromString(@"{11,15,9,9}");
   _robotSetting.textColor = _isRight? SharedColor.textLightBlack : SharedColor.textLightBlack;
   _robotSetting.font      = [UIFont systemFontOfSize:14];
//    _robotSetting.showAvatar = YES;
}

- (void)applyDefaultUnsupportSettings
{
   _unsupportSetting = [[NIMKitSetting alloc] init:_isRight];
   _unsupportSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{11,11,9,15}") : UIEdgeInsetsFromString(@"{11,15,9,9}");
   _unsupportSetting.textColor = _isRight? SharedColor.textLightBlack : SharedColor.textLightBlack;
   _unsupportSetting.font      = [UIFont systemFontOfSize:13];
   _unsupportSetting.showAvatar = YES;
}



- (void)applyDefaultChatroomNotificationSettings
{
   _chatroomNotificationSetting = [[NIMKitSetting alloc] init:_isRight];
   _chatroomNotificationSetting.contentInsets = UIEdgeInsetsZero;
   _chatroomNotificationSetting.textColor = SharedColor.textLightBlack;
   _chatroomNotificationSetting.font      = [UIFont systemFontOfSize:13];
   _chatroomNotificationSetting.showAvatar = NO;
   UIImage *backgroundImage = [[UIImage nim_imageInKit:@"icon_session_time_bg"] resizableImageWithCapInsets:UIEdgeInsetsFromString(@"{8,20,8,20}") resizingMode:UIImageResizingModeStretch];
   _chatroomNotificationSetting.normalBackgroundImage    = backgroundImage;
   _chatroomNotificationSetting.highLightBackgroundImage = backgroundImage;
}

- (void)applyDefaultNetcallNotificationSettings
{
   _netcallNotificationSetting = [[NIMKitSetting alloc] init:_isRight];
   _netcallNotificationSetting.contentInsets = _isRight? UIEdgeInsetsFromString(@"{11,11,9,15}") : UIEdgeInsetsFromString(@"{11,15,9,9}");
   _netcallNotificationSetting.textColor = _isRight? SharedColor.textLightBlack : SharedColor.textLightBlack;
   _netcallNotificationSetting.font      = [UIFont systemFontOfSize:13];
   _netcallNotificationSetting.showAvatar = YES;
}

@end

NIMSessionViewController 聊天回话页面的父类控制器
NIMKitTitleView 导航了标题View
NIMSessionTimestampCell 时间显示的cell
NIMMessageCell 聊天信息展示的cell
NIMSessionNotificationContentView 群消息提醒展示的contentView
NIMSessionTextContentView 文本展示的contentView
NIMInputView 聊天页面下的输入框
NIMInputToolBar 输入框上的语音 表情 更多按钮显示的地方
NIMCellLayoutConfig cell布局的协议

页面的布局 控制

#import "NIMCellLayoutConfig.h"
#import "NIMSessionMessageContentView.h"
#import "NIMSessionUnknowContentView.h"
#import "M80AttributedLabel+NIMKit.h"
#import "NIMKitUtil.h"
#import "UIImage+NIMKit.h"
#import "NIMMessageModel.h"
#import "NIMBaseSessionContentConfig.h"
#import "NIMKit.h"

@interface NIMCellLayoutConfig()

@end

@implementation NIMCellLayoutConfig

- (CGSize)contentSize:(NIMMessageModel *)model cellWidth:(CGFloat)cellWidth{
    idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];
    return [config contentSize:cellWidth message:model.message];
}

- (NSString *)cellContent:(NIMMessageModel *)model{
    idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];
    NSString *cellContent = [config cellContent:model.message];
    return cellContent.length ? cellContent : @"NIMSessionUnknowContentView";
}


- (UIEdgeInsets)contentViewInsets:(NIMMessageModel *)model{
    idconfig = [[NIMSessionContentConfigFactory sharedFacotry] configBy:model.message];
    return [config contentViewInsets:model.message];
}


- (UIEdgeInsets)cellInsets:(NIMMessageModel *)model
{
    if ([[self cellContent:model] isEqualToString:@"NIMSessionNotificationContentView"]) {
        return UIEdgeInsetsZero;
    }
    CGFloat cellTopToBubbleTop           = 3;
    CGFloat otherNickNameHeight          = 20;
    CGFloat otherBubbleOriginX           = [self shouldShowAvatar:model]? 55 : 0;
    CGFloat cellBubbleButtomToCellButtom = 13;
    
    if ([self shouldShowNickName:model])
    {
        //要显示名字
        return UIEdgeInsetsMake(cellTopToBubbleTop + otherNickNameHeight ,otherBubbleOriginX,cellBubbleButtomToCellButtom, 0);
    }
    else
    {
        return UIEdgeInsetsMake(cellTopToBubbleTop,otherBubbleOriginX,cellBubbleButtomToCellButtom, 0);
    }
    
}

- (BOOL)shouldShowAvatar:(NIMMessageModel *)model
{
    return [[NIMKit sharedKit].config setting:model.message].showAvatar;
}


- (BOOL)shouldShowNickName:(NIMMessageModel *)model{
    NIMMessage *message = model.message;
    if (message.messageType == NIMMessageTypeNotification)
    {
        NIMNotificationType type = [(NIMNotificationObject *)message.messageObject notificationType];
        if (type == NIMNotificationTypeTeam) {
            return NO;
        }
    }
    if (message.messageType == NIMMessageTypeTip) {
        return NO;
    }
    return (!message.isOutgoingMsg && message.session.sessionType == NIMSessionTypeTeam);
}


- (BOOL)shouldShowLeft:(NIMMessageModel *)model
{
    return !model.message.isOutgoingMsg;
}

- (CGPoint)avatarMargin:(NIMMessageModel *)model
{
    return CGPointMake(8.f, 0.f);
}

- (CGSize)avatarSize:(NIMMessageModel *)model
{
    return CGSizeMake(42, 42);
}

- (CGPoint)nickNameMargin:(NIMMessageModel *)model
{
    return [self shouldShowAvatar:model] ? CGPointMake(57.f, -3.f) : CGPointMake(10.f, -3.f);
}


- (NSArray *)customViews:(NIMMessageModel *)model
{
    return nil;
}

- (BOOL)disableRetryButton:(NIMMessageModel *)model
{
    if (!model.message.isReceivedMsg)
    {
        return model.message.deliveryState != NIMMessageDeliveryStateFailed;
    }
    else
    {
        return model.message.attachmentDownloadState != NIMMessageAttachmentDownloadStateFailed;
    }
}

@end

NIMInputAudioRecordIndicatorView 录音提示View

NIMSessionMsgDatasource 云信下拉改为请求云记录消息

在 NIMSessionMsgDatasource.m 中做修改 云信下拉改为请求云记录消息

#pragma mark - answer 在此修改
- (void)loadHistoryMessagesWithComplete:(void(^)(NSInteger index, NSArray *messages , NSError *error))handler{
   
    __block NIMMessageModel *currentOldestMsg = nil;

    [self.items enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if ([obj isKindOfClass:[NIMMessageModel class]]) {
            currentOldestMsg = (NIMMessageModel*)obj;
            *stop = YES;
        }
    }];
    

    __block  NSInteger index = 0;


    if ([self.dataProvider respondsToSelector:@selector(pullDown:handler:)])
    {
        __weak typeof(self) wself = self;
        [self.dataProvider pullDown:currentOldestMsg.message handler:^(NSError *error, NSArray *messages) {
            NIMKit_Dispatch_Async_Main(^{
                NSInteger index = [wself insertMessages:messages];
                if (handler) {
                    handler(index,messages,error);
                }
            });
        }];
        return;

    }else{

#warning  在此修改
        
        NIMHistoryMessageSearchOption *searchOpt = [[NIMHistoryMessageSearchOption alloc] init];
        searchOpt.startTime  = 0;
        searchOpt.endTime    = currentOldestMsg.message.timestamp;
        searchOpt.currentMessage = currentOldestMsg.message;
        searchOpt.limit      = self.messageLimit;
        searchOpt.sync       =  YES;
        [[NIMSDK sharedSDK].conversationManager fetchMessageHistory:_currentSession option:searchOpt result:^(NSError *error, NSArray *messages) {
        
            if (!error) {
                
                NSArray *array = [messages sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
                    
                    NIMMessage *hm1 = (NIMMessage *)obj1;
                    NIMMessage *hm2 = (NIMMessage *)obj2;
                    
                    if (hm1.timestamp > hm2.timestamp) {
                    
                         return NSOrderedDescending;
                        
                    }else {
                        
                        return NSOrderedAscending;
                       
                    }
                
                }];
                
                index = [self insertMessages:array];
                
                if (handler) {
                    NIMKit_Dispatch_Async_Main(^{
                        handler(index,messages,nil);
                        
                        [self postNotification:@"loadHistoryMessages"];
                        
                        
                    });
                }
                
                
            }
    
        }];
    
        //        NSArray *messages = [[[NIMSDK sharedSDK] conversationManager] messagesInSession:_currentSession
        //                                                                                message:currentOldestMsg.message
        //                                                                                  limit:self.messageLimit];
        //        index = [self insertMessages:messages];
        //        if (handler) {
        //            NIMKit_Dispatch_Async_Main(^{
        //                handler(index,messages,nil);
        //            });
        //        }
    }

}

5.接下来重点来 自定义消息 以及自定义消息布局

首先在AppDelegate中 注册
//自定义消息布局
[[NIMKit sharedKit] registerLayoutConfig:[TimingCellLayoutConfig new]];
//自定义消息对象序列化
[NIMCustomObject registerCustomDecoder:[[TimingCustomAttachmentDecoder alloc] init]];

TimingCustomAttachmentDecoder自定义消息解析器

#import "TimingCustomAttachmentDecoder.h"
#import "TimingCustomAttachmentDefines.h"
#import "TCustomInvitedIntoTeamAttachment.h"
#import "TimingCustomAttachment.h"

@implementation TimingCustomAttachmentDecoder

- (id)decodeAttachment:(NSString *)content
{
    id attachment = nil;
    
    NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding];
    if (data) {
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data
                                                             options:0
                                                             error:nil];
        if ([dict isKindOfClass:[NSDictionary class]])
        {
            NSInteger type  = [dict jsonInteger:TimingType];
            
            switch (type) {
                  
                case CustomMessageTypeInvitedIntoTeam:{//邀请进群
                    
                    attachment = [[TCustomInvitedIntoTeamAttachment alloc] init];
                    
                     ((TCustomInvitedIntoTeamAttachment *)attachment).type = [dict jsonInteger:@"type"];
                    
                    ((TCustomInvitedIntoTeamAttachment *)attachment).titleStr = [dict jsonString:@"titleStr"];
                    
                    ((TCustomInvitedIntoTeamAttachment *)attachment).teamType = [dict jsonInteger:@"teamType"];
                    
                    ((TCustomInvitedIntoTeamAttachment *)attachment).contentStr = [dict jsonString:@"contentStr"];
                    
                    ((TCustomInvitedIntoTeamAttachment *)attachment).imageUrl = [dict jsonString:@"imageUrl"];
                    
                    ((TCustomInvitedIntoTeamAttachment *)attachment).groupID = [dict jsonInteger:@"groupID"];
                    
                    ((TCustomInvitedIntoTeamAttachment *)attachment).teamID = [dict jsonString:@"teamID"];
                    
                }
                    break;
                
            }
            
        }
        
    }
    
    return attachment;
    
}

@end
ifndef TimingCustomAttachmentDefines_h
#define TimingCustomAttachmentDefines_h

typedef NS_ENUM(NSInteger,TimingCustomMessageType){
    
    CustomMessageTypeImageAndTitle = 1,//图片和文字一起
    CustomMessageTypeInvitedIntoTeam = 2,//邀请进群
    
    
};

#define TimingType  @"type"

//手势点击方法
#define TimingCustomImageAndTitleTouch @"TimingCustomImageAndTitleTouch"
#define CustomImageAndTitleTapTitleLablel @"TapTitleLablel"
#define CustomImageAndTitleTapSubTitleLablel @"TapSubTitleLablel"

#define TimingCustomInviteGroupTouch @"TimingCustomInviteGroupTouch"

#endif /* TimingCustomAttachmentDefines_h */

自定义消息的模型类 TCustomInvitedIntoTeamAttachment
TCustomInvitedIntoTeamAttachment.h

#import 
#import "TimingCustomAttachmentDefines.h"

//邀请进群的自定义消息
@interface TCustomInvitedIntoTeamAttachment : NSObject

@property (nonatomic,copy) NSString *titleStr;
@property (nonatomic,assign)NSInteger teamType;
@property (nonatomic,copy) NSString *contentStr;
@property(nonatomic,copy)  NSString *imageUrl;
@property (nonatomic,assign)NSInteger groupID;

@property(nonatomic,copy)  NSString *teamID;
@property (nonatomic,assign)NSInteger type;

-(NIMMessage *)assembleMessage;

@end

TCustomInvitedIntoTeamAttachment.m

#import "TCustomInvitedIntoTeamAttachment.h"

@implementation TCustomInvitedIntoTeamAttachment

- (NSString *)encodeAttachment
{
    NSDictionary *dict = @{
                           TimingType:@(CustomMessageTypeInvitedIntoTeam),
                           @"titleStr":self.titleStr?self.titleStr:@"",
                           @"teamType" :@(self.teamType),
                           @"contentStr":self.contentStr?self.contentStr:@"",
                           @"imageUrl":self.imageUrl?self.imageUrl:@"",
                           @"groupID":self.groupID?@(self.groupID):@"",
                           @"teamID":self.teamID?self.teamID:@"",
                           };
    
    NSData *data = [NSJSONSerialization dataWithJSONObject:dict
                                                   options:0
                                                     error:nil];
    NSString *content = nil;
    
    if (data) {
        content = [[NSString alloc] initWithData:data
                                        encoding:NSUTF8StringEncoding];
    }
    return content;
}
#pragma mark -拼装消息
-(NIMMessage *)assembleMessage{
    
    NIMCustomObject *object = [[NIMCustomObject alloc] init];
    object.attachment    = self;
    
    NIMMessage *message       = [[NIMMessage alloc] init];
    message.messageObject = object;
    
    NIMMessageSetting *setting = [[NIMMessageSetting alloc] init];
    setting.apnsEnabled        = YES;
    setting.shouldBeCounted    = YES;
    
    message.setting            = setting;
    
    
    //用messageObject判断不了 直接用apnsPayload字典
    NSDictionary *dict = @{
                           TimingType:@(CustomMessageTypeInvitedIntoTeam),
                           @"titleStr":self.titleStr?self.titleStr:@"",
                           @"teamType" :@(self.teamType),
                           @"contentStr":self.contentStr?self.contentStr:@"",
                           @"imageUrl":self.imageUrl?self.imageUrl:@"",
                           @"groupID":@(self.groupID),
                           @"teamID":self.teamID?self.teamID:@"",
                           };
    
    message.apnsPayload = dict;
    
    
    return message;
    
}
@end

自定义消息的View
NIMSessionMessageContentView.h

#import "NIMSessionMessageContentView.h"
#import "TCustomInvitedIntoTeamAttachment.h"

@interface TCustomInvitedIntoTeamContentView : NIMSessionMessageContentView

@property (nonatomic, strong) UILabel *lblTitle;//标题
@property (nonatomic, strong) UIImageView *ivType;//群类型
@property (nonatomic, strong) UILabel *lblContent;//内容
@property (nonatomic, strong) UIImageView *ivTeam;//群图像

@property (nonatomic, strong) TCustomInvitedIntoTeamAttachment *attachment;

@end

NIMSessionMessageContentView.m

#import "TCustomInvitedIntoTeamContentView.h"
#import "UIView+NIM.h"
#import "TimingCustomAttachmentDefines.h"

@implementation TCustomInvitedIntoTeamContentView
{
    
    UILabel *_lblname;
    UIView  *_viewBack;
    
}
- (instancetype)initSessionMessageContentView{
    
    self = [super initSessionMessageContentView];
    
    if (self) {
        
        
        [self setUpView];
        
    }
    
    return self;
}
-(void)setUpView{
   
    
    _lblname = [UILabel new];
    [self addSubview:_lblname];
    _lblname.textColor = [UIColor blackColor];
    _lblname.font = [UIFont systemFontOfSize:16];
    [_lblname mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(self).offset(15);
        make.leading.equalTo(self).offset(12);
        make.width.equalTo(@222);
        make.height.equalTo(@14);
    }];
    
    
    _viewBack = [UIView new];
    _viewBack.clipsToBounds = YES;
    _viewBack.layer.cornerRadius = 5;
    _viewBack.backgroundColor = [UIColor whiteColor];
    _viewBack.layer.borderWidth = 0.5;
    _viewBack.userInteractionEnabled = NO;
    [self addSubview:_viewBack];
    
    [_viewBack mas_makeConstraints:^(MASConstraintMaker *make) {
        
        make.height.equalTo(@58);
        make.leading.equalTo(self).offset(12);
        make.trailing.equalTo(self).offset(-20);
        make.bottom.equalTo(self).offset(-18);
        
    }];
    

    //群成员图像
    _ivTeam = [UIImageView new];
    _ivTeam.clipsToBounds = YES;
    _ivTeam.layer.cornerRadius = 5;
    [_viewBack addSubview:_ivTeam];
    
    [_ivTeam mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.width.height.equalTo(@30);
        make.centerY.equalTo(_viewBack.mas_centerY);
        make.trailing.equalTo(_viewBack).offset(-10);
    
    }];
    
    
    //标题
    _lblTitle = [UILabel new];
    [_viewBack addSubview:_lblTitle];
    _lblTitle.textColor = [UIColor blackColor];
    _lblTitle.font = [UIFont systemFontOfSize:15];
    [_lblTitle mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(_viewBack).offset(12);
        make.leading.equalTo(_viewBack).offset(10);
        make.width.mas_lessThanOrEqualTo(@120);
        make.height.equalTo(@13);
    }];
    
    //群类型
    _ivType = [UIImageView new];
    [_viewBack addSubview:_ivType];
    [_ivType mas_makeConstraints:^(MASConstraintMaker *make) {
        make.centerY.equalTo(_lblTitle.mas_centerY);
        make.leading.equalTo(_lblTitle.mas_trailing).offset(5);
        make.height.equalTo(@17);
        make.width.equalTo(@35);
    }];
    
    //信息内容
    _lblContent = [UILabel new];
    [_viewBack addSubview:_lblContent];
    _lblContent.textColor = SharedColor.textLightBlack;
    _lblContent.font = [UIFont systemFontOfSize:14];
    [_lblContent mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.equalTo(_lblTitle.mas_bottom).offset(8);
        make.leading.equalTo(_viewBack).offset(10);
        make.width.equalTo(@158);
    }];
    
    
    
    
}
- (void)refresh:(NIMMessageModel*)data{
    //务必调用super方法
    [super refresh:data];
    
    NIMCustomObject *object = (NIMCustomObject *)data.message.messageObject;
    TCustomInvitedIntoTeamAttachment *attachment = (TCustomInvitedIntoTeamAttachment *)object.attachment;
    
    _attachment = attachment;
    
    self.lblTitle.text = attachment.titleStr;
    
    
    switch (attachment.teamType) {
        case 1:{
            
            [self.ivType setImage:[UIImage imageNamed:@"team_share_normal"]];
        }
            
            break;
        case 2:{
           [self.ivType setImage:[UIImage imageNamed:@"team_share_clock"]];
        }
            
            break;
        case 3:{
            
           [self.ivType setImage:[UIImage imageNamed:@"team_share_delegate"]];
        }
            
            break;
            
        default:
            break;
    }
    self.lblContent.text = attachment.contentStr;
    
    [self.ivTeam yy_setImageWithURL:[NSURL URLWithString:attachment.imageUrl] placeholder:[UIImage imageNamed:@"user_bg_icon"]];
    
    NIMMessage *message = data.message;
    
    if (message.isOutgoingMsg) {
    
        _lblname.text = @"邀请道友入群";
        
        [_lblname mas_remakeConstraints:^(MASConstraintMaker *make) {
            
            make.top.equalTo(self).offset(15);
            make.leading.equalTo(self).offset(12);
            make.width.equalTo(@222);
            make.height.equalTo(@14);
            
        }];
        
        [_viewBack mas_remakeConstraints:^(MASConstraintMaker *make) {
            
            make.height.equalTo(@58);
            make.leading.equalTo(self).offset(12);
            make.trailing.equalTo(self).offset(-20);
            make.bottom.equalTo(self).offset(-18);
            
        }];
        
        _viewBack.layer.borderColor = [UIColor whiteColor].CGColor;
        
        
    
    }else{
        
        
        _viewBack.layer.borderColor = TIMINGCOLOR(234, 228, 222, 1).CGColor;
        
        
        _lblname.text = @"邀请你入群";
        
        [_lblname mas_remakeConstraints:^(MASConstraintMaker *make) {
            
            make.top.equalTo(self).offset(15);
            make.leading.equalTo(self).offset(15);
            make.width.equalTo(@222);
            make.height.equalTo(@14);
            
        }];
        
        [_viewBack mas_remakeConstraints:^(MASConstraintMaker *make) {
            
            make.height.equalTo(@58);
            make.leading.equalTo(self).offset(15);
            make.trailing.equalTo(self).offset(-16);
            make.bottom.equalTo(self).offset(-18);
            
        }];
        
        
    }
    

}

#pragma mark - 气泡
- (UIImage *)chatBubbleImageForState:(UIControlState)state outgoing:(BOOL)outgoing
{
    
    NIMKitSetting *setting = [[NIMKit sharedKit].config setting:self.model.message];
    
    if (state == UIControlStateNormal)
    {
        return setting.normalBackgroundImage;
    }
    else
    {
        return setting.highLightBackgroundImage;
    }
    
}

/**
 *  手指从contentView内部抬起
 */
- (void)onTouchUpInside:(id)sender
{
    NIMKitEvent *event = [[NIMKitEvent alloc] init];
    event.eventName = TimingCustomInviteGroupTouch;
    event.messageModel = self.model;
    event.attachment = _attachment;
    [self.delegate onCatchEvent:event];
    
    
}
/**
 *  手指从contentView外部抬起
 */
- (void)onTouchUpOutside:(id)sender{
    
    [super onTouchUpOutside:sender];
}

/**
 *  手指按下contentView
 */
- (void)onTouchDown:(id)sender{
    
    [super onTouchDown:sender];
}
@end

在实现自定义消息布局的协议 NIMCellLayoutConfig
NIMCellLayoutConfig.h

#import "NIMCellLayoutConfig.h"
@interface TimingCellLayoutConfig : NIMCellLayoutConfig

@end

NIMCellLayoutConfig.m

#import "TimingCellLayoutConfig.h"
#import "TimingCustomAttachment.h"
#import "TCustomInvitedIntoTeamAttachment.h"


@implementation TimingCellLayoutConfig
#pragma mark -构造的cellContent类名
- (NSString *)cellContent:(NIMMessageModel *)model{
    
    NIMMessage *message = model.message;
    //填入contentView类型
    if (message.messageType == NIMMessageTypeCustom) {
        NIMCustomObject *object = (NIMCustomObject *)message.messageObject;
        //邀请入群
        if ([object.attachment isKindOfClass:[TCustomInvitedIntoTeamAttachment class]]) {
            return @"TCustomInvitedIntoTeamContentView";
        }
        
    }
    
    //如果不是自己定义的消息,就走内置处理流程
    return [super cellContent:model];
}

#pragma mark -返回message的内容大小
- (CGSize)contentSize:(NIMMessageModel *)model cellWidth:(CGFloat)width{
    
     NIMMessage *message = model.message;
    if (message.messageType == NIMMessageTypeCustom) {
        NIMCustomObject *object = (NIMCustomObject *)message.messageObject;
    
        //邀请入群
        if ([object.attachment isKindOfClass:[TCustomInvitedIntoTeamAttachment class]]) {
            
             return CGSizeMake(251.5, 120);
        }
        
    }
    //如果不是自己定义的消息,就走内置处理流程
    return [super contentSize:model cellWidth:width];
            
}

#pragma mark - cell气泡距离整个cell的内间距
- (UIEdgeInsets)cellInsets:(NIMMessageModel *)model{
    
    NIMMessage *message = model.message;
    //填入气泡距cell的边距,选填
    if (message.messageType == NIMMessageTypeCustom) {
        NIMCustomObject *object = (NIMCustomObject *)message.messageObject;
        
        //邀请入群
        if ([object.attachment isKindOfClass:[TCustomInvitedIntoTeamAttachment class]]) {
            
            if (model.message.isOutgoingMsg) {
                
                return UIEdgeInsetsMake(25, 10, 22, 75);
                
            }else{
                
                //有昵称是距上30
                return UIEdgeInsetsMake(25, 60, 22, 10);
            }
        }
        
    }
    
    //如果不是自己定义的消息,就走内置处理流程
    return [super cellInsets:model];
}
#pragma mark - ContentView内容 距离气泡的内间距
- (UIEdgeInsets)contentViewInsets:(NIMMessageModel *)model{
    
    NIMMessage *message = model.message;
    
    if (message.messageType == NIMMessageTypeCustom) {
        NIMCustomObject *object = (NIMCustomObject *)message.messageObject;
        
        //邀请入群
        if ([object.attachment isKindOfClass:[TCustomInvitedIntoTeamAttachment class]]) {
            
            return UIEdgeInsetsMake(0, 0, 0, 0);

        }
        
    }
    //如果不是自己定义的消息,就走内置处理流程
    return [super contentViewInsets:model];
}

#pragma mark -昵称的位置
- (CGPoint)nickNameMargin:(NIMMessageModel *)model{
    
//    NIMMessage *message = model.message;
//
//    if (message.messageType == NIMMessageTypeCustom) {
//        NIMCustomObject *object = (NIMCustomObject *)message.messageObject;
//
//        //邀请入群
//        if ([object.attachment isKindOfClass:[TCustomInvitedIntoTeamAttachment class]]) {
//
//            if (model.message.isOutgoingMsg) {
//
//                return CGPointMake(30.f, 0.f);
//
//            }else{
//
//                //有昵称是距上
//                return CGPointMake(60.f, 0.f);
//            }
//        }
//        
//    }
    return [super nickNameMargin:model];
}


#pragma mark-是否取消重试按钮
- (BOOL)disableRetryButton:(NIMMessageModel *)model
{
    NIMMessage *message = model.message;
    //填入contentView类型
    if (message.messageType == NIMMessageTypeCustom) {
        NIMCustomObject *object = (NIMCustomObject *)message.messageObject;
        
        //邀请入群
        if ([object.attachment isKindOfClass:[TCustomInvitedIntoTeamAttachment class]]) {
            
            return YES;
            
        }
        
    }
    
    return [super disableRetryButton:model];
}
- (NSArray *)customViews:(NIMMessageModel *)model
{
    
    return [super customViews:model];
    
}
#pragma mark -是否展示图像
- (BOOL)shouldShowAvatar:(NIMMessageModel *)model
{
    
    return [super shouldShowAvatar:model];
}
#pragma mark -是否展示昵称
- (BOOL)shouldShowNickName:(NIMMessageModel *)model{
    
    NIMMessage *message = model.message;
    //填入contentView类型
    if (message.messageType == NIMMessageTypeCustom) {
        NIMCustomObject *object = (NIMCustomObject *)message.messageObject;
        
        //邀请入群
        if ([object.attachment isKindOfClass:[TCustomInvitedIntoTeamAttachment class]] && (message.session.sessionType == NIMSessionTypeTeam)) {
            
            return YES;
            
        }
        
    }
    
    if (message.session.sessionType == NIMSessionTypeTeam) {
        
        return YES;
    }
    
    return [super shouldShowNickName:model];
}

@end

自定义消息效果图:


iOS 云信IM 遇到的坑_第1张图片
IMG_4452.PNG

iOS 云信IM 遇到的坑_第2张图片
图片发自App
iOS 云信IM 遇到的坑_第3张图片
图片发自App
iOS 云信IM 遇到的坑_第4张图片
图片发自App

读者如有疑问可以给博主留言 或者加QQ 1256454781 随便点个赞呗 谢谢
顺便分享一下云信内部技术文档 http://faq.netease.im/#KB0014

你可能感兴趣的:(iOS 云信IM 遇到的坑)