Receive messages
Register the iOS message listener and merge new messages into conversation state.
The iOS SDK delivers regular new messages, online-only messages, revocations, deletions, and read receipts through OIMAdvancedMsgListener. Register the listener once when initializing the message state layer and retain the listener strongly because OIMCallbacker holds only a weak reference.
Message types
Each regular event returns one OIMMessageInfo. Choose text, @ text, custom, image, audio, video, file, or fallback rendering according to the message element. Do not assume that every message contains textElem. For media messages, read the remote URL, size, name, duration, and snapshot from the element; do not upload the resource again.
A message may belong to a conversation that is not currently open. Determine the target conversation first from sessionType, sendID, recvID, and groupID, then merge idempotently by clientMsgID.
Common OIMMessageInfo properties used for reception, routing, and merging are:
| Property | Type | Description |
|---|---|---|
clientMsgID | NSString * _Nullable | Client message ID; use it as the stable unique merge key when non-empty. |
serverMsgID | NSString * _Nullable | Server message ID. It does not replace clientMsgID for local merging. |
sessionType | OIMConversationType | Conversation type enum used to determine single or group chat routing. |
sendID | NSString * _Nullable | Sender user ID. |
recvID | NSString * _Nullable | Recipient user ID. |
groupID | NSString * _Nullable | Target group ID for group messages. |
contentType | OIMMessageContentType | Content type enum determining which content element to render. |
sendTime | NSTimeInterval | Message dispatch timestamp used for sorting; cannot serve as a unique ID. |
status | OIMMessageStatus | Message delivery status enum. |
isRead | BOOL | Read receipt state recorded by the SDK. |
Content properties such as textElem, pictureElem, soundElem, videoElem, fileElem, atTextElem, and customElem may be nil. Check both contentType and the corresponding element when rendering. Display fallback placeholders when expected content is missing instead of force-unwrapping.
Register the new-message listener
@interface MessageStore () <OIMAdvancedMsgListener>
@end
@implementation MessageStore
- (void)startListening {
[[OIMManager callbacker] addAdvancedMsgListener:self];
}
- (void)stopListening {
[[OIMManager callbacker] removeAdvancedMsgListener:self];
}
- (void)onRecvNewMessage:(OIMMessageInfo * _Nullable)message {
if (message.clientMsgID.length == 0) {
return;
}
[self mergeMessage:message];
}
- (void)onRecvOnlineOnlyMessage:(OIMMessageInfo * _Nullable)message {
if (message.clientMsgID.length == 0) {
return;
}
[self handleOnlineOnlyMessage:message];
}
@endRegister the global message listener after initSDK succeeds and before login. Remove the listener with the same instance when signing out, switching accounts, or destroying the state layer. The callback message parameter can be nil, so validate clientMsgID before processing. Each callback delivers a single OIMMessageInfo model.
Online-only messages are not stored in regular offline history and are suitable for transient hints or business notifications. For sending parameters, see Send a message.
Merge messages
Resolve the target conversation from routing fields first, then merge idempotently by clientMsgID. A new-message event can overlap with a send-success callback or history query result, so never append it directly without deduplication.
History queries establish the baseline snapshot, onRecvNewMessage: provides online increments, and the SDK synchronizes offline changes upon logging in. After synchronization completes, re-query the current conversation's history to reconcile list state.
Retrieve history when first opening a conversation
Event callbacks only supply newly arriving messages. Use getAdvancedHistoryMessageList:onSuccess:onFailure: to retrieve history when opening a conversation, scrolling upward, or refreshing a list after synchronization. Set startClientMsgID to nil for the first page and use the boundary message's clientMsgID for subsequent pages. See Load message history for details.
The query callback returns a snapshot of messages and does not trigger the new-message listener. Both pagination and incoming events must use identical conversation routing and clientMsgID deduplication rules.
Mark the conversation as read
After the user opens the conversation and views visible messages, invoke the mark-as-read API to clear the unread counter. For one-to-one chat receipts, see Mark a conversation as read. For member-level group receipts, see Report group-message read status.
Other message events
- For message revocation handling, see Revoke a message.
- For deletion events, see Delete messages in batches.
- For one-to-one read receipts, see Mark a conversation as read; for group read receipts, see Report group-message read status.
- For custom business notifications, see Receive custom business messages.
Query APIs, local insertion, and message creation do not trigger onRecvNewMessage:.
Verify the receiving flow
- Send a message to the target one-to-one or group chat from another account and verify that it merges exactly once by conversation and
clientMsgID. - Send an online-only message and verify that it arrives through
onRecvOnlineOnlyMessage:and is not returned by history queries. - Revoke or delete a message and verify that the message view updates the corresponding bubble by
clientMsgID. - After signing out or switching accounts, verify that the listener was removed and does not process duplicate messages after the next login.
Was this page helpful?