IM消息收发

接收消息
接口设计

如果需要感知新消息的通知,可以注册消息通知回调IIMMsgListener。新消息到来时,onNewMsg方法将被调用。当某条消息被撤回时,onMsgRevoked方法将被调用。

/**监听消息事件 */
@protocol IIMMsgListener 

/**
 * 收到新消息
 * @msgList      新消息列表
 */
- (void)onNewMsg:(NSArray *)msgList;

/**
 * 消息被撤回
 * @msg 被撤回的消息
 */
- (void)onMsgRevoked:(IMBaseMessage *)msg;

@end

在AppMsgManager里面,提供了注册消息监听和移除消息监听的接口

/** 监听全局的消息事件 */
- (void)addMsgListener:(id)listener;
/** 取消监听 */
- (void)removeMsgListener:(id)listener;

为了方便使用,把onNewMsg和onMsgRevoked两个消息回调接口封装成Block的方式使用,因此可直接使用IMMsgListerner作为监听者。

typedef void(^NewMsg)(NSArray *); //收到新消息Block
typedef void(^MsgRevoked)(IMBaseMessage *);  // 收到消息撤回通知Block

@interface IMMsgListener : NSObject 

- (instancetype)initWithNewMsgBlock:(NewMsg)newMsgBlock revokedMsgBlock:(MsgRevoked)revokedMsgBolck;

@end
接口实现

在AppMsgManager里面进行消息的中转和改装,listenerList维护者监听者列表
onNewMessage:

- (void)onNewMessage:(NSArray *)msgs
{
    NSMutableArray *msgList =  [NSMutableArray array];
    
    // 消息格式换转
    for (TIMMessage *msg in msgs){
        IMBaseMessage *baseMsg = [TimMsgUtil convertMsgFromTIMToIM:msg];
        [msgList addObject:baseMsg];
    }
    
    // 通知注册者数据到来
    [_listenerList enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [obj onNewMsg:msgList];
    }];
}

onMessageRevoke

- (void)onMessageRevoke:(TIMMessageLocator*)locator
{
     IMSession *session = [IMSession IMSessionWithSessionId:locator.sessId type:locator.sessType];
     IMMessageStruct *msgBody = [[IMMessageStruct alloc] initWithType:0 seq:locator.seq elems:nil];
    
     IMBaseMessage *baseMsg = [IMBaseMessage IMBaseMessageWithSenderUid:nil session:session msg:msgBody];
    
    [_listenerList enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        [obj onMsgRevoked:baseMsg];
    }];
}

消息转换需要自行去TimMsgUtil添加转换处理:

  • IMBaseMessage转TIMMessage(以IMFileMsgElem转TimFileElem为例)
if([msgElem getType] == IM_FILE_TYPE)
 {
     IMFileMsgElem *fileElem = (IMFileMsgElem *)msgElem;
            
     TIMFileElem *elem = [[TIMFileElem alloc] init];
     elem.filename = fileElem.fileName;
     elem.fileSize = (int)fileElem.fileSize;
     elem.path     = fileElem.url;
            
     [timMsg addElem:elem];
}
  • TIMMessage转IMBaseMessage(以TimCustomElem转IMBaseMessage为例)
    得到IMCustomMsgElem后在根据它得ElemType进行第二层的PB解析,得到需要的IMElem
if ([timElem isKindOfClass:[TIMCustomElem class]])
{
    TIMCustomElem *custonElem = (TIMCustomElem *)timElem;
    
    // 两层PB解析
    IMCustomMsgElem *customElem = (IMCustomMsgElem *)[PBCoder decodeObjectOfClass:[IMCustomMsgElem class] fromData:custonElem.data];
    
    if(customElem.elemType == IM_FILE_TYPE)
    {
        NSData *elemData = (NSData *)customElem.elemData;
        IMFileMsgElem *fileElem = (IMFileMsgElem *)[PBCoder decodeObjectOfClass:[IMFileMsgElem class] fromData:elemData];
        
        [msgElems addObject:fileElem];
    }
}
上层调用
IMMsgListener *msgListener = [[IMMsgListener alloc] initWithNewMsgBlock:^(NSArray * _Nonnull msgList) {
        NSLog(@"收到新消息");
    } revokedMsgBlock:^(IMBaseMessage * _Nonnull msg) {
        NSLog(@"收到消息撤回通知");
    }];
    
