Send and receive messages
This document describes how to use the ZIM SDK (In-app Chat) to send and receive messages.
Solution
The following shows the access solution that the ZIM SDK provides.
In this solution, you will need to implement the following business logic based on your actual business requirements:
- The logic for managing the users on the client, and the logic for distributing user ID for users to log in.
Prerequisites
Before you begin, make sure:
-
Go to ZEGOCLOUD Admin Console, and do the following:
- Create a project, get the AppID and AppSign.
- Activate the In-app Chat service (as shown in the following figure).
-
Visual Studio 2015 or later
-
Windows 7 or later
Integrate the SDK
Optional: Create a project
Skip this step if a project already exists.
Import the SDK
-
Download the latest version of SDK from SDK downloads.
-
Extract the files from the SDK packages and copy the files to your project directory.
The SDK package includes two directories: include and lib. The SDK contains two folders as illustrated below:
Untitledx86 --------------- 32-bit version | include --------------- SDK header file included. x64 --------------- 64-bit version | include --------------- SDK header file included.
1
Set project property
To set project property, right-click the project name in the Solution Explorer window, click Properties, and configure the following :
- Add the
include
directory to the header file search path.
- C/C++ -> General-> Add the
include
directory to Additional include Directories
- Add the
lib
directory to the library search path.
- Linker-> General-> Add the library directory
lib/x86
orlib/x64
to the Additional Library Directories
- Specify the link library
ZIM.lib
.
- Linker-> Input-> Add
ZIM.lib
to Additional Dependencies
Implementation steps
Get the sample code
To download and run the sample code, see Sample app.
For the sample code related to this feature, check out the source files in the CZIMConversationView.h
and CZIMConversationView.cpp
files under the ZIMDemo
directory in the SDK sample code package.
Import the header file
Import the header file ZIM.h
to the project, and define the macro ZIM_MAIN_CONFIG
once in the source file of the project file (*.cpp
or *.cc
file) (you only need to define the macro once at the very beginning).
//The header file.
#include "ZIM.h"
...
//The source file.
#include "pch.h"
#define ZIM_MAIN_CONFIG
#include "framework.h"
...
Create a ZIM SDK instance
Creating a ZIM instance is the very first step, an instance corresponds to a user logging in to the system as a client.
So, let's suppose we have two clients now, client A and client B. To send and receive messages to each other, both of them will need to call the create method with the AppID and the AppSign you get in the previous Prerequisites steps to create a ZIM SDK instance of their own:
// Create a ZIM SDK instance. We recommend creating a ZIM SDK instance for a client.
zim::ZIMAppConfig app_config;
app_config.appID = 0; //替换为您申请到的 AppID
app_config.appSign = ""; //替换为您申请到的 AppSign
zim_ = zim::ZIM::create(app_config);
Set an event handler object
Before a client user's login, you will need to call the setEventHandler method to implement an event handler object, and customize the event callbacks, such as you can receive callback notifications when SDK errors occur or receive message related callback notifications.
class CZIMEventHandler :public zim::ZIMEventHandler
{
public:
CZIMEventHandler();
~CZIMEventHandler();
private:
// The callback for receiving error codes. This callback will be triggered when SDK returns error codes.
virtual void onError(zim::ZIM* /*zim*/, zim::ZIMError /*errorInfo*/, const std::string& /*desc*/) override;
// The callback for connection status changes. This callback will be triggered when the connection status changes, and you can customize a UI for this event.
virtual void onConnectionStateChanged(zim::ZIM* /*zim*/, zim::ZIMConnectionState /*state*/, zim::ZIMConnectionEvent /*event*/, const std::string& /*extendedData*/) override;
// The callback for Token expires. This callback will be triggered when the Token is about to expire, and you can customize a UI for this event.
virtual void onTokenWillExpire(zim::ZIM* /*zim*/, unsigned int /*second*/) override;
// The callback for receiving one-to-one messages. You can receive message notifications through this callback after login.
virtual void onPeerMessageReceived(ZIM * /*zim*/, const std::vector<std::shared_ptr<ZIMMessage>> & /*messageList*/,const ZIMMessageReceivedInfo & /*info*/, const std::string & /*fromUserID*/) override;
}
im_event_handler_ = std::make_shared<CZIMEventHandler>();
zim_->setEventHandler(im_event_handler_);
// You can set the event callbacks by Register##callback_name as needed.
For a detailed introduction to the interfaces, please refer to onConnectionStateChanged, onTokenWillExpire, onPeerMessageReceived.
You need to switch to your own thread for further operations When you receive callbacks.
For example, when you receive an in-room message, to process the message, you need to switch it to your own thread (the following sample code is for switching to the UI thread).
// The OnReceiveRoomMessage here refers to the onReceiveRoomMessage of the bounded SDK.
void CZIMDemoDlg::OnRoomMessageReceived(zim::ZIM* zim,
const std::vector<std::shared_ptr<zim::ZIMMessage>>& message_list,
const ZIMMessageReceivedInfo& info, const std::string& from_room_id)
{
global_main_dialog_->PostUiThread([=]() {
global_main_dialog_->im_mode_select_dialog_->OnRoomMessageReceived(zim, message_list, info, from_room_id);
});
}
Log in to the ZIM SDK
For client A and client B to send, receive, and renew the Token after creating the ZIM SDK instance, they will need to log in to the ZIM SDK.
The clients need to log in using their respective user information. Call the login interface, passing in the userID and ZIMLoginConfig object to log in.
- You can custom the userID and userName, and we recommend you set the userID to a meaningful value and associate them with the account system of your application.
- For SDK 2.3.0 or later: The SDK uses the AppSign authentication by default. You only need to leave the Token blank when logging in.
- If you use the Token-based authentication mode, please refer to the Authentication to get the Token first, and pass it when logging in.
// userID must be within 32 bytes, and can only contain letters, numbers, and the following special characters: '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '=', '-', '`', ';', '’', ',', '.', '<', '>', '/', '\'.
// userName must be within 256 bytes, no special characters limited.
zim::ZIMLoginConfig config;
config.userName = "";
// If you are using the Token-based authentication mode, you will need to fill in the Token which you generated by referring to the [Authentication] doc.
// If you are using the AppSign mode for authentication (the default auth mode for v2.3.0 or later), leave the Token parameter blank.
config.token = "";
zim_->login(userID, config, [=](zim::ZIMError errorInfo){
// You can get the return code to check whether the login is successful. And handle it accordingly if the login fails.
});
Send messages
Client A can send messages to client B after logging in successfully.
Currently, the ZIM SDK supports the following message types:
Message Type | Description | Feature and Scenario |
---|---|---|
ZIMCommandMessage(2) | The signaling message whose content can be customized. A signaling message cannot exceed 5 KB in size, and up to 10 signaling messages can be sent per second per client. | Signaling messages, unable to be stored, are applicable to signaling transmission (for example, co-hosting, virtual gifting, and course materials sending) in scenarios with a higher concurrency, such as chat rooms and online classrooms. API: sendMessage |
ZIMBarrageMessage(20) | On-screen comments in a chat room. An on-screen comment cannot exceed 5 KB in size, and there is no number limit on comments that can be sent per second per client. | On-screen comments, unable to be stored are usually unreliable messages that are sent at a high frequency and can be discarded. A high concurrency is supported, but reliability cannot be guaranteed. API: sendMessage |
ZIMTextMessage(1) | The text message. A text message cannot exceed 32 KB in size, and up to 10 text messages can be sent per second per client. | Text messages are reliable, in order, and able to be stored as historical messages. (For the storage duration, please refer to Pricing - Plan Fee - Plan Differences).
API: sendMessage、replyMessage |
ZIMMultipleMessage(10) | Multi-item message, a message that can include multiple texts, up to 10 images, 1 file, 1 audio, 1 video, and 1 custom message. Note
| |
ZIMImageMessage(11) | Image message. Applicable formats includes JPG, PNG, BMP, TIFF, GIF, and WebP. The maximum size is 10 MB. Up to 10 image messages can be sent per second per client. | |
ZIMFileMessage(12) | File Message. A file message contains a file of any format and cannot exceed 100 MB in size. Up to 10 file messages can be sent per second per client. | |
ZIMAudioMessage(13) | Audio message. An audio message contains an MP3 or M4A audio of up to 300 seconds and cannot exceed 6 MB in size. Up to 10 audio messages can be sent per second per client. | |
ZIMVideoMessage(14) | A video message contains an MP4 or MOV video and cannot exceed 100 MB in size. Up to 10 video messages can be sent per second per client. Note To retrieve the width and height of the first video frame after a video is successfully sent, the video must be encoded in H.264 or H.265. | |
ZIMCombineMessage(100) | For combined messages, there is no limit on message size, and the sending frequency of a single client is limited to 10 times/second. | |
ZIMCustomMessage(200) | You can customize the message type and parse the message without using the ZIM SDK. |
To send one-to-one messages, for example, client A wants to send a message to client B, then client A needs to call the sendMessage method with client B's userID, message content, and the ZIMConversationType
And client A can be notified whether the message is delivered successfully through the callback ZIMMessageSentCallback (correspond to the send_callback
shows below).
- onMessageAttached callback: The callback on the message not sent yet. Before the message is sent, you can get a temporary ZIMMessage message for you to implement your business logic as needed. For example, you can get the ID of the message before sending it. Or when sending a message with large content, such as a video, you can get the localMessageID of th
// The following shows how to send one-to-one text message.
zim::ZIMMessage* message = nullptr;
zim::ZIMTextMessage text_message;
text_message.message = "message";
// Set priority for the message. 1: Low (by default). 2: Medium. 3: High.
zim::ZIMMessageSendConfig config;
config.priority = zim::ZIM_MESSAGE_PRIORITY_LOW;
message = &text_message;
auto smessage = std::make_shared<zim::ZIMTextMessage>("test 1");
auto notification = std::make_shared<zim::ZIMMessageSendNotification>();
notification->onMessageAttached = std::move([=](const std::shared_ptr<zim::ZIMMessage> &message) { int i = 0; });
// In 1-on-1 chats, the conversationID is the peer user ID. In group chats, the conversationID is the groupID. In the chat room, the conversationID is the roomID.
zim_->sendMessage(std::static_pointer_cast<zim::ZIMMessage>(smessage), "conversationID",
zim::ZIMConversationType::ZIM_CONVERSATION_TYPE_PEER, sendConfig,
notification,
[=](const std::shared_ptr<zim::ZIMMessage> &message,
const zim::ZIMError &errorInfo) { int i = 0; });
Receive messages
After client B logs in, he will receive client A's message through the callback onPeerMessageReceived which is already set in the setEventHandler method.
When a message is received, you need to determine whether the message is a Text message or a Command message because these two message types are based on the basic message. You need to convert the basic message class to a concrete message type and then retrieve the message content from the Message
field.
void ZIMConversationView::OnReceivePeerMessage(zim::ZIM* zim, const std::vector<std::shared_ptr<zim::ZIMMessage>>& message_list, const std::string& from_user_id)
{
for (auto message : message_list)
{
if (message->type == zim::ZIM_MESSAGE_TYPE_CUSTOM)
{
auto custom_message = std::dynamic_pointer_cast<zim::ZIMCustomMessage>(message);
CFile file;
file.Open(L"Binary message file", CFile::typeBinary | CFile::shareDenyNone | CFile::modeCreate | CFile::modeReadWrite);
file.Write(&custom_message->message[0], custom_message->message.size());
}
}
auto conversation = FindConversation(Utf8ToUnicode(from_user_id), kCurrentConversationTypePeer);
conversation->messages.insert(conversation->messages.end(), message_list.begin(), message_list.end());
UpdateConversationList();
}
Log out
For a client to log out, call the logout method.
zim_->logout();
Destroy the ZIM SDK instance
To destroy the ZIM SDK instance, call the destroy method.
zim_->destroy();