Skip to main content

Red Packet Use Case Implementation

Scenario Description

Users can send red packets (containing actual currency, virtual currency, points, etc.) to specified friends in one-to-one chat or group chat conversations. Both senders and recipients can clearly perceive the status of whether the red packet has been claimed (unclaimed, claimed).

Example Effect

Red Packet Message Flow

1. Prerequisites

Before starting, ensure you have created an application and completed client SDK integration.

2. Define Red Packet Message

2.1 Define Red Packet Message Type

You can use the IMLib SDK's custom message feature to create a red packet message type (e.g., RedPacketMessage). The message content structure should be defined according to your business requirements, ensuring consistency across multiple platforms (Android / iOS / Web).

Reference implementations for Android / iOS custom message classes:

Web Example Code:

// 1. RongIMLib.registerMessageType must be called before connect(), otherwise it may cause abnormal message receiving behavior.
// 2. Please try to register all custom messages involved in the application in one unified registration, and only call registration once for the same type of message for easier management.

const messageType = 'app:red_packet' // Message type
const isPersited = true // Whether to store
const isCounted = true // Whether to count
const searchProps = [] // Search fields, no need to set for Web. When search field value is set to a number, the value range is (-Math.pow(2, 64), Math.pow(2, 64)) and must be an integer
const isStatusMessage = false // Whether it is a status message. Status messages are not stored, not counted, and can only be received when the recipient is online.
const PersonMessage = RongIMLib.registerMessageType(messageType, isPersited, isCounted, searchProps, isStatusMessage)

2.2 Define Red Packet Message Display Template

If you are using the IMKit SDK, you must create a corresponding message display template, otherwise the SDK cannot display this type of message normally.

Reference classes for Android / iOS custom red packet message display templates:

Web IMKit Custom Message Style Example Code

// Construct IMKit initialization parameters
const customMessage = {
// Regular message display
userMessage: {
// key is the custom message's messageType. Returned elements do not currently support class setting. If you need to set styles, set them as inline styles.
'app:red_packet': (message) => {
const content = message.content;
return `<div style='padding: 0.5em 0.8333em;'>Red packet from ${content.name}</div>`;
}
},
// Notification message display
notifyMessage: {
// key is the custom message's messageType. Returned elements do not currently support class setting. If you need to set styles, set them as inline styles.
'app:red_packet': (message) => {
const content = message.content
const string = `<div>Red packet from ${content.name}</div>`
return string;
}
},
// Last message in conversation display
lastMessage:{
// key is the custom message's messageType. Returned elements do not currently support class setting. If you need to set styles, set them as inline styles.
'app:red_packet': (message) => {
const content = message.content;
return `[Red packet info]`;
},
}
};

// Important note: This init is only for demonstrating custom message setup. Do not initialize multiple times in your application.
imkit.init({
customMessage:customMessage
});

3. Register and Receive Red Packet Messages

// Register custom message type, register after SDK initialization
ArrayList<Class<? extends MessageContent>> myMessages = new ArrayList<>();
myMessages.add(CustomRedPacketMessage.class);
RongCoreClient.registerMessageType(myMessages);

// Message receiving example: Set message receiving listener, will automatically callback when receiving messages. If you are using IMLib SDK, please call RongCoreClient's addOnReceiveMessageListener method
IMCenter.addOnReceiveMessageListener(
new io.rong.imlib.listener.OnReceiveMessageWrapperListener() {
@Override
public boolean onReceivedMessage(Message message, ReceivedProfile profile) {
int left = profile.getLeft();
boolean isOffline = profile.isOffline();
boolean hasPackage = profile.hasPackage();
}
});

// Returned `Message` object reference information below, you can use `objectName` or `content` to distinguish message types:

{
"conversationType": "PRIVATE",
"targetId": "userid3453",
"messageId": 70,
"channelId": "",
"messageDirection": "RECEIVE",
"senderUserId": "userid3453",
"receivedStatus": "io.rong.imlib.model.Message$ReceivedStatus @560f848",
"sentStatus": "SENT",
"receivedTime": 1739428279001,
"sentTime": 1739428279158,
"objectName": "app:red_packet",
"content": {
"content": "Red packet message"
},
"extra": "",
"readReceiptInfo": "io.rong.imlib.model.ReadReceiptInfo @b8d3c06",
"messageConfig": {
"disablePushTitle": false,
"pushTitle": "",
"pushContent": "",
"pushData": "null",
"templateId": "",
"forceShowDetailContent": false,
"iOSConfig": null,
"androidConfig": null,
"harmonyConfig": null
},
"canIncludeExpansion": false,
"expansionDic": null,
"expansionDicEx": null,
"mayHasMoreMessagesBefore": false,
"UId": "CKVO-0J6T-GM26-D3E6",
"disableUpdateLastMessage": "false",
"directedUsers": "0"
}

4. Extension Area Display (Send Red Packet Entry)

4.1 Set Red Packet Extension Panel Plugin

If you are using the IMLib SDK, you need to implement the send red packet entry yourself. If you are using the IMKit SDK, you can add custom plugins in IMKit's extension panel.

Android Implementation Process

Custom plugins need to implement the IPluginModule interface class. You can refer to IPluginModule.java in the IMKit source code, as well as specific implementation classes. Here, we use the example class RedPacketPlugin as an example of implementing a custom plugin.

iOS Implementation Process

Insert the corresponding red packet extension plugin icon in the viewDidLoad method of the chat UI page

[self.chatSessionInputBarControl.pluginBoardView insertItem:[UIImage imageNamed:@"redPacket"] highlightedImage:[UIImage imageNamed:@"redPacket"] title:@"Send Red Packet" tag:20080];

Web IMKit does not have the extension panel concept

