- Android
- iOS
- JavaScript
- Flutter
- ReactNative
- HarmonyOS
Message Listeners
You can register multiple listeners.
JIM.getInstance().getMessageManager().addListener("main", new IMessageManager.IMessageListener() {
/// message-receive callback
@Override
public void onMessageReceive(Message message) {
Log.d("TAG", "onMessageReceive, conversationType is " + message.getConversation().getConversationType() + ", conversationId is " + message.getConversation().getConversationId());
MessageContent content = message.getContent();
if (content instanceof TextMessage) {
Log.d("TAG", "text did receive, content is " + ((TextMessage) content).getContent());
} else if (content instanceof ImageMessage) {
Log.d("TAG", "image did receive, url is " + ((ImageMessage) content).getUrl());
} else if (content instanceof FileMessage) {
Log.d("TAG", "file did receive, name is " + ((FileMessage) content).getName());
} else if (content instanceof VoiceMessage) {
Log.d("TAG", "voice did receive");
}
}
/// message-recall callback
@Override
public void onMessageRecall(Message message) {
Log.d("TAG", "onMessageRecall, messageId is " + message.getMessageId());
}
/// message-update callback
@Override
public void onMessageUpdate(Message message) {
Log.d("TAG", "onMessageUpdate, messageId is " + message.getMessageId());
}
/// message-delete callback
/// conversation: conversation identifier
/// clientMsgNos: list of unique local message numbers
@Override
public void onMessageDelete(Conversation conversation, List<Long> clientMsgNos) {
Log.d("TAG", "onMessageDelete, conversation is " + conversation.getConversationId() + ", clientMsgNo is " + clientMsgNos);
}
/// callback triggered when all messages before a specified time in a conversation are cleared
/// conversation: conversation identifier
/// timestamp: timestamp in milliseconds; messages before timestamp are cleared
/// senderId: if non-empty, only messages sent by senderId are cleared
@Override
public void onMessageClear(Conversation conversation, long timestamp, String senderId) {
Log.d("TAG", "onMessageClear, conversation is " + conversation.getConversationId() + ", timestamp is " + timestamp + ", senderId is " + senderId);
}
/// callback triggered when a message reaction is added
/// conversation: containing conversation
/// reaction: added message reaction
@Override
public void onMessageReactionAdd(Conversation conversation, MessageReaction reaction) {
}
/// callback triggered when a message reaction is removed
/// conversation: containing conversation
/// reaction: removed message reaction
void onMessageReactionRemove(Conversation conversation, MessageReaction reaction) {
}
/// callback triggered when a message is pinned or unpinned
/// message: corresponding message
/// operator: user who performed the pin operation
/// isTop: true false indicates unpinning
void onMessageSetTop(Message message, UserInfo operator, boolean isTop) {
}
});
Message Read-Status Listeners
You can register multiple listeners.
JIM.getInstance().getMessageManager().addReadReceiptListener("main", new IMessageManager.IMessageReadReceiptListener() {
/// private chat message read callback
/// conversation: containing conversation
/// messageIds: message ID array
@Override
public void onMessagesRead(Conversation conversation, List<String> messageIds) {
Log.d("TAG", "onMessageRead, count is " + messageIds.size() + ", conversationType is " + conversation.getConversationType() + ", conversationId is " + conversation.getConversationId());
}
/// group-message read callback
/// conversation: containing conversation
/// messages: messageId is the key
@Override
public void onGroupMessagesRead(Conversation conversation, Map<String, GroupMessageReadInfo> messages) {
Log.d("TAG", "onGroupMessagesRead, conversationType is " + conversation.getConversationType() + ", id is " + conversation.getConversationId() + ", count is " + messages.size());
}
});
Message Destruction Listeners
You can register multiple listeners.
JIM.getInstance().getMessageManager().addDestroyListener("main", new IMessageManager.IMessageDestroyListener() {
/**
* callback triggered when a message's destruction time changes (typically for burn-after-reading)
* @param messageId message ID
* @param conversation containing conversation
* @param destroyTime updated destruction time
*/
@Override
public void onMessageDestroyTimeUpdate(String messageId, Conversation conversation, long destroyTime) {
}
});
Message Encryption and Decryption Callback
Only one message encryption and decryption listener can be configured.
JIM.getInstance().getMessageManager().setPreprocessor(new IMessageManager.IMessagePreprocessor() {
/**
* message-encryption callback
* callback timing: after the message is stored and before it is sent
* @param content message content to send, serialized as byte[]
* @param conversation containing conversation
* @param contentType message type
* @return processed message content.
*/
@Override
public byte[] encryptMessageContent(byte[] content, Conversation conversation, String contentType) {
}
/**
* message-decryption callback
* callback timing: after receiving the message and before storing it
* @param content received message content as byte[], not yet deserialized
* @param conversation containing conversation
* @param contentType message type
* @return processed message content.
*/
@Override
public byte[] decryptMessageContent(byte[] content, Conversation conversation, String contentType) {
}
});
Message Event Listeners
You can register multiple delegates.
[JIM.shared.messageManager addDelegate:self];
/// message-receive callback
- (void)messageDidReceive:(JMessage *)message {
NSLog(@"messageDidReceive conversationType is %d, conversationId is %@", message.conversation.conversationType, message.conversation.conversationId);
JMessageContent *content = message.content;
if ([content isKindOfClass:[JTextMessage class]]) {
NSLog(@"text messageDidReceive, content is %@", ((JTextMessage *)content).content);
} else if ([content isKindOfClass:[JImageMessage class]]) {
NSLog(@"image messageDidReceive, url is %@", ((JImageMessage *)content).url);
} else if ([content isKindOfClass:[JFileMessage class]]) {
NSLog(@"file messageDidReceive");
} else if ([content isKindOfClass:[JVoiceMessage class]]) {
NSLog(@"voice messageDidReceive");
}
}
/// message-recall callback
- (void)messageDidRecall:(JMessage *)message {
NSLog(@"messageDidRecall");
}
/// message-update callback
- (void)messageDidUpdate:(JMessage *)message {
NSLog(@"messageDidRecall");
}
/// message-delete callback
- (void)messageDidDelete:(JConversation *)conversation
clientMsgNos:(NSArray <NSNumber *> *)clientMsgNos {
}
/// callback triggered when all messages before a specified time in a conversation are cleared
/// - Parameters:
/// - conversation: identifier of the conversation whose messages are cleared
/// - timestamp: timestamp in milliseconds; messages before timestamp are cleared
/// - senderId: if non-empty, only messages sent by senderId are cleared
- (void)messageDidClear:(JConversation *)conversation
timestamp:(long long)timestamp
senderId:(NSString *)senderId {
}
/// callback triggered when a message reaction is added
/// - Parameter reaction: added message reaction
/// - Parameter conversation: containing conversation
- (void)messageReactionDidAdd:(JMessageReaction *)reaction
inConversation:(JConversation *)conversation {
}
/// callback triggered when a message reaction is removed
/// - Parameter reaction: removed message reaction
/// - Parameter conversation: containing conversation
- (void)messageReactionDidRemove:(JMessageReaction *)reaction
inConversation:(JConversation *)conversation {
}
/// callback triggered when a message is pinned or unpinned
/// - Parameters:
/// - isTop: YES pins the message; NO unpins it
/// - message: corresponding message
/// - userInfo: user who performed the pin operation
- (void)messageDidSetTop:(BOOL)isTop
message:(JMessage *)message
user:(JUserInfo *)userInfo {
}
Message Read-Receipt Event Listeners
You can register multiple delegates.
[JIM.shared.messageManager addReadReceiptDelegate:self];
/// private chat message read callback
/// - Parameters:
/// - messageIds: message ID array
/// - conversation: containing conversation
- (void)messagesDidRead:(NSArray<NSString *> *)messageIds inConversation:(JConversation *)conversation {
NSLog(@"messagesDidRead");
}
/// group-message read callback
/// - Parameters:
/// - msgs: messageId is the key
/// - conversation: containing conversation
- (void)groupMessagesDidRead:(NSDictionary<NSString *,JGroupMessageReadInfo *> *)msgs inConversation:(JConversation *)conversation {
NSLog(@"groupMessagesDidRead, groupId is %@", conversation.conversationId);
}
Message Destruction Event Listeners
You can register multiple delegates.
[JIM.shared.messageManager addDestroyDelegate:self];
/// callback triggered when a message's destruction time changes (typically for burn-after-reading)
/// - Parameters:
/// - messageId: message ID
/// - conversation: containing conversation
/// - destroyTime: updated destruction time
- (void)messageDestroyTimeDidUpdate:(NSString *)messageId
inConversation:(JConversation *)conversation
destroyTime:(long long)destroyTime {
}
Message Encryption and Decryption Callbacks
Only one message encryption and decryption delegate can be configured.
[JIM.shared.messageManager setPreprocessor:self];
/// message-encryption callback
/// callback timing: after the message is stored and before it is sent
/// - Parameter content: message content to send, serialized as NSData
/// - Parameter conversation: containing conversation
/// - Parameter contentType: message type
/// - Return: processed message content.
- (NSData *)encryptMessageContent:(NSData *)content
inConversation:(JConversation *)conversation
contentType:(NSString *)contentType {
}
/// message-decryption callback
/// callback timing: after receiving the message and before storing it
/// - Parameter content: received message content as NSData, not yet deserialized
/// - Parameter conversation: containing conversation
/// - Parameter contentType: message type
/// - Return: processed message content.
- (NSData *)decryptMessageContent:(NSData *)content
inConversation:(JConversation *)conversation
contentType:(NSString *)contentType {
}
Configure this listener only once globally; subsequent calls overwrite the previous listener. Messages sent to the current user trigger it. For message structure, see Message; for Event details, see listener enums.
let { Event } = JIM;
### Message-Receive Listener
jim.on(Event.MESSAGE_RECEIVED, (message) => {
console.log(message);
});
### Message Read Listener
jim.on(Event.MESSAGE_READ, (notify) => {
/*
Processing logic:
1. Update the in-memory message's isRead state to true here
2. The SDK automatically handles message states in message history
3. Retrieving message history returns the latest read status
notify example:
{
conversationType: 1,
conversationId: "dDshdk1d4",
// list of message IDs read by the other party; update message read status by messageId
messages: [{
messageId:"na4d4nfa2d6gnn28",
// only group conversations have readCount and unreadCount; their sum equals the group size when the message was sent
readCount: 1,
unreadCount: 2
}],
// whether the notification message was sent from another device belonging to the current user,
isSender: false,
// ID of the user who sent the notification message
senderId: 'dadkdks',
// read time
readTime: 1761912175539
}
*/
console.log(notify);
/*
Using burn-after-reading:
1. Prerequisites
(1) message.lifeTimeAfterRead > 0 on a message received in real time or retrieved from message history indicates a burn-after-reading message
(2) Calculate the destruction time as notify.messages[0].readTime + message.lifeTimeAfterRead
2. If a displayed message matches a messageId in notify.messages and message.lifeTimeAfterRead > 0, start a countdown and remove it from the page when the countdown ends
3. If no displayed message matches a messageId in notify.messages, ignore it; the server deletes it automatically
4. Typical burn-after-reading logic for private chats and group chats
(1) Private chat sender: after receiving the other party's read notification, count down for message.lifeTimeAfterRead and clear the message
(2) Private chat recipient: after sending a read notification, count down for message.lifeTimeAfterRead and clear the message
(3) Group chat sender: notify.messages[0].unreadCount == 0 means everyone has read the message; the sender clears it after message.lifeTimeAfterRead
(4) Group chat recipient: after sending a read receipt, clear the message after message.lifeTimeAfterRead
*/
});
### Message-Clear Listener
jim.on(Event.MESSAGE_CLEAN, (notify) => {
/*
notify example:
{
conversationType: 1,
conversationId: "dDshdk1d4",
cleanTime: 1716471002135
}
*/
console.log(notify);
});
### Message-Recall Listener
jim.on(Event.MESSAGE_RECALLED, (notify) => {
/*
Processing logic:Developers only need to update the in-memory message-recall state; the SDK automatically handles message history stored locally and on the server
notify example:
{
conversationType: 1,
conversationId: "dDshdk1d4",
content: {
// UID of the recalled message
messageId: "nq4d9xsfgeghvtnd",
// timestamp of the recalled message
sentTime: 1712903378965
},
sender: {
id: 'dkdosd',
name: 'chater',
portrait: 'https://xxx.example.com/avatar.png'
}
}
*/
console.log(notify);
});
### Message-Delete Listener
jim.on(Event.MESSAGE_REMOVED, (notify) => {
/*
notify example:
{
conversationType: 1,
conversationId: "dDshdk1d4",
content: {
messages: [{ messageId: "nq4d9xsfgeghvtnd" }],
}
}
*/
console.log(notify);
});
### Message-Update Listener
jim.on(Event.MESSAGE_UPDATED, (notify) => {
/*
Processing logic:
1. Set isUpdated on the in-memory message to true
2. The SDK automatically sets isUpdated to true when retrieving message history
3. Only update memory here; ignore the event if the updated message is not in memory
notify example:
{
conversationType: 1,
conversationId: "dDshdk1d4",
// ID of the updated message; update the displayed message in the UI by message ID
messageId: 'nq4d9xsfgeghvtnd',
content: {
// latest message content
content: 'new content'
},
}
*/
console.log(notify);
});
You can register multiple listeners.
//new message received
JuggleIm.instance.getMessageManager().addMsgReceivedListener((msg)=>{
})
//Message-Recall Listener
JuggleIm.instance.getMessageManager().addMsgRecalledListener((msg)=>{
})
//Message-Update Listener
JuggleIm.instance.getMessageManager().addMsgModifiedListener((msg)=>{
})
//Message-Delete Listener
JuggleIm.instance.getMessageManager().addMsgDeletedListener((conver,msgIds)=>{
})
//Message-Clear Listener
JuggleIm.instance.getMessageManager().addMsgCleanedListener((conver,cleanTime,senderId)=>{
})
Message Event Listeners
You can register multiple listeners. Each listener requires a unique key, and the returned function can be used to unregister it.
import JuggleIM from 'juggleim-rnsdk';
// Add a message listener. Returns a function that removes the listener.
const unsubscribeMessage = JuggleIM.addMessageListener('message_key', {
// message-receive callback
onMessageReceive: (message) => {
console.log('Received message:', message);
},
// message-recall callback
onMessageRecall: (message) => {
console.log('Message recalled:', message);
},
// message-update callback
onMessageUpdate: (message) => {
console.log('Message updated:', message);
},
// message-delete callback
// conversation: conversation identifier
// clientMsgNos: list of unique local message numbers
onMessageDelete: (conversation, clientMsgNos) => {
console.log('Messages deleted:', conversation, clientMsgNos);
},
// callback triggered when all messages before a specified time in a conversation are cleared
// conversation: conversation identifier
// timestamp: timestamp in milliseconds; messages before timestamp are cleared
// senderId: if non-empty, only messages sent by senderId are cleared
onMessageClear: (conversation, timestamp, senderId) => {
console.log('Messages cleared:', conversation, timestamp, senderId);
},
// callback triggered when a message reaction is added
// conversation: containing conversation
// reaction: added message reaction
onMessageReactionAdd: (conversation, reaction) => {
console.log('Message reaction added:', conversation, reaction);
},
// callback triggered when a message reaction is removed
// conversation: containing conversation
// reaction: removed message reaction
onMessageReactionRemove: (conversation, reaction) => {
console.log('Message reaction removed:', conversation, reaction);
},
// callback triggered when a message is pinned or unpinned
// message: corresponding message
// operator: user who performed the pin operation
// isTop: true false indicates unpinning
onMessageSetTop: (message, operator, isTop) => {
console.log('Message set top:', message, operator, isTop);
}
});
// remove the listener
// unsubscribeMessage();
Message Read-Receipt Event Listeners
// Add a message read status listener. Returns a function that removes the listener.
const unsubscribeReadReceipt = JuggleIM.addMessageReadReceiptListener('read_receipt_key', {
// private chat message read callback
// conversation: containing conversation
// messageIds: message ID (messageId) array
onMessagesRead: (conversation, messageIds) => {
console.log('Messages read:', conversation, messageIds);
},
// group-message read callback
// conversation: containing conversation
// messages: messageId is the key and read status is the value
onGroupMessagesRead: (conversation, messages) => {
console.log('Group messages read info updated:', conversation, messages);
}
});
// remove the listener
// unsubscribeReadReceipt();
Message Destruction Event Listeners
// Add a message-destruction listener. Returns a function that removes the listener.
const unsubscribeDestroy = JuggleIM.addMessageDestroyListener('destroy_key', {
// callback triggered when a message's destruction time changes (typically for burn-after-reading)
// messageId message ID
// conversation containing conversation
// destroyTime updated destruction time
onMessageDestroyTimeUpdate: (messageId, conversation, destroyTime) => {
console.log('Message destroy time updated:', messageId, conversation, destroyTime);
}
});
// remove the listener
// unsubscribeDestroy();
Message Event Listeners
A connection listener can be set only once. Later assignments overwrite the previous listener. If multiple components need to listen, handle all states in one listener and redistribute events in the application layer.
// message-receive callback
JuggleIm.instance.onMessageReceive = (Message message) {
};
// message-recall callback
JuggleIm.instance.onMessageRecall = (Message message) {
};
// message-update callback
JuggleIm.instance.onMessageUpdate = (Message message) {
};
// message-delete callback
// conversation: conversation identifier
// list: list of unique local message numbers (clientMsgNo)
JuggleIm.instance.onMessageDelete = (Conversation conversation, List<int> clientMsgNoList) {
};
// callback triggered when all messages before a specified time in a conversation are cleared
// conversation: conversation identifier
// timestamp: timestamp in milliseconds; messages before timestamp are cleared
// senderId: if non-empty, only messages sent by senderId are cleared
JuggleIm.instance.onMessageClear = (Conversation conversation, int timestamp, String? senderId) {
};
// callback triggered when a message reaction is added
// conversation: containing conversation
// reaction: added message reaction
JuggleIm.instance.onMessageReactionAdd = (Conversation conversation, MessageReaction reaction) {
};
// callback triggered when a message reaction is removed
// conversation: containing conversation
// reaction: removed message reaction
JuggleIm.instance.onMessageReactionRemove = (Conversation conversation, MessageReaction reaction) {
};
// callback triggered when a message is pinned or unpinned
// message: corresponding message
// operator: user who performed the pin operation
// isTop: true false indicates unpinning
JuggleIm.instance.onMessageSetTop = (Message message, String operator, bool isTop) {
};
Message Read-Receipt Event Listeners
// private chat message read callback
// conversation: containing conversation
// list: message ID (messageId) array
JuggleIm.instance.onMessagesRead = (Conversation conversation, List<String> messageIdList) {
};
// group-message read callback
// conversation: containing conversation
// messages: messageId is the key and read status is the value
JuggleIm.instance.onGroupMessagesRead = (Conversation conversation, Map<String, GroupMessageReadInfo> messages) {
};
Message Destruction Event Listeners
// callback triggered when a message's destruction time changes (typically for burn-after-reading)
// messageId message ID
// conversation containing conversation
// destroyTime updated destruction time
JuggleIm.instance.onMessageDestroyTimeUpdate = (String messageId, Conversation conversation, int destroyTime) {
};