id msgService = [[JSObjection defaultInjector] getObject:@protocol(IIMAppMsgService)];
id msgManager = [msgService getMessageMgr];

[msgManager addMsgListener:msgListener];
样例

由于消息转换不完全,因此消息状态会有点问题。

  1. 收到文本消息

    收到文本消息
  2. 收到自定义消息(文件)

    收到自定义消息
自定义消息收发

如果你不满足于发送文字和图片,那么你可以发送自定义的消息。发送自定义消息时,将以IMCustomMsgElem为载体,打包我们要发送的数据。

@interface IMCustomMsgElem : NSObject

/**自定义Elem类型*/
@property(nonatomic, assign) uint32_t elemType;

/**自定义Elem的数据*/
@property(nonatomic, strong) NSData *elemData;

@end
属性 类型 说明
elemType uint32_t 自定义Elem的类型
elemData NSData 自定义Elem的数据内容
使用事例
  1. 自定义IMFileMsgElem
@interface IMFileMsgElem : NSObject 

/** 文件名 */
@property(nonatomic, strong) NSString *fileName;
/** 文件大小 */
@property(nonatomic, assign) uint64_t fileSize;
/** 文件路径 */
@property(nonatomic, strong) NSString *url;

@end
  1. 使用PB协议指定要解析的字段
@implementation IMFileMsgElem
PBCODER_TABLE_BEGIN(IMFileMsgElem)
PBCODER_OBJ_PROPERTY(IMFileMsgElem, fileName, NSString, 1) //解析文件名字段
PBCODER_UINT64_PROPERTY(IMFileMsgElem, fileSize, 2) //解析文件大小字段
PBCODER_OBJ_PROPERTY(IMFileMsgElem, url, NSString, 3) //解析文件路径字段
PBCODER_TABLE_END(IMFileMsgElem)
@end
  1. 重写toByteArray方法
-(NSData *)toByteArray
{
    return [PBCoder encodeDataWithObject:self];
}
  1. 发送自定义消息,自定义消息类型将通过toByteArray函数转换成NSData,最后将包装成IMCustomMsgElem进行发送。
// 自定义消息类型创建
IMFileMsgElem *fileElem = [[IMFileMsgElem alloc] init];
fileElem.url = filePath;
fileElem.fileName = filePath;
fileElem.fileSize = 5000;

// 将自定义消息类型包装成IMCustonMsgElem
IMCustomMsgElem *customElem = [[IMCustomMsgElem alloc] init];
customElem.elemType = IM_FILE_TYPE;
customElem.elemData = fileElem.toByteArray;   // 将数据塞给IMCustomMsgElem的elemData
IMMessageStruct *msgBody = [[IMMessageStruct alloc] initWithType:IM_FILE_TYPE seq:0 elems:@[customElem]];

// 构建通用消息体
IMBaseMessage *imMsg = [[IMBaseMessage alloc] initWithSenderUid:@"" session:nil msg:msgBody];

imMsg.session = [[IMSession alloc] init];
imMsg.session.sessionId = _conversation.receiver;
imMsg.session.type = _conversation.type;

// 获取IIMAppMsgManager接口实例
id msgService = [[JSObjection defaultInjector] getObject:@protocol(IIMAppMsgService)];
id msgMgr = [msgService getMessageMgr];

// 发消息
[msgMgr sendMsg:imMsg callback:nil];
  1. 自定义消息的解析
if ([timElem isKindOfClass:[TIMCustomElem class]])
{
    TIMCustomElem *custonElem = (TIMCustomElem *)timElem;
    
    // 两层PB解析
    IMCustomMsgElem *customElem = (IMCustomMsgElem *)[PBCoder decodeObjectOfClass:[IMCustomMsgElem class] fromData:custonElem.data];
    
    if(customElem.elemType == IM_FILE_TYPE)
    {
        NSData *elemData = (NSData *)customElem.elemData;
        IMFileMsgElem *fileElem = (IMFileMsgElem *)[PBCoder decodeObjectOfClass:[IMFileMsgElem class] fromData:elemData];
        
        [msgElems addObject:fileElem];
    }
}

// 获取IIMAppMsgManager接口实例
id msgService = [[JSObjection defaultInjector] getObject:@protocol(IIMAppMsgService)];
id msgMgr = [msgService getMessageMgr];

你可能感兴趣的:(IM消息收发)