Quick Integration of Live Chatroom
This tutorial describes how to quickly implement a live chatroom on Android (Java) using RC's IM SDK.
Prerequisites
Create a RC developer account and obtain an [App Key].
Step 1: Import the SDK
Using Android Studio's Gradle build system, you can add RC's Instant Messaging library (IMLib) as either a remote dependency or a local Android library module to your build.
This tutorial demonstrates adding it as a remote dependency. Note that you'll need to use RC's Maven repository.
-
Open the root-level
build.gradle(under Project view) and declare RC's Maven repository.allprojects {
repositories {
...
// RC Maven repository address
maven {url "https://maven.rongcloud.cn/repository/maven-releases/"}
}
} -
In your app's
build.gradle, add RC's Instant Messaging library (IMLib) as a remote dependency.dependencies {
...
api 'cn.rongcloud.sdk:im_libcore:5.4.1'
api 'cn.rongcloud.sdk:im_chatroom:5.4.1'
}
Step 2: Initialize the SDK
Initialize the SDK in the Application's onCreate() method by passing the App Key and initialization configuration (InitOption). If your App Key doesn't belong to the China (Beijing) data center, you must specify the navigation server and statistics server addresses in the initialization configuration.
String appKey = "Your_AppKey";
InitOption initOption = new InitOption.Builder()
.setNaviServer("http(s)://naviServer") // Required for Singapore or North America data centers
.setStatisticServer("http(s)://StatisticServer") // Required for Singapore or North America data centers
.build();
RongCoreClient.init(context, appKey, initOption);
- Singapore Data Center Navi Server addresses: nav.sg-light-edge.com (primary), nav-b.sg-light-edge.com (backup)
- Singapore Data Center StatisticServer address: stats.sg-light-edge.com
Step 3: Add Message Listener
Your app needs to receive messages and notifications through the message listener provided by the SDK. The current user will receive all types of messages through this listener. We recommend registering the message listener throughout the app's lifecycle.
RongCoreClient.addOnReceiveMessageListener(
new OnReceiveMessageWrapperListener() {
@Override
public boolean onReceivedMessage(Message message, int left, boolean hasPackage, boolean offline) {
///
return false;
}
});
Step 4: Establish IM Connection
You must establish an IM connection with RC servers before using the instant messaging features. A user Token is required to establish the connection.
The user Token represents the user's unique identifier in RC. You need to maintain your app's user registration process, assign unique user identifiers (User IDs), and use these IDs to request Tokens from RC for establishing IM connections.
Step 4.1: Obtain Token
The client SDK doesn't provide an API for obtaining Tokens. You need to use RC's server-side API to get a Token.
Exchange your app's user ID (userId) for an authentication Token used in RC services. The same user ID can obtain multiple Tokens - any valid Token can be used to connect to RC services. Use the same interface if you need to reacquire a Token for the same user ID.
Authentication is required when calling RC's server-side APIs. Add the following HTTP header fields to your request:
App-Key: App KeyNonce: Random numberTimestamp: Unix timestampSignature: Concatenate App Secret, Nonce, and Timestamp in order, then compute the SHA1 hash. The App Secret corresponds to your App Key and can be obtained from the [App Key] page in RC Console.
If your App Key doesn't belong to the China (Beijing) data center, you must use the corresponding overseas API service address.
- Beijing: api.rong-api.com
- Singapore: api.sg-light-api.com (primary), api-b.sg-light-api.com (backup)
When obtaining a Token, the HTTP request body must include the user ID (userId), name (name), and avatar (portraitUri).
POST /user/getToken.json HTTP/1.1
Host: api.rong-api.com
App-Key: Your_AppKey
Nonce: 14314
Timestamp: 1408710653491
Signature: 45beb7cc7307889a8e711219a47b7cf6a5b000e8
Content-Type: application/x-www-form-urlencoded
userId=jlk456j5&name=Ironman&portraitUri=http%3A%2F%2Fabc.com%2Fmyportrait.jpg
User IDs support combinations of uppercase/lowercase letters and numbers, with a maximum length of 64 bytes. Note: The name (name) and avatar (portraitUri) are only used for mobile push notifications. If you provide new data when reacquiring a Token, it will overwrite the previous name and avatar data.
The response will include the user ID and corresponding Token. The Token length is up to 256 bytes, which you can cache in your app.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"code":200, "userId":"jlk456j5", "token":"sfd9823ihufi"}
Step 4.2: Connect to Chat Server
After initialization, you can establish an IM connection using the Token obtained in the previous step. The timeLimit parameter specifies the timeout in seconds.
RongCoreClient.connect(userToken, timeLimit, new IRongCoreCallback.ConnectCallback(){
@Override
public void onDatabaseOpened(IRongCoreEnum.DatabaseOpenStatus code) {
if(IRongCoreEnum.DatabaseOpenStatus.DATABASE_OPEN_SUCCESS.equals(code)) {
//Local database opened, navigate to conversation list
} else {
//Database open failed, you can show a toast notification
}
}
@Override
public void onSuccess(String s) {
//Connection successful, if no navigation occurred in onDatabaseOpened(), you can navigate here
}
@Override
public void onError(IRongCoreEnum.ConnectionErrorCode errorCode) {
if(errorCode.equals(IRongCoreEnum.ConnectionErrorCode.RC_CONN_TOKEN_EXPIRE)) {
//Request new token from your app server, then reconnect with the new token
} else if (errorCode.equals(RongCoreClient.ConnectionErrorCode.RC_CONNECT_TIMEOUT)) {
//Connection timeout, show notification and guide users to retry when network is stable
} else {
//Handle other error codes accordingly
}
}
})
Once connected successfully, the SDK's reconnection mechanism becomes active. If disconnected due to network issues, the SDK will continuously attempt to reconnect until successful, requiring no additional connection operations from you.
Step 5: Join Chatroom
In RC's chatroom service, you need to first create a chatroom and have users join it before they can send and receive messages in the chatroom.
Typically, you would create chatrooms through server-side APIs, while users join through client SDKs. To keep this tutorial simple, we'll directly use the client-side RongChatRoomClient#joinChatRoom interface that combines both creation and joining.
String chatroomId = "chatroomA";
int defMessageCount = -1;
RongChatRoomClient.getInstance().joinChatRoom(chatroomId, defMessageCount, new IRongCoreCallback.OperationCallback() {
@Override
public void onSuccess() {
}
@Override
public void onError(IRongCoreEnum.CoreErrorCode coreErrorCode) {
}
});
The defMessageCount variable specifies the number of historical messages to retrieve when joining the chatroom. A value of -1 means no historical messages will be retrieved.
To join an existing chatroom, you can call the RongChatRoomClient#joinExistChatRoom method.
Step 6: Send Messages
Use the core class RongCoreClient to send messages. Note that the client SDK has a message rate limit of 5 messages per second.
Step 6.1: Constructing Messages
All messages can be divided into two main categories: regular messages and multimedia messages. The parent class for regular messages is [MessageContent], while the parent class for media messages is [MediaMessageContent]. The fundamental difference between sending media messages and regular messages lies in whether there is an upload process.
Regular messages typically refer to text messages. The following example constructs a text message:
String targetId = "chatroom ID";
ConversationType conversationType = Conversation.ConversationType.CHATROOM;
TextMessage messageContent = TextMessage.obtain("Hello");
Message message = Message.obtain(targetId, conversationType, messageContent);
Media messages generally include image messages, GIFs, etc. The following example constructs an image message:
```java
String targetId = "chatroom ID";
ConversationType conversationType = Conversation.ConversationType.CHATROOM;
Uri localUri = Uri.parse("file://path_to_image"); // Local path of the image. The recipient can obtain the automatically generated thumbnail Uri via getThumUri
boolean mIsFull = true; // Whether to send the original image
ImageMessage mediaMessageContent = ImageMessage.obtain(localUri, mIsFull);
Message message = Message.obtain(targetId, conversationType, channelId, mediaMessageContent);
### Step 6.2: Sending Messages
To send messages that do not involve media file uploads, such as RC's built-in text messages or custom messages without media upload processes, use the `sendMessage` method:
```java
RongCoreClient.getInstance().sendMessage(message, null, null, new IRongCoreCallback.ISendMessageCallback() {
@Override
public void onAttached(Message message) {
}
@Override
public void onSuccess(Message message) {
}
@Override
public void onError(Message message, IRongCoreEnum.CoreErrorCode errorCode) {
}
});
To send media messages, use the `sendMediaMessage` method. This method first uploads media files (images, videos, etc.) to RC's default file server ([File Storage Duration](https://help.rongcloud.cn/t/topic/1049)) before sending the message upon successful upload:
```java
RongCoreClient.getInstance().sendMediaMessage(message, null, null, new IRongCoreCallback.ISendMediaMessageCallback() {
@Override
public void onProgress(Message message, int i) {
}
@Override
public void onCanceled(Message message) {
}
@Override
public void onAttached(Message message) {
}
@Override
public void onSuccess(Message message) {
}
@Override
public void onError(final Message message, final IRongCoreEnum.CoreErrorCode errorCode) {
}
});
## Step 7: Saving Historical Messages
Local chatroom messages for the current user are automatically deleted upon exiting the chatroom. Before exiting, you can retrieve local historical message records. With the **Cloud Storage for Chatroom Messages** service enabled, chatroom messages can be stored on RC's server. Clients can directly access messages stored on the server.
Typically, first call `getHistoryMessages` to retrieve local historical records. If empty, then call `getChatroomHistoryMessages` to fetch remote historical records. Note that `getChatroomHistoryMessages` will not return messages already existing in the local database.
```java
Conversation.ConversationType conversationType = Conversation.ConversationType.CHATROOM;
int oldestMessageId = -1;
final int count = 10;
final String targetId = "chatroom ID";
final long recordTime = 0;
RongCoreClient.getInstance().getHistoryMessages(conversationType, targetId, oldestMessageId, count,
new IRongCoreCallback.ResultCallback<List<Message>>() {
@Override
public void onSuccess(List<Message> messages) {
| if (messages == null || messages.isEmpty()) { |
RongChatRoomClient.getInstance().getChatroomHistoryMessages(targetId, recordTime, count, IRongCoreEnum.TimestampOrder.RC_TIMESTAMP_ASC,
new IRongCoreCallback.IChatRoomHistoryMessageCallback() {
@Override
public void onSuccess(List<Message> messages, long syncTime) {
}
@Override
public void onError(IRongCoreEnum.CoreErrorCode code) {
}
});
}
}
@Override
public void onError(IRongCoreEnum.CoreErrorCode errorCode) {
}
});
`oldestMessageId` set to `-1` indicates querying from the latest local message.
`getChatroomHistoryMessages` returns an array of historical messages and `syncTime` in the success callback. If the fetch order is `RC_Timestamp_Desc`, `syncTime` represents the timestamp of the earliest message in the results (i.e., the smallest timestamp). If the fetch order is `RC_Timestamp_Asc`, it represents the timestamp of the latest message (i.e., the largest timestamp). With the same fetch order, the returned `syncTime` can be used as the `recordTime` for the next fetch, facilitating continuous retrieval.
## Step 8: Recalling Messages
If an App administrator or regular user wishes to delete a message from all chatroom members' chat histories, they can use the message recall feature. Upon successful recall, the original message content will be deleted from all users' local and server-side historical records.
```java
Message message = Message.obtain("123", ConversationType.GROUP, "12345");
RongCoreClient.getInstance().recallMessage(message, "", new IRongCoreCallback.ResultCallback<RecallNotificationMessage>() {
/**
* Success callback
*/
@Override
public void onSuccess(RecallNotificationMessage recallNotificationMessage) {
}
/**
* Failure callback
* @param errorCode Error code
*/
@Override
public void onError(IRongCoreEnum.CoreErrorCode errorCode) {
}
});
## Step 9: Banning Users
The IM service supports various banning and muting capabilities. Client-side APIs are not provided; you can implement these features via server-side APIs.
### Banning Specific Users
Ban App users, with a maximum of 20 user IDs (`userId`) per request. The `minute` parameter specifies the ban duration, up to 43,200 minutes. Once banned, the user's IM connection is immediately terminated. During the ban, the user cannot establish an IM connection with RC or actively use IM services.
- Ban:
```http
POST /user/block.json HTTP/1.1
Host: api.rong-api.com
App-Key: uwd1c0sxdlx2
Nonce: 14314
Timestamp: 1408710653491
Signature: 45beb7cc7307889a8e711219a47b7cf6a5b000e8
Content-Type: application/x-www-form-urlencoded
userId=UserA&minute=10
-
Unban:
POST /user/unblock.json HTTP/1.1
Host: api.rong-api.com
App-Key: uwd1c0sxdlx2
Nonce: 14314
Timestamp: 1408710653491
Signature: 45beb7cc7307889a8e711219a47b7cf6a5b000e8
Content-Type: application/x-www-form-urlencoded
userId=UserA
Muting Chatroom Users
The chatroom service supports muting users. You can mute up to 20 users (userId) in a specified chatroom (chatroomId) at a time. The minute parameter indicates the duration of the mute, with a maximum mute duration of 43,200 minutes. Muted users can still receive and view messages from other users in the chatroom but cannot send messages to the chatroom via the client SDK. A user leaving the chatroom does not lift the mute status.
-
Mute a User
POST /chatroom/user/gag/add.json HTTP/1.1
Host: api.rong-api.com
App-Key: uwd1c0sxdlx2
Nonce: 14314
Timestamp: 1408710653491
Signature: 45beb7cc7307889a8e711219a47b7cf6a5b000e8
Content-Type: application/x-www-form-urlencoded
userId=UserA&chatroomId=16&minute=1 -
Unmute a User:
POST /chatroom/user/gag/rollback.json HTTP/1.1
Host: api.rong-api.com
App-Key: uwd1c0sxdlx2
Nonce: 14314
Timestamp: 1408710653491
Signature: 45beb7cc7307889a8e711219a47b7cf6a5b000e8
Content-Type: application/x-www-form-urlencoded
userId=UserA&chatroomId=16
Muting a Chatroom
The chatroom service supports muting an entire chatroom (chatroomId). Once muted, all users in the chatroom will be unable to send messages to the chatroom via the client SDK. To allow exceptions for specific users, you can add them to the chatroom mute allowlist (not covered in this tutorial). If the chatroom is disbanded, all mute data will be cleared.
-
Mute a Chatroom
POST /chatroom/ban/add.json HTTP/1.1
Host: api.rong-api.com
App-Key: uwd1c0sxdlx2
Nonce: 14314
Timestamp: 1408710653491
Signature: 45beb7cc7307889a8e711219a47b7cf6a5b000e8
Content-Type: application/x-www-form-urlencoded
chatroomId=123 -
Unmute a Chatroom:
POST /chatroom/ban/rollback.json HTTP/1.1
Host: api.rong-api.com
App-Key: uwd1c0sxdlx2
Nonce: 14314
Timestamp: 1408710653491
Signature: 45beb7cc7307889a8e711219a47b7cf6a5b000e8
Content-Type: application/x-www-form-urlencoded
chatroomId=123
The chatroom service also supports muting a specified user across all chatrooms in the application, with configurable mute duration. During the mute period, the muted user will be unable to send messages via the client SDK in any chatroom within the application. This feature requires enabling the Chatroom Global Mute service and is not covered in this tutorial.
Appendix: Implementing Chatroom Likes
You can implement a like feature in chatrooms using custom messages.
-
Create a custom message type that extends
MessageContent, such asXappChatroomLike. The like message will contain this content.import android.os.Parcel;
import io.rong.imlib.MessageTag;
import io.rong.imlib.model.MessageContent;
@MessageTag(value = "Xapp:Chatroom:Like")
public class XappChatroomLike extends MessageContent {
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
}
public void readFromParcel(Parcel source) {
}
public XappChatroomLike() {
}
public XappChatroomLike(byte[] data){
}
@Override
public byte[] encode() {
return new byte[0];
}
protected XappChatroomLike(Parcel in) {
}
public static final Creator<XappChatroomLike> CREATOR = new Creator<XappChatroomLike>() {
@Override
public XappChatroomLike createFromParcel(Parcel source) {
return new XappChatroomLike(source);
}
@Override
public XappChatroomLike[] newArray(int size) {
return new XappChatroomLike[size];
}
};
} -
Register
XappChatroomLikewith the SDK before calling theRongCoreClient#connectmethod.ArrayList<Class<? extends MessageContent>> myMessageContents = new ArrayList<>();
myMessageContents.add(XappChatroomLike.class);
RongCoreClient.registerMessageType(myMessageContents); -
When a like is triggered, construct the like message and send it using the
sendMessagemethod.String targetId = "Chatroom ID";
ConversationType conversationType = Conversation.ConversationType.CHATROOM;
XappChatroomLike messageContent = XappChatroomLike();
Message message = Message.obtain(targetId, conversationType, messageContent); -
When other users in the chatroom receive the message, check if it is an
XappChatroomLike. If it is a like message, display the like effect in the UI.RongCoreClient.addOnReceiveMessageListener(
new OnReceiveMessageWrapperListener() {
@Override
public boolean onReceivedMessage(Message message, int left, boolean hasPackage, boolean offline) {
MessageContent msgContent = message.getContent();
if (msgContent instanceof XappChatroomLike) {
}
return false;
}
});