跳到主要内容

引用回复

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 全局配置开启引用消息功能升级。

Java
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。

Java
List<String> whiteList = new ArrayList<>();
whiteList.add("RC:TxtMsg");
whiteList.add("RC:ImgMsg");
whiteList.add("RC:FileMsg");
RongConfigCenter.featureConfig().setQuoteMessageTypeWhiteList(whiteList);

引用语音回复的转文字

开启引用消息功能升级后,如果回复消息是普通语音消息或高清语音消息,且应用已开通并启用 IMKit 语音转文字能力,IMKit 会按语音消息原有规则展示转文字结果。转换后的文字是否显示,由消息中 SpeechToTextInfoisVisible 状态控制。

自定义

自定义引用消息的 UI

如需自定义旧版引用消息(RC:ReferenceMsg)展示样式,或自定义带引用关系信息消息的完整消息气泡,请按自定义消息展示模板方式处理。详见修改消息的展示样式

如果只需要自定义被引用内容在引用卡片或输入框上方引用区域中的展示,请使用下文介绍的引用内容 Provider。

自定义引用卡片展示

如需展示被引用自定义消息的专属样式,需要为该消息开放引用消息入口,并注册消息列表内的引用卡片 Provider。

显示自定义消息的引用入口

自定义消息默认不显示引用消息入口。您可以通过 ReferenceMenuItemFilter 放行指定消息类型;如需保留 SDK 默认支持的消息类型,请委托默认实现。

以下示例将自定义名片消息 ContactCardMessage 加入可引用范围。

Java
RongConfigCenter.conversationConfig()
.setReferenceMenuItemFilter(
uiMessage -> {
if (uiMessage != null
&& uiMessage.getContent() instanceof ContactCardMessage) {
return true;
}
return RongConfigCenter.conversationConfig()
.getDefaultReferenceMenuItemFilter()
.shouldShowReferenceMenuItem(uiMessage);
});

传入 null 可恢复 SDK 默认准入逻辑。

Java
RongConfigCenter.conversationConfig().setReferenceMenuItemFilter(null);

注册自定义引用卡片 Provider

自定义引用卡片 Provider 需要继承 ReferenceContentMessageItemProvider。建议在打开会话页面前完成注册。

Java
RongConfigCenter.conversationConfig()
.addReferenceContentMessageItemProvider(
"RC:CardMsg", new ContactCardReferenceMessageItemProvider());

Provider 查询时会优先按 objectName 精确匹配;如果注册时传入的 objectName 为空,该 Provider 仅参与消息内容类型兜底。精确匹配未命中时,SDK 会再调用已注册 Provider 的 isReferenceContentType 按消息内容类型兜底判断。

命中该 Provider 后,IMKit 会将 onCreateView 返回的 View 添加到引用卡片容器中,并调用 onBindView 绑定被引用消息。

Java
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;
}
}

处理引用卡片内的自定义事件

消息列表引用卡片中不会注入 SDK 默认点击预览逻辑。如果自定义引用卡片 View 内部需要触发业务事件,例如跳转详情页、弹窗或埋点,请在 onCreateViewonBindView 中为自定义 View 设置对应事件处理。

提示
  • 未注册自定义引用卡片 Provider 时,IMKit 会继续使用默认引用摘要样式。
  • 该能力只处理消息列表中回复消息内的引用卡片展示,不控制输入框上方的引用区域。
  • 如果 onCreateView 返回 null,或 Provider 内部抛出异常,IMKit 会回退到默认引用摘要展示。
  • RecyclerView 复用时,SDK 会清理旧的自定义 View,避免展示上一条消息的引用内容。

自定义输入框上方引用区域

用户在会话页面选择引用消息后,IMKit 默认会在输入框上方展示引用区域。如果需要自定义该区域的展示,例如为自定义消息展示专属摘要、头像或操作按钮,可以注册输入框引用区域 Provider。

自定义输入框引用区域 Provider 需要继承 ReferenceContentInputBarProvider。建议在打开会话页面前完成注册。

Java
RongConfigCenter.conversationConfig()
.addReferenceContentInputBarProvider(
"RC:CardMsg", new ContactCardReferenceInputBarProvider());

输入框引用区域支持整块 View 自定义,包括高度、布局和取消按钮。SDK 会在 onCreateView 中传入 ReferenceInputBarAction,业务方可调用 cancelReference() 清除当前引用状态。onCreateView 返回 null 时,IMKit 会继续使用默认输入框引用区域。

Java
public class ContactCardReferenceInputBarProvider
extends ReferenceContentInputBarProvider<ContactCardMessage> {

@Override
public View onCreateView(
Context context, ViewGroup parent, ReferenceInputBarAction action) {
View view =
LayoutInflater.from(context)
.inflate(R.layout.input_reference_contact_card, parent, false);
view.findViewById(R.id.reference_cancel)
.setOnClickListener(v -> action.cancelReference());
return view;
}

@Override
public void onBindView(View view, Message quotedMessage, ContactCardMessage quotedContent) {
TextView nameView = view.findViewById(R.id.contact_name);
nameView.setText(quotedContent.getName());
}

@Override
public boolean isReferenceContentType(MessageContent content) {
return content instanceof ContactCardMessage;
}
}
提示
  • IMKit 会负责添加、绑定和移除自定义输入框引用区域 View。
  • 自定义 View 的宽度由 IMKit 在布局时统一设置;高度由自定义 View 自身布局决定。
  • 取消按钮、整块点击手势以及 View 内部交互需要由业务自行实现。需要取消当前引用时,可调用 ReferenceInputBarAction.cancelReference()
  • 未注册 Provider、onCreateView 返回 null、或 Provider 内部抛出异常时,IMKit 会继续使用默认输入框引用区域。

关闭引用回复功能

IMKit 5.X 版本不支持通过修改 XML 资源文件控制此功能。如需关闭引用回复功能,可以修改 IMKit 全局配置:

init 之后调用。

Java
RongConfigCenter.featureConfig().enableReference(false);