Community is a Discord-like real-time interactive community feature provided by ZIM, using a two-layer "Community - Channel" structure. A Channel is the basic unit for chat interactions within a Community, similar to traditional groups, supporting sending various types of messages such as text, images, voice, and video.
This document describes how to send and receive messages in Community channels. Sending and receiving channel messages are based on ZIM's standard messaging APIs, using ZIMConversationType.COMMUNITY_CHANNEL as the conversation type.
Prerequisites
Please refer to Send and receive messages to complete ZIM SDK integration, initialization, and user login.
The Community feature requires ZIM SDK 3.0.0 or later.
The Community feature is part of the Premium plan. Please contact ZEGOCLOUD Technical Support to enable it before use.
The Token generation for the Community feature is consistent with other ZIM features, and no additional permission declarations are required.
Before sending channel messages, the user must join (or create) a Community and obtain the conversationID of the target channel.
Note
Supported message types are the same as those for groups, including text, rich media, custom, and combined messages. For details, see Send and receive messages - Message types.
Step 1: Create or join a Community
Create a Community
Call the createCommunity API to create a Community. Upon successful creation, the system automatically creates a default channel of type GENERAL for the Community.
import im.zego.zim.ZIM;
import im.zego.zim.entity.ZIMCommunityCreateConfig;
import im.zego.zim.entity.ZIMCommunityFullInfo;
import im.zego.zim.entity.ZIMCommunityInfo;
import im.zego.zim.entity.ZIMError;
import im.zego.zim.enums.ZIMErrorCode;
// Construct basic Community information
ZIMCommunityInfo communityInfo = new ZIMCommunityInfo();
communityInfo.setCommunityID("community_001"); // Community ID, customized by the developer
communityInfo.setCommunityName("My Community");
communityInfo.setCommunityAvatarUrl("https://example.com/avatar.png");
ZIMCommunityCreateConfig config = new ZIMCommunityCreateConfig();
// Optional: set Community notice
config.setCommunityNotice("Welcome!");
zim.createCommunity(communityInfo, config, (ZIMCommunityFullInfo fullInfo, ZIMError error) -> {
if (error.code == ZIMErrorCode.SUCCESS) {
// Creation succeeded, fullInfo contains full Community information
}
});
import im.zego.zim.ZIM;
import im.zego.zim.entity.ZIMCommunityCreateConfig;
import im.zego.zim.entity.ZIMCommunityFullInfo;
import im.zego.zim.entity.ZIMCommunityInfo;
import im.zego.zim.entity.ZIMError;
import im.zego.zim.enums.ZIMErrorCode;
// Construct basic Community information
ZIMCommunityInfo communityInfo = new ZIMCommunityInfo();
communityInfo.setCommunityID("community_001"); // Community ID, customized by the developer
communityInfo.setCommunityName("My Community");
communityInfo.setCommunityAvatarUrl("https://example.com/avatar.png");
ZIMCommunityCreateConfig config = new ZIMCommunityCreateConfig();
// Optional: set Community notice
config.setCommunityNotice("Welcome!");
zim.createCommunity(communityInfo, config, (ZIMCommunityFullInfo fullInfo, ZIMError error) -> {
if (error.code == ZIMErrorCode.SUCCESS) {
// Creation succeeded, fullInfo contains full Community information
}
});
#include <zim/zim.h>
using namespace ZIM;
// Construct basic Community information
ZIMCommunityInfo communityInfo;
communityInfo.communityID = "community_001";
communityInfo.communityName = "My Community";
communityInfo.communityAvatarUrl = "https://example.com/avatar.png";
ZIMCommunityCreateConfig config;
// Optional: set Community notice
config.communityNotice = "Welcome!";
zim->createCommunity(communityInfo, config, [](ZIMCommunityFullInfo fullInfo, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
// Creation succeeded, fullInfo contains full Community information
}
});
#include <zim/zim.h>
using namespace ZIM;
// Construct basic Community information
ZIMCommunityInfo communityInfo;
communityInfo.communityID = "community_001";
communityInfo.communityName = "My Community";
communityInfo.communityAvatarUrl = "https://example.com/avatar.png";
ZIMCommunityCreateConfig config;
// Optional: set Community notice
config.communityNotice = "Welcome!";
zim->createCommunity(communityInfo, config, [](ZIMCommunityFullInfo fullInfo, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
// Creation succeeded, fullInfo contains full Community information
}
});
Example code
// Construct basic Community information
const communityInfo = {
communityID: "community_001",
communityName: "My Community",
communityAvatarUrl: "https://example.com/avatar.png"
};
const config = {
// Optional: set Community notice
communityNotice: "Welcome!"
};
try {
const result = await zim.createCommunity(communityInfo, config);
// Creation succeeded, result contains full Community information
} catch (error) {
// Creation failed, handle based on error.code
}
// Construct basic Community information
const communityInfo = {
communityID: "community_001",
communityName: "My Community",
communityAvatarUrl: "https://example.com/avatar.png"
};
const config = {
// Optional: set Community notice
communityNotice: "Welcome!"
};
try {
const result = await zim.createCommunity(communityInfo, config);
// Creation succeeded, result contains full Community information
} catch (error) {
// Creation failed, handle based on error.code
}
Example code
// Construct basic Community information
final communityInfo = ZIMCommunityInfo()
..communityID = 'community_001'
..communityName = 'My Community'
..communityAvatarUrl = 'https://example.com/avatar.png';
final config = ZIMCommunityCreateConfig();
// Optional: set Community notice
config.communityNotice = 'Welcome!';
try {
final result = await ZIM.getInstance()!.createCommunity(
communityInfo: communityInfo,
config: config,
);
// Creation succeeded, result contains full Community information
} catch (error) {
// Creation failed, handle based on error.code
}
// Construct basic Community information
final communityInfo = ZIMCommunityInfo()
..communityID = 'community_001'
..communityName = 'My Community'
..communityAvatarUrl = 'https://example.com/avatar.png';
final config = ZIMCommunityCreateConfig();
// Optional: set Community notice
config.communityNotice = 'Welcome!';
try {
final result = await ZIM.getInstance()!.createCommunity(
communityInfo: communityInfo,
config: config,
);
// Creation succeeded, result contains full Community information
} catch (error) {
// Creation failed, handle based on error.code
}
Join an existing Community
When the communityID is known, call the joinCommunity API to join the Community.
String communityID = "community_001";
zim.joinCommunity(communityID, (ZIMCommunityFullInfo fullInfo, ZIMError error) -> {
if (error.code == ZIMErrorCode.SUCCESS) {
// Joined successfully, fullInfo contains full Community information
}
});
String communityID = "community_001";
zim.joinCommunity(communityID, (ZIMCommunityFullInfo fullInfo, ZIMError error) -> {
if (error.code == ZIMErrorCode.SUCCESS) {
// Joined successfully, fullInfo contains full Community information
}
});
Example code
NSString *communityID = @"community_001";
[zim joinCommunity:communityID callback:^(ZIMCommunityFullInfo * _Nonnull communityFullInfo, ZIMError * _Nonnull errorInfo) {
if (errorInfo.code == ZIMErrorCodenoneSuccess) {
// Joined successfully, communityFullInfo contains full Community information
}
}];
NSString *communityID = @"community_001";
[zim joinCommunity:communityID callback:^(ZIMCommunityFullInfo * _Nonnull communityFullInfo, ZIMError * _Nonnull errorInfo) {
if (errorInfo.code == ZIMErrorCodenoneSuccess) {
// Joined successfully, communityFullInfo contains full Community information
}
}];
Example code
std::string communityID = "community_001";
zim->joinCommunity(communityID, [](ZIMCommunityFullInfo fullInfo, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
// Joined successfully, fullInfo contains full Community information
}
});
std::string communityID = "community_001";
zim->joinCommunity(communityID, [](ZIMCommunityFullInfo fullInfo, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
// Joined successfully, fullInfo contains full Community information
}
});
Example code
const communityID = "community_001";
try {
const result = await zim.joinCommunity(communityID);
// Joined successfully, result contains full Community information
} catch (error) {
// Failed to join, handle based on error.code
}
const communityID = "community_001";
try {
const result = await zim.joinCommunity(communityID);
// Joined successfully, result contains full Community information
} catch (error) {
// Failed to join, handle based on error.code
}
Example code
const communityID = 'community_001';
try {
final result = await ZIM.getInstance()!.joinCommunity(communityID);
// Joined successfully, result contains full Community information
} catch (error) {
// Failed to join, handle based on error.code
}
const communityID = 'community_001';
try {
final result = await ZIM.getInstance()!.joinCommunity(communityID);
// Joined successfully, result contains full Community information
} catch (error) {
// Failed to join, handle based on error.code
}
The conversationID field of the channel object is the conversation ID required for subsequent message sending and receiving.
String communityID = "community_001";
int count = 100; // Maximum number of channels to fetch per request
ZIMCommunityChannelListQueryConfig config = new ZIMCommunityChannelListQueryConfig();
// config.nextFlag is used for pagination. No need to set it for the first query; for subsequent queries, use the nextFlag returned from the previous call.
zim.queryCommunityChannelList(communityID, count, config,
(ArrayList<ZIMCommunityChannel> channelList, long nextFlag, ZIMError error) -> {
if (error.code == ZIMErrorCode.SUCCESS) {
for (ZIMCommunityChannel channel : channelList) {
// channel.getBaseInfo().getChannelID() — Channel ID
// channel.getBaseInfo().getChannelName() — Channel name
// channel.getConversationID() — Conversation ID used for sending/receiving messages
}
}
});
String communityID = "community_001";
int count = 100; // Maximum number of channels to fetch per request
ZIMCommunityChannelListQueryConfig config = new ZIMCommunityChannelListQueryConfig();
// config.nextFlag is used for pagination. No need to set it for the first query; for subsequent queries, use the nextFlag returned from the previous call.
zim.queryCommunityChannelList(communityID, count, config,
(ArrayList<ZIMCommunityChannel> channelList, long nextFlag, ZIMError error) -> {
if (error.code == ZIMErrorCode.SUCCESS) {
for (ZIMCommunityChannel channel : channelList) {
// channel.getBaseInfo().getChannelID() — Channel ID
// channel.getBaseInfo().getChannelName() — Channel name
// channel.getConversationID() — Conversation ID used for sending/receiving messages
}
}
});
Example code
NSString *communityID = @"community_001";
NSUInteger count = 100;
ZIMCommunityChannelListQueryConfig *config = [[ZIMCommunityChannelListQueryConfig alloc] init];
// config.nextFlag is used for pagination. No need to set it for the first query.
[zim queryCommunityChannelList:communityID count:count config:config callback:^(NSString * _Nonnull communityID, NSArray<ZIMCommunityChannel *> * _Nonnull channelList, long long nextFlag, ZIMError * _Nonnull errorInfo) {
if (errorInfo.code == ZIMErrorCodenoneSuccess) {
for (ZIMCommunityChannel *channel in channelList) {
// channel.baseInfo.channelID — Channel ID
// channel.baseInfo.channelName — Channel name
// channel.conversationID — Conversation ID used for sending/receiving messages
}
}
}];
NSString *communityID = @"community_001";
NSUInteger count = 100;
ZIMCommunityChannelListQueryConfig *config = [[ZIMCommunityChannelListQueryConfig alloc] init];
// config.nextFlag is used for pagination. No need to set it for the first query.
[zim queryCommunityChannelList:communityID count:count config:config callback:^(NSString * _Nonnull communityID, NSArray<ZIMCommunityChannel *> * _Nonnull channelList, long long nextFlag, ZIMError * _Nonnull errorInfo) {
if (errorInfo.code == ZIMErrorCodenoneSuccess) {
for (ZIMCommunityChannel *channel in channelList) {
// channel.baseInfo.channelID — Channel ID
// channel.baseInfo.channelName — Channel name
// channel.conversationID — Conversation ID used for sending/receiving messages
}
}
}];
Example code
std::string communityID = "community_001";
unsigned int count = 100; // Maximum number of channels to fetch per request
ZIMCommunityChannelListQueryConfig config;
// config.nextFlag is used for pagination. No need to set it for the first query; for subsequent queries, use the nextFlag returned from the previous call.
zim->queryCommunityChannelList(communityID, count, config,
[](std::string communityID, std::vector<ZIMCommunityChannel> channelList, uint64_t nextFlag, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
for (auto& channel : channelList) {
// channel.baseInfo.channelID — Channel ID
// channel.baseInfo.channelName — Channel name
// channel.conversationID — Conversation ID used for sending/receiving messages
}
}
});
std::string communityID = "community_001";
unsigned int count = 100; // Maximum number of channels to fetch per request
ZIMCommunityChannelListQueryConfig config;
// config.nextFlag is used for pagination. No need to set it for the first query; for subsequent queries, use the nextFlag returned from the previous call.
zim->queryCommunityChannelList(communityID, count, config,
[](std::string communityID, std::vector<ZIMCommunityChannel> channelList, uint64_t nextFlag, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
for (auto& channel : channelList) {
// channel.baseInfo.channelID — Channel ID
// channel.baseInfo.channelName — Channel name
// channel.conversationID — Conversation ID used for sending/receiving messages
}
}
});
Example code
const communityID = "community_001";
const count = 100; // Maximum number of channels to fetch per request
const config = {
// nextFlag is used for pagination. No need to set it for the first query; for subsequent queries, use the nextFlag returned from the previous call.
};
try {
const result = await zim.queryCommunityChannelList(communityID, count, config);
for (const channel of result.channelList) {
// channel.baseInfo.channelID — Channel ID
// channel.baseInfo.channelName — Channel name
// channel.conversationID — Conversation ID used for sending/receiving messages
}
// result.nextFlag is used for pagination. A value of 0 or an empty list indicates no more data.
} catch (error) {
// Query failed, handle based on error.code
}
const communityID = "community_001";
const count = 100; // Maximum number of channels to fetch per request
const config = {
// nextFlag is used for pagination. No need to set it for the first query; for subsequent queries, use the nextFlag returned from the previous call.
};
try {
const result = await zim.queryCommunityChannelList(communityID, count, config);
for (const channel of result.channelList) {
// channel.baseInfo.channelID — Channel ID
// channel.baseInfo.channelName — Channel name
// channel.conversationID — Conversation ID used for sending/receiving messages
}
// result.nextFlag is used for pagination. A value of 0 or an empty list indicates no more data.
} catch (error) {
// Query failed, handle based on error.code
}
Example code
const communityID = 'community_001';
const count = 100; // Maximum number of channels to fetch per request
final config = ZIMCommunityChannelListQueryConfig();
// config.nextFlag is used for pagination. No need to set it for the first query.
try {
final result = await ZIM.getInstance()!.queryCommunityChannelList(
communityID,
count,
config: config,
);
for (final channel in result.channelList) {
// channel.baseInfo.channelID — Channel ID
// channel.baseInfo.channelName — Channel name
// channel.conversationID — Conversation ID used for sending/receiving messages
}
// result.nextFlag is used for pagination. A value of 0 or an empty list indicates no more data.
} catch (error) {
// Query failed, handle based on error.code
}
const communityID = 'community_001';
const count = 100; // Maximum number of channels to fetch per request
final config = ZIMCommunityChannelListQueryConfig();
// config.nextFlag is used for pagination. No need to set it for the first query.
try {
final result = await ZIM.getInstance()!.queryCommunityChannelList(
communityID,
count,
config: config,
);
for (final channel in result.channelList) {
// channel.baseInfo.channelID — Channel ID
// channel.baseInfo.channelName — Channel name
// channel.conversationID — Conversation ID used for sending/receiving messages
}
// result.nextFlag is used for pagination. A value of 0 or an empty list indicates no more data.
} catch (error) {
// Query failed, handle based on error.code
}
Note
ZIMCommunityChannel.conversationID is different from ZIMCommunityChannelInfo.channelID. Please use conversationID when sending messages.
If the Community has many channels, you can paginate using the returned nextFlag until it returns 0 or the list is empty.
Send messages
Note
The conversationID used for sending and receiving channel messages is different from the channel's channelID. conversationID is used for message sending/receiving and conversation management, and can be obtained from the channel object; channelID is used for channel management operations (such as creating, updating, and deleting channels). Do not confuse the two.
After obtaining the target channel's conversationID, call the sendMessage API to send a message. The difference from other conversation types is that you need to set conversationType to ZIMConversationType.COMMUNITY_CHANNEL.
Warning
The message sending API is shared across one-on-one chats, groups, rooms, and Community channels via the same sendMessage, with the target conversation type distinguished by conversationType.
The interval between two message sends must be greater than 100ms.
Ordinary messages
// After obtaining the target channel, use its conversationID to send a message
String conversationID = channel.getConversationID(); // From the queryCommunityChannelList result
ZIMTextMessage textMessage = new ZIMTextMessage();
textMessage.setMessage("Hello, Channel!");
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// Set message priority: LOW(1) / MEDIUM(2) / HIGH(3)
config.setPriority(ZIMMessagePriority.LOW);
zim.sendMessage(
textMessage,
conversationID,
ZIMConversationType.COMMUNITY_CHANNEL, // Conversation type: Community channel
config,
new ZIMMessageSentFullCallback() {
@Override
public void onMessageAttached(ZIMMessage message) {
// Message has passed local validation and is ready to send; you can update the UI here (e.g., show sending status)
}
@Override
public void onMessageSent(ZIMMessage message, ZIMError error) {
if (error.code == ZIMErrorCode.SUCCESS) {
// Message sent successfully
} else {
// Message sending failed, handle based on error.code
}
}
@Override
public void onMediaUploadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize) {
}
@Override
public void onMultipleMediaUploadingProgress(ZIMMultipleMessage message, long messageInfoIndex, long currentIndexFileSize, int messageIndex, long totalIndexFileSize, long totalFileSize) {
}
}
);
// After obtaining the target channel, use its conversationID to send a message
String conversationID = channel.getConversationID(); // From the queryCommunityChannelList result
ZIMTextMessage textMessage = new ZIMTextMessage();
textMessage.setMessage("Hello, Channel!");
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// Set message priority: LOW(1) / MEDIUM(2) / HIGH(3)
config.setPriority(ZIMMessagePriority.LOW);
zim.sendMessage(
textMessage,
conversationID,
ZIMConversationType.COMMUNITY_CHANNEL, // Conversation type: Community channel
config,
new ZIMMessageSentFullCallback() {
@Override
public void onMessageAttached(ZIMMessage message) {
// Message has passed local validation and is ready to send; you can update the UI here (e.g., show sending status)
}
@Override
public void onMessageSent(ZIMMessage message, ZIMError error) {
if (error.code == ZIMErrorCode.SUCCESS) {
// Message sent successfully
} else {
// Message sending failed, handle based on error.code
}
}
@Override
public void onMediaUploadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize) {
}
@Override
public void onMultipleMediaUploadingProgress(ZIMMultipleMessage message, long messageInfoIndex, long currentIndexFileSize, int messageIndex, long totalIndexFileSize, long totalFileSize) {
}
}
);
Example code
// After obtaining the target channel, use its conversationID to send a message
NSString *conversationID = channel.conversationID;
ZIMTextMessage *textMessage = [[ZIMTextMessage alloc] init];
textMessage.message = @"Hello, Channel!";
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
config.priority = ZIMMessagePriorityLow;
[zim sendMessage:textMessage toConversationID:conversationID conversationType:ZIMConversationTypeCommunityChannel config:config callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
if (errorInfo.code == ZIMErrorCodenoneSuccess) {
// Message sent successfully
}
}];
// After obtaining the target channel, use its conversationID to send a message
NSString *conversationID = channel.conversationID;
ZIMTextMessage *textMessage = [[ZIMTextMessage alloc] init];
textMessage.message = @"Hello, Channel!";
ZIMMessageSendConfig *config = [[ZIMMessageSendConfig alloc] init];
config.priority = ZIMMessagePriorityLow;
[zim sendMessage:textMessage toConversationID:conversationID conversationType:ZIMConversationTypeCommunityChannel config:config callback:^(ZIMMessage * _Nonnull message, ZIMError * _Nonnull errorInfo) {
if (errorInfo.code == ZIMErrorCodenoneSuccess) {
// Message sent successfully
}
}];
Example code
// After obtaining the target channel, use its conversationID to send a message
std::string conversationID = channel.conversationID; // From the queryCommunityChannelList result
auto textMessage = ZIMTextMessage();
textMessage.message = "Hello, Channel!";
ZIMMessageSendConfig config;
// Set message priority: LOW(1) / MEDIUM(2) / HIGH(3)
config.priority = ZIMMessagePriority::LOW;
zim->sendMessage(
textMessage,
conversationID,
ZIMConversationType::COMMUNITY_CHANNEL, // Conversation type: Community channel
config,
[](ZIMMessage message, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
// Message sent successfully
} else {
// Message sending failed, handle based on error.code
}
});
// After obtaining the target channel, use its conversationID to send a message
std::string conversationID = channel.conversationID; // From the queryCommunityChannelList result
auto textMessage = ZIMTextMessage();
textMessage.message = "Hello, Channel!";
ZIMMessageSendConfig config;
// Set message priority: LOW(1) / MEDIUM(2) / HIGH(3)
config.priority = ZIMMessagePriority::LOW;
zim->sendMessage(
textMessage,
conversationID,
ZIMConversationType::COMMUNITY_CHANNEL, // Conversation type: Community channel
config,
[](ZIMMessage message, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
// Message sent successfully
} else {
// Message sending failed, handle based on error.code
}
});
Example code
// After obtaining the target channel, use its conversationID to send a message
const conversationID = channel.conversationID; // From the queryCommunityChannelList result
const textMessage = new ZIMTextMessage();
textMessage.message = "Hello, Channel!";
const config = {
// Set message priority: LOW(1) / MEDIUM(2) / HIGH(3)
priority: ZIMMessagePriority.LOW,
};
try {
const result = await zim.sendMessage(
textMessage,
conversationID,
ZIMConversationType.COMMUNITY_CHANNEL, // Conversation type: Community channel
config
);
// Message sent successfully
} catch (error) {
// Message sending failed, handle based on error.code
}
// After obtaining the target channel, use its conversationID to send a message
const conversationID = channel.conversationID; // From the queryCommunityChannelList result
const textMessage = new ZIMTextMessage();
textMessage.message = "Hello, Channel!";
const config = {
// Set message priority: LOW(1) / MEDIUM(2) / HIGH(3)
priority: ZIMMessagePriority.LOW,
};
try {
const result = await zim.sendMessage(
textMessage,
conversationID,
ZIMConversationType.COMMUNITY_CHANNEL, // Conversation type: Community channel
config
);
// Message sent successfully
} catch (error) {
// Message sending failed, handle based on error.code
}
Example code
// After obtaining the target channel, use its conversationID to send a message
final conversationID = channel.conversationID; // From the queryCommunityChannelList result
final textMessage = ZIMTextMessage(message: 'Hello, Channel!');
final config = ZIMMessageSendConfig()
..priority = ZIMMessagePriority.low; // Set message priority: low / medium / high
try {
final result = await ZIM.getInstance()!.sendMessage(
textMessage,
conversationID,
ZIMConversationType.communityChannel, // Conversation type: Community channel
config: config,
);
// Message sent successfully
} catch (error) {
// Message sending failed, handle based on error.code
}
// After obtaining the target channel, use its conversationID to send a message
final conversationID = channel.conversationID; // From the queryCommunityChannelList result
final textMessage = ZIMTextMessage(message: 'Hello, Channel!');
final config = ZIMMessageSendConfig()
..priority = ZIMMessagePriority.low; // Set message priority: low / medium / high
try {
final result = await ZIM.getInstance()!.sendMessage(
textMessage,
conversationID,
ZIMConversationType.communityChannel, // Conversation type: Community channel
config: config,
);
// Message sent successfully
} catch (error) {
// Message sending failed, handle based on error.code
}
Rich media messages
When sending rich media messages such as images, files, audio, and video, also set conversationType to ZIMConversationType.COMMUNITY_CHANNEL. The rest of the usage is consistent with group messages.
// Example: sending an image message
ZIMImageMessage imageMessage = new ZIMImageMessage(
"/storage/emulated/0/Android/data/com.example/pictures/photo.jpg"
);
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
config.setPriority(ZIMMessagePriority.MEDIUM);
zim.sendMessage(
imageMessage,
conversationID,
ZIMConversationType.COMMUNITY_CHANNEL,
config,
new ZIMMessageSentFullCallback() {
@Override
public void onMessageAttached(ZIMMessage message) {
// You can show an image placeholder UI here
}
@Override
public void onMessageSent(ZIMMessage message, ZIMError error) {
if (error.code == ZIMErrorCode.SUCCESS) {
// Image sent successfully; message contains the server-generated fileDownloadUrl
}
}
@Override
public void onMediaUploadingProgress(
ZIMMediaMessage message, long currentFileSize, long totalFileSize) {
// You can update the upload progress bar here
}
}
);
// Example: sending an image message
ZIMImageMessage imageMessage = new ZIMImageMessage(
"/storage/emulated/0/Android/data/com.example/pictures/photo.jpg"
);
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
config.setPriority(ZIMMessagePriority.MEDIUM);
zim.sendMessage(
imageMessage,
conversationID,
ZIMConversationType.COMMUNITY_CHANNEL,
config,
new ZIMMessageSentFullCallback() {
@Override
public void onMessageAttached(ZIMMessage message) {
// You can show an image placeholder UI here
}
@Override
public void onMessageSent(ZIMMessage message, ZIMError error) {
if (error.code == ZIMErrorCode.SUCCESS) {
// Image sent successfully; message contains the server-generated fileDownloadUrl
}
}
@Override
public void onMediaUploadingProgress(
ZIMMediaMessage message, long currentFileSize, long totalFileSize) {
// You can update the upload progress bar here
}
}
);
// Example: sending an image message
auto imageMessage = ZIMImageMessage("/path/to/photo.jpg");
ZIMMessageSendConfig config;
config.priority = ZIMMessagePriority::MEDIUM;
zim->sendMessage(
imageMessage,
conversationID,
ZIMConversationType::COMMUNITY_CHANNEL,
config,
[](ZIMMessage message, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
// Image sent successfully; message contains the server-generated fileDownloadUrl
}
});
// Example: sending an image message
auto imageMessage = ZIMImageMessage("/path/to/photo.jpg");
ZIMMessageSendConfig config;
config.priority = ZIMMessagePriority::MEDIUM;
zim->sendMessage(
imageMessage,
conversationID,
ZIMConversationType::COMMUNITY_CHANNEL,
config,
[](ZIMMessage message, ZIMError error) {
if (error.code == ZIMErrorCodeSuccess) {
// Image sent successfully; message contains the server-generated fileDownloadUrl
}
});
Example code
// Example: sending an image message
const imageMessage = new ZIMImageMessage({ fileLocalPath: '/path/to/photo.jpg' });
const config = {
priority: ZIMMessagePriority.MEDIUM,
};
try {
const result = await zim.sendMessage(
imageMessage,
conversationID,
ZIMConversationType.COMMUNITY_CHANNEL,
config
);
// Image sent successfully
} catch (error) {
// Image sending failed, handle based on error.code
}
// Example: sending an image message
const imageMessage = new ZIMImageMessage({ fileLocalPath: '/path/to/photo.jpg' });
const config = {
priority: ZIMMessagePriority.MEDIUM,
};
try {
const result = await zim.sendMessage(
imageMessage,
conversationID,
ZIMConversationType.COMMUNITY_CHANNEL,
config
);
// Image sent successfully
} catch (error) {
// Image sending failed, handle based on error.code
}
Example code
// Example: sending an image message
final imageMessage = ZIMImageMessage(fileLocalPath: '/path/to/photo.jpg');
final config = ZIMMessageSendConfig()
..priority = ZIMMessagePriority.medium;
try {
final result = await ZIM.getInstance()!.sendMessage(
imageMessage,
conversationID,
ZIMConversationType.communityChannel,
config: config,
);
// Image sent successfully
} catch (error) {
// Image sending failed, handle based on error.code
}
// Example: sending an image message
final imageMessage = ZIMImageMessage(fileLocalPath: '/path/to/photo.jpg');
final config = ZIMMessageSendConfig()
..priority = ZIMMessagePriority.medium;
try {
final result = await ZIM.getInstance()!.sendMessage(
imageMessage,
conversationID,
ZIMConversationType.communityChannel,
config: config,
);
// Image sent successfully
} catch (error) {
// Image sending failed, handle based on error.code
}
Note
For the construction and sending parameters of each message type (custom messages, combined messages, etc.), please refer to Send and receive messages. Simply replace the conversationType in the corresponding example code with ZIMConversationType.COMMUNITY_CHANNEL, and replace toConversationID with the channel's conversationID.
Receive messages
Starting from ZIM SDK 3.0.0, all online messages from one-on-one chats, groups, rooms, and Community channels are received through the unified onMessageReceived callback. The callback returns ZIMMessageReceivedEventResult, where the receivedInfo.conversationType field is used to determine the conversation type to which the message belongs.
zim.setEventHandler(new ZIMEventHandler() {
@Override
public void onMessageReceived(ZIM zim, ZIMMessageReceivedEventResult result) {
ZIMMessageReceivedInfo info = result.getReceivedInfo();
// Filter Community channel messages
if (info.getConversationType() == ZIMConversationType.COMMUNITY_CHANNEL) {
String conversationID = info.getConversationID(); // conversationID of the channel the message belongs to
for (ZIMMessage message : result.getMessageList()) {
// Handle by message type
switch (message.getType()) {
case TEXT:
ZIMTextMessage textMsg = (ZIMTextMessage) message;
// Handle text message
break;
case IMAGE:
ZIMImageMessage imageMsg = (ZIMImageMessage) message;
// Handle image message; call downloadMediaFile to download the original image
break;
default:
break;
}
}
}
}
});
zim.setEventHandler(new ZIMEventHandler() {
@Override
public void onMessageReceived(ZIM zim, ZIMMessageReceivedEventResult result) {
ZIMMessageReceivedInfo info = result.getReceivedInfo();
// Filter Community channel messages
if (info.getConversationType() == ZIMConversationType.COMMUNITY_CHANNEL) {
String conversationID = info.getConversationID(); // conversationID of the channel the message belongs to
for (ZIMMessage message : result.getMessageList()) {
// Handle by message type
switch (message.getType()) {
case TEXT:
ZIMTextMessage textMsg = (ZIMTextMessage) message;
// Handle text message
break;
case IMAGE:
ZIMImageMessage imageMsg = (ZIMImageMessage) message;
// Handle image message; call downloadMediaFile to download the original image
break;
default:
break;
}
}
}
}
});
Example code
zim.eventHandler = self;
- (void)zim:(ZIM *)zim messageReceivedWithResult:(ZIMMessageReceivedEventResult *)result {
ZIMMessageReceivedInfo *info = result.receivedInfo;
// Filter Community channel messages
if (info.conversationType == ZIMConversationTypeCommunityChannel) {
NSString *conversationID = info.conversationID;
for (ZIMMessage *message in result.messageList) {
// Handle by message type
if ([message isKindOfClass:[ZIMTextMessage class]]) {
ZIMTextMessage *textMsg = (ZIMTextMessage *)message;
// Handle text message
} else if ([message isKindOfClass:[ZIMImageMessage class]]) {
ZIMImageMessage *imageMsg = (ZIMImageMessage *)message;
// Handle image message
}
}
}
}
zim.eventHandler = self;
- (void)zim:(ZIM *)zim messageReceivedWithResult:(ZIMMessageReceivedEventResult *)result {
ZIMMessageReceivedInfo *info = result.receivedInfo;
// Filter Community channel messages
if (info.conversationType == ZIMConversationTypeCommunityChannel) {
NSString *conversationID = info.conversationID;
for (ZIMMessage *message in result.messageList) {
// Handle by message type
if ([message isKindOfClass:[ZIMTextMessage class]]) {
ZIMTextMessage *textMsg = (ZIMTextMessage *)message;
// Handle text message
} else if ([message isKindOfClass:[ZIMImageMessage class]]) {
ZIMImageMessage *imageMsg = (ZIMImageMessage *)message;
// Handle image message
}
}
}
}
Example code
zim->setEventHandler([&](ZIMMessageReceivedEventResult result) {
auto info = result.receivedInfo;
// Filter Community channel messages
if (info.conversationType == ZIMConversationType::COMMUNITY_CHANNEL) {
std::string conversationID = info.conversationID;
for (auto& message : result.messageList) {
// Handle by message type
if (message.type == ZIMMessageType::TEXT) {
auto textMsg = std::static_pointer_cast<ZIMTextMessage>(message);
// Handle text message
} else if (message.type == ZIMMessageType::IMAGE) {
auto imageMsg = std::static_pointer_cast<ZIMImageMessage>(message);
// Handle image message; call downloadMediaFile to download the original image
}
}
}
});
zim->setEventHandler([&](ZIMMessageReceivedEventResult result) {
auto info = result.receivedInfo;
// Filter Community channel messages
if (info.conversationType == ZIMConversationType::COMMUNITY_CHANNEL) {
std::string conversationID = info.conversationID;
for (auto& message : result.messageList) {
// Handle by message type
if (message.type == ZIMMessageType::TEXT) {
auto textMsg = std::static_pointer_cast<ZIMTextMessage>(message);
// Handle text message
} else if (message.type == ZIMMessageType::IMAGE) {
auto imageMsg = std::static_pointer_cast<ZIMImageMessage>(message);
// Handle image message; call downloadMediaFile to download the original image
}
}
}
});
Example code
zim.on('messageReceived', (result: ZIMMessageReceivedEventResult) => {
const info = result.receivedInfo;
// Filter Community channel messages
if (info.conversationType === ZIMConversationType.COMMUNITY_CHANNEL) {
const conversationID = info.conversationID;
for (const message of result.messageList) {
// Handle by message type
if (message.type === ZIMMessageType.TEXT) {
const textMsg = message as ZIMTextMessage;
// Handle text message
} else if (message.type === ZIMMessageType.IMAGE) {
const imageMsg = message as ZIMImageMessage;
// Handle image message; call downloadMediaFile to download the original image
}
}
}
});
zim.on('messageReceived', (result: ZIMMessageReceivedEventResult) => {
const info = result.receivedInfo;
// Filter Community channel messages
if (info.conversationType === ZIMConversationType.COMMUNITY_CHANNEL) {
const conversationID = info.conversationID;
for (const message of result.messageList) {
// Handle by message type
if (message.type === ZIMMessageType.TEXT) {
const textMsg = message as ZIMTextMessage;
// Handle text message
} else if (message.type === ZIMMessageType.IMAGE) {
const imageMsg = message as ZIMImageMessage;
// Handle image message; call downloadMediaFile to download the original image
}
}
}
});
Example code
ZIMEventHandler.onMessageReceived = (ZIM zim, ZIMMessageReceivedEventResult result) {
final info = result.receivedInfo;
// Filter Community channel messages
if (info.conversationType == ZIMConversationType.communityChannel) {
final conversationID = info.conversationID;
for (final message in result.messageList) {
// Handle by message type
if (message is ZIMTextMessage) {
// Handle text message
} else if (message is ZIMImageMessage) {
// Handle image message; call downloadMediaFile to download the original image
}
}
}
};
ZIMEventHandler.onMessageReceived = (ZIM zim, ZIMMessageReceivedEventResult result) {
final info = result.receivedInfo;
// Filter Community channel messages
if (info.conversationType == ZIMConversationType.communityChannel) {
final conversationID = info.conversationID;
for (final message in result.messageList) {
// Handle by message type
if (message is ZIMTextMessage) {
// Handle text message
} else if (message is ZIMImageMessage) {
// Handle image message; call downloadMediaFile to download the original image
}
}
}
};
Note
After a user logs back in, they can receive channel messages that accumulated during offline time through this callback (requires the server to enable channel offline message storage).
To proactively pull history messages, please refer to Get message history, passing in the channel's conversationID and ZIMConversationType.COMMUNITY_CHANNEL.
Advanced operations
In addition to basic message sending and receiving, Community channels also support the following advanced messaging operations. For each feature, pass the channel's conversationID as the conversationID and ZIMConversationType.COMMUNITY_CHANNEL as the conversationType. For detailed usage, refer to the corresponding documentation.