Message overview
Message structure
| Property | Type | Description |
|---|---|---|
| channelType | ChannelType? | Channel type |
| channelId | String? | Channel ID |
| subChannelId | String? | Business identifier for the channel (max 20 characters). Only applies to community channels. |
| messageType | MessageType? | Message type |
| clientId | int? | Unique local message ID (database index) |
| messageId | String? | Unique server message ID (globally unique within an App Key) |
| direction | MessageDirection | Message direction |
| receivedTime | int | Receive time (Unix timestamp in milliseconds) |
| sentTime | int | Send time (Unix timestamp in milliseconds) |
| receivedStatus | ReceivedStatus | Receive status |
| sentStatus | SentStatus | Send status |
| senderUserId | String | Sender user ID |
| metadata | Map? | Metadata key-value pairs. Set them at send time. After sending, they can't be changed through this field. Supported only in direct channels and group channels. Key length ≤ 32, value length ≤ 4096, max 20 pairs per update, max 300 total per message. |
| offLine | bool | Whether this is a missed message. Only valid in the message receive callback. true for missed messages, false otherwise. |
| groupReadReceiptInfo | GroupReadReceiptInfo | Group read receipt status |
| userInfo | UserInfo | User info attached to the message |
| mentionedInfo | MentionedInfo? | Mention (@) information |
| extra | String? | Additional field attached to the message. The receiver can access this data. |
Message types and constructors
The Chat SDK MessageType enum provides predefined types for text, voice, image, and other messages. Apps can also implement custom messages using MessageType.nativeCustom.
By default, all message types are stored locally and counted toward the unread count, except:
- Recall (
MessageType.recall): Stored locally but not counted as unread. - Command (
MessageType.command): Not stored locally, not counted as unread. - Command notification (
MessageType.commandNotification): Stored locally but not counted as unread. - Custom (
MessageType.custom): Storage controlled by the app's CustomMessagePolicy. - Native custom (
MessageType.nativeCustom): Storage controlled byCustomMessagePersistentFlag. - Native custom media (
MessageType.nativeCustomMedia): Storage controlled byCustomMessagePersistentFlag.
The SDK supports native custom messages. The difference between custom messages and native custom messages:
- Custom messages (
MessageType.custom): A cross-platform wrapper type. These messages are wrapped at a lower level and cannot interoperate with custom messages registered via the native iOS/Android SDKs. - Native custom messages (
MessageType.nativeCustom): Fully interoperable with custom messages registered via the native iOS/Android SDKs.
Text message
Type: MessageType.text
| Property | Type | Description |
|---|---|---|
| text | String | Text content |
Build a text message
final channel = DirectChannel('<target-id>');
await channel.sendMessage(SendMessageParams(
messageParams: TextMessageParams(
text: '<message-text>',
),
));
| Parameter | Type | Description |
|---|---|---|
| text | String | Text content |
Voice message
Record voice messages in AAC format with a bitrate of at least 56 kbps for quality and compatibility.
Type: MessageType.voice
| Property | Type | Description |
|---|---|---|
| duration | int | Voice duration in seconds |
Build a voice message
final channel = DirectChannel('<target-user-id>');
await channel.sendMediaMessage(SendMediaMessageParams(
messageParams: VoiceMessageParams(
path: path,
duration: duration,
),
));
| Parameter | Type | Description |
|---|---|---|
| path | String | Local path to the voice file (must be valid) |
| duration | int | Voice message duration |
Image message
Type: MessageType.image
| Property | Type | Description |
|---|---|---|
| thumbnailBase64String | String | Base64 thumbnail data |
| thumWidth | int | Thumbnail width (pixels) |
| thumHeight | int | Thumbnail height (pixels) |
| original | bool | Whether this is the original image |
Build an image message
final channel = DirectChannel('<target-user-id>');
await channel.sendMediaMessage(SendMediaMessageParams(
messageParams: ImageMessageParams(
path: path,
),
));
| Parameter | Type | Description |
|---|---|---|
| path | String | Local path to the image file (must be valid) |
File message
Type: MessageType.file
| Property | Type | Description |
|---|---|---|
| name | String | File name |
| fileType | String | File type |
| size | int | File size in bytes |
Build a file message
final channel = DirectChannel('<target-user-id>');
await channel.sendMediaMessage(SendMediaMessageParams(
messageParams: FileMessageParams(
path: path,
),
));
| Parameter | Type | Description |
|---|---|---|
| path | String | Local path to the file (must be valid) |
Short video message
Type: MessageType.sight
| Property | Type | Description |
|---|---|---|
| duration | int | Video duration |
| size | int | Video size |
| name | String | Video name |
| thumbnailBase64String | String | Thumbnail data |
Build a short video message
final channel = DirectChannel('<target-user-id>');
await channel.sendMediaMessage(SendMediaMessageParams(
messageParams: ShortVideoMessageParams(
path: path,
duration: duration,
),
));
| Parameter | Type | Description |
|---|---|---|
| path | String | Local path to the video file (must be valid) |
| duration | int | Video duration. The server default maximum is 2 minutes. Contact your sales representative to adjust this limit. |
GIF message
Type: MessageType.gif
| Property | Type | Description |
|---|---|---|
| dataSize | int | GIF size in bytes |
| width | int | GIF width |
| height | int | GIF height |
Build a GIF message
final channel = DirectChannel('<target-user-id>');
await channel.sendMediaMessage(SendMediaMessageParams(
messageParams: GIFMessageParams(
path: path,
),
));
| Parameter | Type | Description |
|---|---|---|
| path | String | Local path to the GIF file |
Recall message
Recall messages cannot be constructed manually. Use the recall message API instead.
Type: MessageType.recall
| Property | Type | Description |
|---|---|---|
| admin | bool | Whether the operation was performed by an admin |
| deleted | bool | Whether the message is deleted |
| recallTime | int | Original message send time (milliseconds) |
| recallActionTime | int | Time of the recall action (milliseconds) |
| originalMessage | Message | The original recalled message |
Reference message
Type: MessageType.reference
| Property | Type | Description |
|---|---|---|
| text | String | Reference text |
| referenceMessage | Message | The referenced message |
Build a reference message
final channel = DirectChannel('<target-user-id>');
await channel.sendMessage(SendMessageParams(
messageParams: ReferenceMessageParams(
referenceMessage: referenceMessage,
text: text,
),
));
| Parameter | Type | Description |
|---|---|---|
| referenceMessage | Message | The message to reference |
| text | String | Reference text content |
Location message
Type: MessageType.location
| Property | Type | Description |
|---|---|---|
| longitude | double | Longitude |
| latitude | double | Latitude |
| poiName | String | POI name |
| thumbnailPath | String | Thumbnail path |
Build a location message
final channel = DirectChannel('<target-user-id>');
await channel.sendMessage(SendMessageParams(
messageParams: LocationMessageParams(
longitude: longitude,
latitude: latitude,
poiName: poiName,
thumbnailPath: thumbnailPath,
),
));
| Parameter | Type | Description |
|---|---|---|
| longitude | double | Longitude |
| latitude | double | Latitude |
| poiName | String | POI name |
| thumbnailPath | String | Local thumbnail path (must be valid) |
Command message
Type: MessageType.command
| Property | Type | Description |
|---|---|---|
| name | String | Command name |
| data | String | Command data. Can be any string, such as JSON data. |
The Flutter SDK does not provide a create method for CommandMessage. It only supports receiving this message type. To send command messages from the client, define a wrapper class in the Flutter layer. See How to send command messages in the Flutter SDK.
Command notification message
Type: MessageType.commandNotification
| Property | Type | Description |
|---|---|---|
| name | String | Notification name |
| data | String | Notification data. Can be any string, such as JSON data. |
The Flutter SDK does not provide a create method for CommandNotificationMessage. It only supports receiving this message type. To send command notification messages from the client, define a wrapper class in the Flutter layer. See How to send command messages in the Flutter SDK.
Group notification message
Type: MessageType.groupNotification
Group notification messages are used for group-related operations such as member join, leave, and group dissolution.
| Property | Type | Description |
|---|---|---|
| operation | String | Operation type |
| operatorUserId | String | Operator user ID |
| data | String | Operation-related data |
| message | String | Operation message content |
Group notification messages are typically sent automatically by the server during group operations. The client primarily receives and parses these notifications. The Flutter SDK does not provide a method to create group notification messages.
Custom message
Type: MessageType.custom
| Property | Type | Description |
|---|---|---|
| identifier | String | Custom message identifier |
| policy | CustomMessagePolicy | Storage policy |
| fields | Map<String, String> | Key-value pairs |
Build a custom message
final channel = GroupChannel('<group-id>');
await channel.sendMessage(SendMessageParams(
messageParams: CustomMessageParams(
messageIdentifier: messageIdentifier,
fields: fields,
),
));
| Parameter | Type | Description |
|---|---|---|
| messageIdentifier | String | Unique message identifier |
| fields | Map<String, String> | Key-value pairs for message content |
Native custom message
Native custom messages are interoperable with custom messages registered on other platforms after registration.
Type: MessageType.nativeCustom
| Property | Type | Description |
|---|---|---|
| fields | Map? | Key-value pairs for message content |
| searchableWords | List<String>? | Searchable keywords |
| messageIdentifier | String? | Unique message identifier (see naming conventions below) |
messageIdentifier corresponds to the server-side objectName parameter and uniquely identifies a custom message type. Follow these guidelines:
- Format: Use
prefix:messageType, e.g.,app:txtcontent - Length: Keep it under 16 characters to minimize impact on message size
- Restrictions:
- Do not start with
RC:(reserved for built-in messages) - Do not use built-in message identifiers
- Do not start with
- Examples:
app:order— Order messagecustom:gift— Gift messagemyapp:notice— Notice messageRC:TxtMsg— Incorrect: uses a reserved prefix
Build a native custom message
Register native custom messages after initialization but before connecting by calling registerCustomMessage.
Register a native custom message
await NCEngine.registerCustomMessage(messageIdentifier, persistentFlag);
| Parameter | Type | Description |
|---|---|---|
| messageIdentifier | String | Unique message identifier |
| persistentFlag | CustomMessagePersistentFlag | Storage policy |
Send a native custom message
final channel = GroupChannel('<group-id>');
await channel.sendMessage(SendMessageParams(
messageParams: CustomMessageParams(
messageIdentifier: '<message-identifier>',
fields: {'key': 'value'},
),
));
| Parameter | Type | Description |
|---|---|---|
| messageIdentifier | String | Unique message identifier |
| fields | Map | Key-value pairs for message content |
Native custom media message
Type: MessageType.nativeCustomMedia
| Property | Type | Description |
|---|---|---|
| fields | Map? | Key-value pairs for message content |
| searchableWords | List<String>? | Searchable keywords |
| messageIdentifier | String | Unique message identifier |
Build a native custom media message
Register native custom media messages after initialization but before connecting by calling registerCustomMediaMessage.
Register a native custom media message
await NCEngine.registerCustomMediaMessage(messageIdentifier, persistentFlag);
| Parameter | Type | Description |
|---|---|---|
| messageIdentifier | String | Unique message identifier |
| persistentFlag | CustomMessagePersistentFlag | Storage policy |
Send a native custom media message
final channel = GroupChannel('<group-id>');
await channel.sendMediaMessage(SendMediaMessageParams(
messageParams: CustomMediaMessageParams(
messageIdentifier: '<message-identifier>',
path: '<local-media-path>',
fields: {'key': 'value'},
),
));
| Parameter | Type | Description |
|---|---|---|
| messageIdentifier | String | Unique message identifier |
| path | String | Local path to the media file (must be valid) |
| fields | Map | Key-value pairs for message content |
Unknown type
When the SDK receives an unrecognized message, it becomes an unknown type. This type cannot be constructed or sent.
Type: MessageType.unknown
| Property | Type | Description |
|---|---|---|
| rawData | String | Raw message data |
| objectName | String | Message identifier |