引用回复
IMKit 支持引用回复功能,允许用户在聊天页面中回复彼此的消息。引用回复功能默认使用 ReferenceMessage(类型标识:RC:ReferenceMsg)发送回复内容。
从 5.38.0 开始,IMKit 升级了引用消息功能。SDK 不再将回复内容封装为 RC:ReferenceMsg,而是在文本、图片、GIF、小视频、普通语音、高清语音、文件、位置等实际回复消息结构上写入引用关系信息。该功能需要在 IMKit SDK 中开启后才能使用,默认仍使用原引用消息逻辑。
使用限制
旧版引用回复功能目前有以下限制:
- 仅支持文本消息、文件消息、图文消息、图片消息、引用消息的引用。
- 仅支持一层引用,即只能引用回复原始消息。多重引用时,只展示上一层被引用消息内容。
- 被引用消息撤回后,引用消息仍会展示被引用的消息内容。
引用消息功能升级后,目前有以下限制:
- 引用展示仅支持一层。如果被引用的消息本身携带引用关系,引用卡片只展示当前被引用消息对应的一层内容,不会递归展示更早的引用层级。
- IMKit 内置会话页面仅支持引用已发送成功且有消息 UId 的消息。用户发送回复时,默认支持文本、图片、GIF、小视频、普通语音、高清语音、文件、位置消息作为回复内容。您可以通过
quoteMessageTypeWhiteList调整允许发送的回复消息类型。 - 自定义消息如需在长按菜单中显示引用消息入口,需要通过
ReferenceMenuItemFilter放行该消息类型。 - 开启后,低版本 SDK 会按原消息类型展示回复消息,无法展示引用关系信息。
用法
IMKit 会话页面默认已启用引用回复功能。用户在会话页面长按消息,在弹窗中选择引用消息,即可引用该消息。在输入区添加消息内容后,SDK 默认会将输入内容与被引用消息组合为 ReferenceMessage,并发送到会话中。
引用消息功能升级
默认的引用回复会将输入内容与被引用消息组合为 ReferenceMessage 发送。开启引用消息功能升级后,SDK 会在实际发送的消息对象上写入引用关系信息 QuoteInfo,并通过 Message.quoteInfo 标识该消息回复的是哪一条原始消息。原 RC:ReferenceMsg 仍可正常使用。
引用消息功能升级默认关闭。开启后,用户引用一条消息后,可以继续发送文本、图片、GIF、小视频、普通语音、高清语音、文件、位置等多种类型的消息作为回复。
您 可以通过 IMKit 全局配置开启引用消息功能升级。
RongConfigCenter.featureConfig().enableReference(true);
RongConfigCenter.featureConfig().enableQuoteV2(true);
enableQuoteV2(true) 仅控制 IMKit 内置会话页面发送引用回复时是否使用升级后的 quoteInfo 方案,并且需要引用回复功能 enableReference(true) 保持开启。接收或历史消息中只要携带有效 Message.quoteInfo,IMKit 内置消息展示模板就会展示引用卡片,不依赖该发送侧开关。
发送前,请确认被引用消息已存在于本地消息库,且消息 UId 有效。SDK 发送时会根据 quoteInfo.messageUId 查询被引用消息。如果 messageUId 为空,发送会失败并返回 RC_INVALID_PARAMETER_MESSAGE_UID;如果未查到对应消息,发送会失败并返回 RC_DB_DATA_NOT_FOUND。
可发送的回复消息类型由 quoteMessageTypeWhiteList 控制。默认包含:
| 消息类型 | 类型标识 |
|---|---|
| 文本消息 | RC:TxtMsg |
| 图片消息 | RC:ImgMsg |
| GIF 消息 | RC:GIFMsg |
| 小视频消息 | RC:SightMsg |
| 普通语 音消息 | RC:VcMsg |
| 高清语音消息 | RC:HQVCMsg |
| 文件消息 | RC:FileMsg |
| 位置消息 | RC:LBSMsg |
如需限制引用后可发送的回复消息类型,可以重新设置白名单。该白名单不控制哪类消息可以被引用;自定义消息如需作为被引用消息进入引用流程,请按下文配置引用入口和自定义展示 Provider。
List<String> whiteList = new ArrayList<>();
whiteList.add("RC:TxtMsg");
whiteList.add("RC:ImgMsg");
whiteList.add("RC:FileMsg");
RongConfigCenter.featureConfig().setQuoteMessageTypeWhiteList(whiteList);
引用语音回复的转文字
开启引用消息功能升级后,如果回复消息是普通语音消息或高清语音消息,且应用已开通并启用 IMKit 语音转文字能力,IMKit 会按语音消息原有规则展示转文字结果。转换后的文字是否显示,由消息中 SpeechToTextInfo 的 isVisible 状态控制。
自定义
自定义引用消息的 UI
如需自定义旧版引用消息(RC:ReferenceMsg)展示样式,或自定义带引用关系信息消息的完整消息气泡,请按自定义消息展示模板方式处理。详见修改消息的展示样式。
如果只需要自定义被引用内容在引用卡片或输入框上方引用区域中的展示,请使用下文介绍的引用内容 Provider。
自定义引用卡片展示
如需展示被引用自定义消息的专属样式,需要为该消息开放引用消息入口,并注册消息列表内的引用卡片 Provider。
显示自定义消息的引用入口
自定义消息默认不显示引用消息入口。您可以通过 ReferenceMenuItemFilter 放行指定消息类型;如需保留 SDK 默认支持的消息类型,请委托默认实现。
以下示例将自定义名片消息 ContactCardMessage 加入可引用范围。
RongConfigCenter.conversationConfig()
.setReferenceMenuItemFilter(
uiMessage -> {
if (uiMessage != null
&& uiMessage.getContent() instanceof ContactCardMessage) {
return true;
}
return RongConfigCenter.conversationConfig()
.getDefaultReferenceMenuItemFilter()
.shouldShowReferenceMenuItem(uiMessage);
});
传入 null 可恢复 SDK 默认准入逻辑。
RongConfigCenter.conversationConfig().setReferenceMenuItemFilter(null);
注册自定义引用卡片 Provider
自定义引用卡片 Provider 需要继承 ReferenceContentMessageItemProvider。建议在打开会话页面前完成注册。
RongConfigCenter.conversationConfig()
.addReferenceContentMessageItemProvider(
"RC:CardMsg", new ContactCardReferenceMessageItemProvider());
Provider 查询时会优先按 objectName 精确匹配;如果注册时传入的 objectName 为空,该 Provider 仅参与消息内容类型兜底。精确匹配未命中时,SDK 会再调用已注册 Provider 的 isReferenceContentType 按消息内容类型兜底判断。
命中该 Provider 后,IMKit 会将 onCreateView 返回的 View 添加到引用卡片容器中,并调用 onBindView 绑定被引用消息。
public class ContactCardReferenceMessageItemProvider
extends ReferenceContentMessageItemProvider<ContactCardMessage> {
@Override
public View onCreateView(Context context, ViewGroup parent) {
return LayoutInflater.from(context)
.inflate(R.layout.item_reference_contact_card, parent, false);
}
@Override
public void onBindView(View view, Message quotedMessage, ContactCardMessage quotedContent) {
TextView nameView = view.findViewById(R.id.contact_name);
TextView idView = view.findViewById(R.id.contact_id);
nameView.setText(quotedContent.getName());
idView.setText(quotedContent.getId());
}
@Override
public boolean isReferenceContentType(MessageContent content) {
return content instanceof ContactCardMessage;
}
}