红包场景实践
场景说明
用户在单聊/群聊会话中向指定好友发送红包(实际货币、虚拟货币、积分等),发送人和接收人可以明确感知红包是否被领取的状态(未领取、已领取)。
效果示例
红包消息流程
1. 准备工作
在开始之前,请确保已创建应用并完成客户端 SDK 集成。
2. 定义红包消息
2.1 定义红包消息类型
您可通过 IMLib SDK 的自定义消息,创建红包类消息类型(如 RedPacketMessage),消息内容结构需根据业务需求自行定义,确保多端(Android / iOS / Web)一致。
Android / iOS 端自定义消息类参考:
- Android 端 CustomRedPacketMessage.java
- iOS 端 CustomRedPacketMessage.h
- iOS 端 CustomRedPacketMessage.m
- Server SDK RedPacketMessage.java
Web 端示例代码:
javascript
// 1. RongIMLib.registerMessageType 必须在 connect 之前调用,否则可能造成收取消息的行为异常。
// 2. 请尽量把应用中所有涉及到的自定义消息统一一次注册,且同类型消息仅调用一次注册,便于管理。
const messageType = 'app:red_packet' // 消息类型
const isPersited = true // 是否存储
const isCounted = true // 是否计数
const searchProps = [] // 搜索字段,Web 端无需设置,搜索字段值设置为数字时取值范围为 (-Math.pow(2, 64), Math.pow(2, 64)) 且为整数
const isStatusMessage = false // 是否是状态消息。状态消息不存储、不计数,接收方在线时才能收到。
const PersonMessage = RongIMLib.registerMessageType(messageType, isPersited, isCounted, searchProps, isStatusMessage)
2.2 定义红包消息展示模板
如果您使用的是 IMKit SDK,必须创建对应的消息展示模板,否则 SDK 无法正常展示该类型消息。
Android / iOS 端自定义红包消息展示模板参考类:
- Android 端 CustomRedPacketMessageItemProvider.java
- iOS 端 CustomRedPacketMessageCell.h
- iOS 端 CustomRedPacketMessageCell.m
Web IMKit 设置自定义消息样式示例代码
javascript
// 构造 IMKit 初始化参数
const customMessage = {
// 普通消息展示
userMessage: {
// key 为自定义消息的 messageType,return 的元素中暂不支持设置 class,如需设置样式 可设置为行内样式。
'app:red_packet': (message) => {
const content = message.content;
return `<div style='padding: 0.5em 0.8333em;'>来自 ${content.name} 的红包</div>`;
}
},
// 通知类消息展示
notifyMessage: {
// key 为自定义消息的 messageType,return 的元素中暂不支持设置 class,如需设置样式可设置为行内样式。
'app:red_packet': (message) => {
const content = message.content
const string = `<div>来自 ${content.name} 的红包</div>`
return string;
}
},
// 会话最后一条消息展示
lastMessage:{
// key 为自定义消息的 messageType,return 的元素中暂不支持设置 class,如需设置样式可设置为行内样式。
'app:red_packet': (message) => {
const content = message.content;
return `[红包信息]`;
},
}
};
// 特别注意:此处 init 仅为展示自定义消息设置,应用内不需要多次进行初始化
imkit.init({
customMessage:customMessage
});
3. 注册并接收红包消息
- Android
- iOS
- Web
Java
// 注册自定义消息类型,初始化 SDK 后注册
ArrayList<Class<? extends MessageContent>> myMessages = new ArrayList<>();
myMessages.add(CustomRedPacketMessage.class);
RongCoreClient.registerMessageType(myMessages);
// 接收消息示例:设置接收消息监听器,接收消息时会自动回调,如果您使用的 IMLib SDK,请调用 RongCoreClient 的 addOnReceiveMessageListener 方法
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();
}
});
// 返回的 `Message` 实体参考下面信息,可以使用 `objectName` 或者 `content` 来区分消息类型:
{
"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": "红包消息"
},
"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"
}
Objective C
// 在初始化 SDK 后,连接 IM 之前注册自定义消息
[[RCCoreClient sharedCoreClient] registerMessageType:[CustomRedPacketMessage class]];
// 注册接收消息监听,IMLib 用户设置 [RCCoreClient sharedCoreClient] 的代理
[RCIM sharedRCIM].receiveMessageDelegate = self;
// IMKit 的代理回调:
- (void)onRCIMReceiveMessage:(RCMessage *)message left:(int)left;
// IMLib 的代理回调
- (void)onReceived:(RCMessage *)message left:(int)nLeft object:(nullable id)object;
// 获取到的自定义消息的相关内容
_isOffline = false
_canIncludeExpansion = false
_hasChanged = false
_disableUpdateLastMessage = false
_conversationType = 1
_targetId = @"123"
_channelId = @""
_messageId = 17
_messageDirection = 2
_senderUserId = @"123"
_receivedStatusInfo RCReceivedStatusInfo * 0x3025eb5c0
_sentStatus = 30
_receivedTime = 1740566955000
_sentTime = 1740566955056
_objectName = @"app:red_packet"
_content CustomRedPacketMessage * 0x300691b80
_RCMessageContent RCMessageContent
_senderUserInfo
_mentionedInfo
_auditInfo
_destructDuration = 0
_extra
_rawJSONData
_contentBaseKeys
_content = @"红包"
_extra = @""
_messageUId = @"CL87-G08C-6L85-E222"
_readReceiptInfo
_groupReadReceiptInfoV2
_messageConfig RCMessageConfig * 0x30279cee0
_messagePushConfig RCMessagePushConfig * 0x300693110
_directedUserIds
_destructTime = 0
_expansionDicEx
typescript
// 设置消息监听
const Events = RongIMLib.Events
RongIMLib.addEventListener(Events.MESSAGES, (evt) => {
console.log(evt.messages)
})
// 注册自定义消息
const PersonMessage = RongIMLib.registerMessageType('app:red_packet', true, true, [], false)
// 发送自定义消息
// 构建要发送的自定义消息
const message = new PersonMessage({ name: 'someone', age: 18 })
// 接收该自定义消息示例
// 调用 addEventListener 设置消息接收监听器。所有接收到的消息都会 在此接口方法中回调。
// 返回 IAReceivedMessage 类型的消息数组,类型请参考:https://doc.rongcloud.cn/apidoc/im-web/latest/zh_CN/interfaces/IMessagesEvent.html
const Events = RongIMLib.Events
const listener = (evt) => {
console.log(evt.messages)
};
RongIMLib.addEventListener(Events.MESSAGES, listener)
// 返回的 `Message` 实体参考下面信息,可以使用 `messageType` 来区分消息类型:
{
// 可根据 messageType 筛选业务层要处理的礼物消息
"messageType": "app:red_packet",
"channelId": "",
"content": {
"content": "红包消息"
},
"senderUserId": "user01",
"targetId": "chart01",
"conversationType": 4,
"sentTime": 1743414376795,
"receivedTime": 0,
"messageUId": "消息唯一值",
"messageDirection": 1,
"isPersited": true,
"isCounted": true,
"isMentioned": false,
"disableNotification": false,
"isStatusMessage": false,
"canIncludeExpansion": false,
"expansion": null,
"receivedStatus": 0,
"receivedStatusInfo": {
"isRead": false,
"isListened": false,
"isDownload": false,
"isRetrieved": false
},
"messageId": 8488190336485840000,
"sentStatus": 30,
"isOffLineMessage": false
}
4. 扩展区域展示(发送红包入口)
4.1 设置红包扩展面板插件
如果您使用的是 IMLib SDK,您需要自行实现发送红包入口。 如果您使用的是 IMKit SDK,可以在 IMKit 的扩展面板中添加自定义插件。
Android 端实现流程
自定义插件需要实现 IPluginModule 接口类,可以参考 IMKit 源码中的 IPluginModule.java,以及具体的实现类。
此处以实现自定义插件 RedPacketPlugin 示例类为例。
iOS 端实现流程
在聊天页面的 viewDidLoad 方法中插入对应的红包扩展插件图标
Objective C
[self.chatSessionInputBarControl.pluginBoardView insertItem:[UIImage imageNamed:@"redPacket"] highlightedImage:[UIImage imageNamed:@"redPacket"] title:@"发红包" tag:20080];
Web IMKit 没有扩展面板概念
4.2 配置扩展面板插件
示例代码
- Android
- iOS
- Web
Java
// 1. 继承 `DefaultExtensionConfig`,创建自定义的扩展面板配置类 `MyExtensionConfig`,重写 `getPluginModules()` 方法。
public class MyExtensionConfig extends DefaultExtensionConfig {
@Override
public List<IPluginModule> getPluginModules(Conversation.ConversationType conversationType, String targetId) {
List<IPluginModule> pluginModules = super.getPluginModules(conversationType,targetId);
// 增加红包扩展项
pluginModules.add(new RedPacketPlugin());
return pluginModules;
}
}
// 2. SDK 初始化之后,调用 `setExtensionConfig` 方法设置自定义的输入配置,SDK 会根据此配置展示扩展面板。
RongExtensionManager.getInstance().setExtensionConfig(new MyExtensionConfig());
Objective C
// 在聊天页面重写插件的点击方法,实现红包发送相关业务逻辑:
// 处理扩展项点击事件
- (void)pluginBoardView:(RCPluginBoardView *)pluginBoardView clickedItemWithTag:(NSInteger)tag {
// 红包扩展插件的 tag
if (tag == 20080) {
// 业务层实现红包发送相关逻辑
}else {
[super pluginBoardView:pluginBoardView clickedItemWithTag:tag];
}
}
Objective C
// Web IMKit 不支持
5. 付款成功发送红包消息
在用户付款成功后,需要调用融云的发送消息方法,发送红包消息并设置消息可扩展。根据业务侧逻辑选择从哪个端发送此类消息。
- Android
- iOS
- Web
Java
// 构建红包消息
CustomRedPacketMessage redPacketMessage = CustomRedPacketMessage.obtain("0.01");
io.rong.imlib.model.Message message =
io.rong.imlib.model.Message.obtain(targetId, conversationType, redPacketMessage);
// 设置消息可扩展
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);
// 发送消息,如果您使用的 IMLib SDK,请使用 RongCoreClient 的 sendMessage 方法
IMCenter.getInstance().sendMessage(message, null, null, null);
Objective C
// 构建红包消息
CustomRedPacketMessage *message = [CustomRedPacketMessage messageWithContent:@"0,01"];
RCMessage *msg = [[RCMessage alloc] initWithType:self.conversationType targetId:self.targetId direction:MessageDirection_SEND content:message];
// 设置消息可扩展
msg.canIncludeExpansion = YES;
msg.expansionDic = @{@"open":@"false",@"count":@"1",@"amount":@"0.01"};
// 发送消息,如果您使用的 IMLib SDK,请使用 RCCoreClient 的 sendMessage 方法
[[RCIM sharedRCIM] sendMessage:msg pushContent:@"红包来了" pushData:nil successBlock:^(RCMessage *successMessage) {
} errorBlock:^(RCErrorCode nErrorCode, RCMessage *errorMessage) {
}];
javascript
// 构建要发送的自定义红包消息
const message = new PersonMessage({ key1: 'value1', key2: 'value2' })
// 发送消息
RongIMLib.sendMessage({
conversationType: RongIMLib.ConversationType.PRIVATE,
targetId: '<targetId>'
}, message).then(res => {
if (res.code === 0) {
console.log(res.code, res.data)
} else {
console.log(res.code)
}
})