4.2 Configure Extension Panel Plugin

Example Code

// 1. Extend `DefaultExtensionConfig` to create a custom extension panel configuration class `MyExtensionConfig`, and override the `getPluginModules()` method.

public class MyExtensionConfig extends DefaultExtensionConfig {
@Override
public List<IPluginModule> getPluginModules(Conversation.ConversationType conversationType, String targetId) {
List<IPluginModule> pluginModules = super.getPluginModules(conversationType,targetId);
// Add red packet extension item
pluginModules.add(new RedPacketPlugin());
return pluginModules;
}
}

// 2. After SDK initialization, call the `setExtensionConfig` method to set the custom input configuration. The SDK will display the extension panel according to this configuration.

RongExtensionManager.getInstance().setExtensionConfig(new MyExtensionConfig());

5. Send Red Packet Message After Successful Payment

After the user successfully completes payment, you need to call RongCloud's message sending method to send the red packet message and set the message as extensible. Choose which end to send this type of message from based on your business logic.

// Build red packet message
CustomRedPacketMessage redPacketMessage = CustomRedPacketMessage.obtain("0.01");
io.rong.imlib.model.Message message =
io.rong.imlib.model.Message.obtain(targetId, conversationType, redPacketMessage);
// Set message as extensible
message.setCanIncludeExpansion(true);
HashMap<String, String> redInfo = new HashMap<>();
redInfo.put("open","false");
redInfo.put("count","1");
redInfo.put("amount","0.01");
message.setExpansion(redInfo);
// Send message. If you are using IMLib SDK, please use RongCoreClient's sendMessage method
IMCenter.getInstance().sendMessage(message, null, null, null);

Server Example Code

 /**
* Send group gray bar message - targeted users (up to 1000 users per request)
*/
String[] targetIds = {"groupId"};
RedPacketMessage redPacketMessage =new RedPacketMessage("Red packet message");
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("open", "false");
hashMap.put("count", "1");
hashMap.put("amount", "2");
GroupMessage groupMessage = new GroupMessage()
.setSenderId("fromId")
.setIsIncludeSender(1)
.setTargetId(targetIds) // Group ID
.setContent(redPacketMessage)
.setObjectName(txtMessage.getType())
.setExpansion(true)
.setExtraContent(hashMap);

ResponseResult redPackeReslut = group.send(groupMessage);
System.out.println("group info Notify message result: " + redPackeReslut.toString());

6. Update Red Packet Extension When Opening Red Packet

After a user clicks to open a red packet, the red packet message status needs to be changed to "opened". At this point, you can update the Message Extension information of this message by setting the Message Extension Listener updateMessageExpansion, configuring the opening user ID and marking it as opened status, while simultaneously changing the locally displayed message style.

// messageUid is the unique ID of the original red packet message.

RongIMClient.getInstance()
.updateMessageExpansion(
redInfo,
messageUid,
new RongIMClient.OperationCallback() {
@Override
public void onSuccess() {
// Update initiator handles UI data refresh after extension update here
IMCenter.getInstance().refreshMessage(currentMessage);
}

@Override
public void onError(RongIMClient.ErrorCode errorCode) {
Toast.makeText(
getApplicationContext(),
"Setup failed, ErrorCode : " + errorCode.getValue(),
Toast.LENGTH_LONG)
.show();
}
});

Server Example Code

/**
*
* Set message extension
*
*/
ExpansionModel msg = new ExpansionModel();
msg.setMsgUID("BS45-NPH4-HV87-10LM");
msg.setUserId("WNYZbMqpH");
msg.setTargetId("tjw3zbMrU");
msg.setConversationType(1);
HashMap<String, String> kv = new HashMap<String, String>();
kv.put("type1", "1");
kv.put("type2", "2");
kv.put("type3", "3");
kv.put("type4", "4");
msg.setExtraKeyVal(kv);
msg.setIsSyncSender(1);
ResponseResult result = expansion.set(msg);
System.out.println("set expansion: " + result.toString());

7. Sender Updates Red Packet Message Extension

The red packet message sender can globally set message extension listeners to handle corresponding processing when receiving message extension update callbacks. It is recommended to call the client service API to obtain the latest red packet claim information.

// Recipient Android example code
RongIMClient.getInstance().setMessageExpansionListener(new RongIMClient.MessageExpansionListener() {
@Override
public void onMessageExpansionUpdate(Map<String, String> expansion, Message message) {
if (message.getContent() instanceof CustomRedPacketMessage){
IMCenter.getInstance().refreshMessage(message); // Refresh original message
// Other custom processing
}
}
});

8. Operations After Red Packet Claim

After opening the red packet, if you need to display "XX claimed the red packet", the server can send a group targeted message to the red packet sender and claimant, or monitor the message extension information to display the corresponding user information and claim status. The red packet sender can monitor the message extension information, and upon receiving the listener, proactively obtain the latest status of message claims from the business client.

// Insert gray bar message
InformationNotificationMessage informationNotificationMessage = InformationNotificationMessage.obtain("You claimed the red packet sent by xxx");

ConversationType conversationType = ConversationType.PRIVATE;
String targetId = "user1";
String senderUserId = "Simulated sender's ID";
ReceivedStatus receivedStatus = new ReceivedStatus(0x1);
String sentTime = System.currentTimeMillis();

IMCenter.getInstance().insertIncomingMessage(conversationType, targetId, senderUserId, receivedStatus, informationNotificationMessage, sentTime, new RongIMClient.ResultCallback<Message>() {
/**
* Success callback
* @param message Inserted message
*/
@Override
public void onSuccess(Message message) {

}

/**
* Failure callback
* @param errorCode Error code
*/
@Override
public void onError(RongIMClient.ErrorCode errorCode) {

}
});