用途
本技能面向使用 CometChat React Native UI Kit v5(@cometchat/chat-uikit-react-native@5)的开发者,用于对聊天界面进行主题化、重新样式化以及扩展自定义消息类型。适用场景包括:更改聊天配色、品牌化聊天 UI、实现深色模式、重新设计消息气泡、添加自定义消息类型、渲染自定义气泡、在消息菜单中增加选项等。
使用前提:需要先掌握配套技能 cometchat-react-native-core(安装、Provider 链、init→login→render),本技能不再重复。主题化需要 CometChatThemeProvider 已在组件链中。
定制机制:三层,从成本最低开始
该 UI Kit 没有 CSS,没有样式表、className 或 --cometchat-* 变量。若手头是带 CSS 自定义属性的 React 片段,在此不适用。
第一层:主题模式 + 颜色令牌(全应用)
Provider 接收的 theme 属性形如 { mode, light, dark }。mode 可取 "light"、"dark"、"auto",其中 "auto" 使套件跟随设备(操作系统)的明暗设置(读取 useColorScheme()),Provider 默认即为 "auto"。
固定深色示例:
<CometChatThemeProvider theme={{ mode: "dark" }}>{/* … */}</CometChatThemeProvider>
跟随系统并在两种模式下品牌化:
<CometChatThemeProvider
theme={{
mode: "auto",
light: { color: { primary: "#F76808" } },
dark: { color: { primary: "#F8935B" } },
}}
>
{/* … */}
</CometChatThemeProvider>
primary 驱动按钮、发出消息气泡和激活状态,通常品牌变更只需这一个令牌。其他常见令牌:textPrimary、background1、neutral50、extendedPrimary500。完整列表应从 /ui-kit/react-native/colors.md 获取,不要猜测令牌名。
要跟随系统,使用 mode: "auto" 并同时设置 light 和 dark。若不使用 Provider,系统主题变化完全不会反映。
第二层:逐组件样式对象
每个组件接收 style 属性,其中包含具名子样式对象——是普通 RN 样式对象,不是 CSS:
<CometChatConversations style={{ containerStyle: { backgroundColor: "#F7F7F7" } }} />
同样的样式键也可通过主题全局设置,当变更应处处生效时更可取:
<CometChatThemeProvider theme={{ light: { conversationStyles: { /* … */ } } }}>
样式键名因组件而异。应从该组件页面(/ui-kit/react-native/component-styling.md 及组件自身页面)获取,不要从其他组件套用。
第三层:在自定义视图中读取当前主题
useTheme() 返回已解析的主题(已按 mode 解析为 light 或 dark),使自定义视图无需重新推导调色板即可与套件匹配:
import { useTheme } from "@cometchat/chat-uikit-react-native";
import { Text } from "react-native";
const Label = () => {
const theme = useTheme();
return <Text style={{ color: theme.color.textPrimary }}>Chats</Text>;
};
自定义消息类型:DataSource 装饰器链
注意:RN 没有 React 插件 API。CometChatMessagePlugin 和 CometChatPluginRegistry 在此套件中不存在,写出它们无法编译。RN 使用装饰器链。
扩展 DataSourceDecorator,覆盖所需方法,并用 ChatConfigurator.enable 注册:
import {
ChatConfigurator, DataSourceDecorator, CometChatMessageTemplate,
} from "@cometchat/chat-uikit-react-native";
const ORDER_TYPE = "order";
class OrderDataSource extends DataSourceDecorator {
// 0. 身份标识——必需。基类 DataSourceDecorator.getId() 会抛出
// ("Method not implemented."),而 ChatConfigurator.enable() 调用 getId() 去重
// 注册表——因此缺少此覆盖的子类会在 ChatConfigurator.enable(...) 处崩溃,
// 而不是在渲染时。返回稳定、唯一的 id。
getId(): string {
return "order_message_datasource";
}
// 1. 渲染——气泡如何绘制。
getAllMessageTemplates(theme?: any, params?: any): CometChatMessageTemplate[] {
const templates = super.getAllMessageTemplates(theme, params);
// 在此追加或替换模板
return templates;
}
// 2. 拉取——没有这两个方法消息永远不会被检索到。
// CometChatMessageList 由此构建请求:
// requestBuilder.setTypes(ChatConfigurator.dataSource.getAllMessageTypes())
// requestBuilder.setCategories(ChatConfigurator.dataSource.getAllMessageCategories())
// 未出现在这些过滤器中的类型会被服务端排除。发送时气泡乐观出现,
// 重新加载后消失——且任何地方都没有错误。
getAllMessageTypes(): string[] {
return [...super.getAllMessageTypes(), ORDER_TYPE];
}
getAllMessageCategories(): string[] {
const categories = super.getAllMessageCategories();
return categories.includes(CometChat.CATEGORY_CUSTOM)
? categories
: [...categories, CometChat.CATEGORY_CUSTOM];
}
}
// 在 login() 之后,而非仅在 init() 之后。CometChatUIKit.login() 调用 enableExtensions(),
// 其第一条语句是 ChatConfigurator.init()——“重新初始化数据源”。更早注册的任何内容
// 都会被丢弃,因此在模块作用域或紧接 init() 之后注册的装饰器会静默消失。
await CometChatUIKit.login({ uid: UID });
ChatConfigurator.enable((source) => new OrderDataSource(source));
getId() 对每个 DataSourceDecorator 子类都是必需的。它是唯一不委托给被包装源的基类方法——基类抛出 Error("Method not implemented."),而 ChatConfigurator.enable() 调用 getId() 去重注册表。省略它,注册会在 ChatConfigurator.enable(...) 处崩溃并报 Method not implemented——而不是在渲染时,因此看起来不相关。每个内置装饰器(Polls、Stickers、Translation、LinkPreview、Collaborative*)都覆盖了它;你的也必须覆盖,返回稳定唯一的字符串。
自定义消息类型有两半,只有一半是显而易见的。渲染是 getAllMessageTemplates / getMessageTemplate。拉取是 getAllMessageTypes / getAllMessageCategories。只交付渲染那一半,一切看起来正常,直到第一次重新加载,该类型的所有消息都消失了——没有错误,没有警告。
DataSourceDecorator 暴露约 50 个可覆盖方法;通常需要的是 getId(必需——见上)、getAllMessageTemplates、getMessageTemplate、getAllMessageTypes、getAllMessageCategories、getMessageOptions(长按菜单)和 getAuxiliaryOptions(输入框操作)。始终调用 super.<method>(...) 并修改结果——整体替换会丢弃所有内置消息类型。
文档缺口(RN-G10):DataSourceDecorator / MessageDataSource / ExtensionsDataSource 和 ChatConfigurator.enable 未在任何 RN 页面记录——文档仅展示通过 getAllMessageTemplates() 修改现有模板。此内容基于套件源码构建;应向开发者说明,而非当作已记录内容呈现。
部分关闭(2026-08-20)。ui-kit/react-native/message-list 现已记录真正破坏构建的那一半:自定义类型必须为拉取注册(getAllMessageTypes / getAllMessageCategories),而不仅为渲染,且装饰器必须在 login() 之后注册,因为 enableExtensions() 会重新运行 ChatConfigurator.init()。仍缺失:一个专门的 RN 自定义消息类型页面,端到端覆盖 DataSourceDecorator / MessageDataSource / ExtensionsDataSource。负责人:docs。
不使用装饰器定制现有气泡
若要重新样式化而非替换,优先使用主题的气泡样式键——textBubbleStyles、imageBubbleStyles、fileBubbleStyles、pollBubbleStyles 及同类。确切键名从 /ui-kit/react-native/message-bubble-styling.md 获取。
常见陷阱
- 试图使用 CSS——没有样式表、className、--cometchat-*。使用主题对象 + RN 样式。
- 写出 React 插件 API——不存在;使用 ChatConfigurator + DataSourceDecorator。
- 装饰器省略 getId()——基类抛出;ChatConfigurator.enable() 调用它 → 注册时崩溃并报 Method not implemented。
- 装饰器覆盖中不调用 super——静默丢弃所有内置模板。
- 应用跟随系统时只设置 light——深色模式回退到默认值。
- 猜测令牌或样式键名——应获取;错误的键会静默失败而非报错。
验证是否生效
- 每个符号都出现在 catalogs/rn-v5.json 中。
- npm run verify:fences:rn-v5 针对固定版本的套件编译示例。
- 在设备上:切换操作系统深色模式并确认界面跟随;确认自定义模板渲染且内置类型仍一并渲染。