Skip to content
能力中心
产品中心
应用市场
WebOffice
开发者后台

自定义消息

协作中台 SDK 在提供基础 消息类型 的同时,还支持用户注册自定义类型的消息,消息传递的内容完全由用户自己来定义,例如下图的天气消息。

快速上手

步骤1:发送自定义消息

  1. 在键盘上扩展消息发送入口,需要继承 KIMExpInputPanelExtension 类实现 imagetitleonClicked 等方法来自定义图标,文本及点击事件。

  2. 继承 KIMExpInputFactory 类实现 newExtensions 方法来返回上一步的实现类对象,支持同时扩展多个键盘入口按钮。

  3. 使用 KIMCoreAppCustomizeMessage.create 方法来创建一条自定义消息的内容部分,参数 content 为自定义消息内容的Json字符串,type 为自定义消息类型,msgDesc 为消息描述可用于摘要显示及消息搜索关键字。

  4. 使用 KIMCoreMessageFactory.createAppCustomize 方法来构建一条 KIMCoreMessage 消息,然后调用 KIMCore.instance().sendMessage 方法来发送消息。

以Demo中的天气消息为例, 示例代码如下:

Kotlin
class WeatherInputPanelExt : KIMExpInputPanelExtension() {
  
  override fun image(): Int {
    // 图标
    return R.drawable.ic_xxx
  }

  override fun title(): String {
    // 标题文本
    return "xxx"
  }

  override fun isSupported(chatType: Int, chatId: String): Boolean {
    return true
  }

  override fun onClicked(hostFragment: Fragment) {
    // 发送自定义消息
    val customizeMessage = KIMCoreAppCustomizeMessage.create(contentJson, customizeType, msgDesc)
    val message = KIMCoreMessageFactory.createAppCustomize(customizeMessage, KIMCoreMessageFactory.MessageParamBuilder(chatId))
    KIMCore.instance().sendMessage(message, null)
  }
  
  override fun priority(): Int {
    return 1000
  }
}

class WeatherInputFactoryImpl : KIMExpInputFactory() {

  override fun newExtensions(): List<KIMExpInputPanelExtension> {
    // 列表可返回多个自定义的键盘入口
    return listOf(WeatherInputPanelExt())
  }
}

步骤2:自定义消息Cell

  1. 在消息列表展示自定义的消息,需要继承 KIMExpMessageBaseCell<IV, D> 类实现 onCreateView 方法返回自定义的消息气泡视图。

  2. 泛型 IV 需继承 KIMExpMessageDefaultItemView<C, D> 类实现 bindContentDataonMessageContentClick 等方法自定义数据绑定及消息点击事件。

  3. 泛型 C 需继承 KIMCoreAppCustomizeMessage 类来自定义消息数据类,可扩展自定义的数据字段,消息解析时协作中台SDK会自动把消息转换为该类型的对象。

  4. 泛型 D 需继承 KIMExpAppCustomMessageItem<T> 类传入自定义消息的类型及消息模型(泛型 T 即为上一步的自定义消息数据类)。

以Demo中的自定义天气消息为例,示例代码如下:

Kotlin
const val WEATHER_MSG_TYPE = "weather_2"

class WeatherMessageCell : KIMExpMessageBaseCell<WeatherMessageItemView, WeatherListItem>() {

    override fun onCreateView(parent: ViewGroup): WeatherMessageItemView {
        // 返回自定义气泡视图
        val binding = ItemCustomizeWeatherMessageBinding.inflate(parent.inflater, parent, false)
        return WeatherMessageItemView(binding)
    }
}

class WeatherListItem : KIMExpAppCustomMessageItem<WeatherCustomMessage>(WEATHER_MSG_TYPE, WeatherCustomMessage::class.java)

class WeatherCustomMessage(
    @SerializedName("city") val city: String,
    @SerializedName("longitude") val longitude: String,
    @SerializedName("latitude") val latitude: String,
) : KIMCoreAppCustomizeMessage() {
    constructor() : this("未知", "0.0", "0.0")
}

气泡数据绑定:

  • 为了更简单的在消息气泡视图绑定用户数据进行渲染显示,我们提供了KIMCellModel<DataType> 类来帮助用户快速实现异步任务(如:网络请求)及数据缓存管理。

  • 缓存支持二级缓存(内存/磁盘),目前数据存储是非加密的。

  • 内存缓存支持任意类型,磁盘缓存的必要条件是数据类必须是基本数据类型(如: Int、String等)及实现了Serializable的类对象,否则磁盘缓存不生效。

  • 异步任务关联Cell的生命周期,页面关闭会自动取消任务,避免内存泄漏风险。

  • 支持异步任务超时自动取消,避免大量的耗时请求一直阻塞线程无法释放,导致新任务无法执行。

方法名使用说明
KIMCellModel(private val lifecycleOwner: LifecycleOwner)构造器
参数:lifecycleOwner生命周期宿主对象,如: Activity, Fragment,或者气泡Cell
用于异步任务跟生命周期绑定,自动取消异步任务操作
fromCache(cacheKey: String, onlyUseMemoryCache: Boolean = false)支持从缓存获取数据
参数:
cacheKey: 缓存数据使用的key
onlyUseMemoryCache: 是否只从内存获取数据,不使用磁盘缓存,默认值: false,即同时使用内存及磁盘缓存
fromSyncOperation(runAlways: Boolean = false, customOperation: () -> DataType)支持用户同步返回数据操作
参数:
runAlways: false: 如果缓存有数据会直接返回,异步任务不会执行, true: 用于用户同时需要使用缓存和异步任务数据的情况, 默认值为false
customOperation:同步操作的block方法,函数返回值为具体的数据对象
注:用户为同步操作,实际框架内部会在线程中执行,异步回调数据, 同时会自动把数据存储到缓存中
bindData(observer: KIMCellObserver)开启数据绑定
参数:
observer:数据回调监听器
用户可在回调中做更新消息气泡视图操作

示例代码:

Kotlin
class WeatherMessageItemView(val binding: ItemCustomizeWeatherMessageBinding) :KIMExpMessageDefaultItemView<WeatherCustomMessage, WeatherListItem>(binding.root) {

  override fun bindContentData(data: WeatherListItem, diff: KMessageListItemPayloadDiff?) {
    val content = data.item.message.content.safeCast<WeatherCustomMessage>() ?: return
    binding.tvWeatherCity.text = content.city
    content.city?.let {
      KIMCellModel<String>(this)
      .fromCache(content.city)
      .fromSyncOperation(runAlways = false) {
         // 耗时任务,同步返回数据
       }
       .bindData { result ->
           binding.tvWeatherInfo.text = if (result.isSuccess()) result.data.toString() else "查询中..."
       }
    }
  }
}

步骤3:自定义消息摘要

  1. 消息摘要用于在会话列表展示消息内容的概要,要继承 KIMChatSummaryFormatter 类实现 blockingGetFormattedChatSummary 方法返回要显示的摘要文本。

  2. 协作中台SDK的消息摘要为链式调用模式, 需要用户判断是否为自定义消息类型并返回自定义的摘要文本,否则要调super方法返回。

以Demo中的自定义天气消息为例,示例代码如下:

Kotlin
class WeatherSummaryFormatter : KIMChatSummaryFormatter() {

    override fun blockingGetFormattedChatSummary(message: KIMCoreMessage?): String {
        // 自定义消息的摘要
        message?.let {
            if (!message.isRecall && message.isAppCustomMessage()) {
                val appCustomizeMessage = message.content as KIMCoreAppCustomizeMessage
                if (WEATHER_MSG_TYPE == appCustomizeMessage.customizeType) {
                    return if (appCustomizeMessage.msgDesc.isNullOrEmpty()) "[查询天气]" else appCustomizeMessage.msgDesc
                }
            }
        }
        // 非自定义消息类型,要调用super方法返回
        return super.blockingGetFormattedChatSummary(message)
    }
}

步骤4:注册自定义消息

上述步骤只是实现自定义消息的发送入口和气泡视图等,关键的一步需要把相关实现类注册到协作中台SDK才能正常显示出消息。

  1. 自定义消息入口类需继承 KIMSdkApplication 类实现 init, confMeatsOnBone 方法注册上述相关的实现类。

  2. 在应用配置文件 AndroidManifest.xml 中配置自定义消息的入口类, 协作中台SDK会识别入口类并在初始化时自动注册。

以Demo中的自定义天气消息为例, 示例代码如下:

Kotlin
class WeatherExtApplication : KIMSdkApplication() {

    override fun init(application: Application) {
        with(KIM.getControl()) {
            // 自定义消息摘要
            addCustomChatSummaryFormatter(WeatherSummaryFormatter())
        }
    }

    override fun confMeatsOnBone(): KConf<Meat> {
        return kConfOf(
          KIMExpInputFactory::class.java confTo WeatherInputFactoryImpl::class.java, // 自定义的键盘入口
          KIMExpMessageBaseCell::class.java confTo WeatherMessageCell::class.java, // 自定义消息气泡
          KIMExpMessageMenuFactory::class.java confTo WeatherMessageMenuFactory::class.java // 自定义消息长按菜单
        )
    }
}
Xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="xxx">
    <application>
      
        <!-- 自定义天气消息入口类 -->
        <meta-data
          android:name="xxx.WeatherExtApplication"
          android:value="@string/kim_sdk_application" />
      
    </application>
</manifest>

API 说明

自定义消息扩展类

类名用途使用说明
KIMSdkApplication自定义消息气泡的注册1. 用户继承此类,覆写 initconfMeatsOnBone 方法实现插件的初始化注入
2. 在插件工程的AndroidManifest.xml中注册插件,如下:
<meta-data android:name=".XXXSdkApplication"
android:value="@string/kim_sdk_application" />
以便协作中台SDK能够识别插件并进行自动初始化
KIMExpInputPanelExtension
KIMExpInputFactory
扩展键盘上的按钮功能,主要用于触发发送自定义消息1. 继承 KIMExpInputPanelExtension 覆写 titleimageonClick 等方法实现自定义的标题及图标以及实现点击事件来发送自定义消息
2. 继承 KIMExpInputFactory 覆写 newExtensions 方法返回功能按钮的实现
3. 在自定义的 KIMSdkApplication 实现类中注册该类
KIMChatSummaryFormatter自定义会话列表要显示的消息概要内容1. 继承覆写 blockingGetFormattedChatSummary 方法返回自定义消息要显示的概要内容
2. 在自定义的KIMSdkApplication 实现类中注册该类
KIMExpMessageBaseCell<IV, D>自定义消息Cell视图1. 继承 KIMExpMessageBaseCell 实现 onCreateViewonBindData 方法,注意该类有两个泛型,IV为cell视图的封装类用于绑定数据做渲染,D为列表数据model的封装用于存储消息内容
2. IV需继承 KIMExpMessageDefaultItemView 实现 bindContentDataonMessageContentClick 自定义数据绑定逻辑及消息点击事件
3. D需继承KIMExpAppCustomMessageItem,自定义消息类型及自定义的数据模型类
KIMCoreAppCustomizeMessage自定义消息模型基类继承该类并定义自己消息需要的成员字段
参数:
content为自定义消息内容的Json字符串
type为自定义消息类型
msgDesc为消息描述可用于摘要显示及消息搜索关键字

发送自定义消息

以自定义天气消息为例,示例代码如下:

Kotlin
// 自定义消息的数据类
class WeatherSendMessageContent(
  @SerializedName("city") val city: String,
  @SerializedName("longitude") val longitude: String,
  @SerializedName("latitude") val latitude: String,
)

val messageContent = WeatherSendMessageContent("珠海", "113.5527", "22.2558")
// 创建自定义消息内容
val weatherMessage = KIMCoreAppCustomizeMessage.create(
                        content = WJsonUtil.toJson(messageContent), //自定义消息内容,可使用Json字符串
                        type = "weather_2", //自定义消息类型
                        msgDesc = "一条自定义消息" //自定义消息描述,可用于摘要显示和消息搜索的关键词
                    )
// 创建 KIMCoreMessage 消息对象,用于发送
val message = KIMCoreMessageFactory.createAppCustomize(
                    weatherMessage,
                    KIMCoreMessageFactory.MessageParamBuilder(chatId)
                      .setMessageConfig( //消息统计设置,可选
                            KIMCoreMessage.KIMCoreMessageConfig(
                                markUnread = true, //是否统计未读数,默认统计
                                true
                            )
                        )
                      .setPushConfig( //离线推送设置,可选项
                            KIMCoreMessage.KIMCorePushConfig(
                                pushTitle = "", //离线推送标题,可选
                                pushContent = "" //离线推送内容,可选
                            ).apply {
                                userPushType = UserPushType.NOT_PUSH //是否推送所有人
                                userPushLevel = PushLevelType.UNSPECIFIED //会话免打扰,默认无级别
                            })
                      .setMsgNotices(msgNotice = arrayListOf<KIMCoreMsgNotice>()) //会话强提醒设置, 可选
                )
// 调用发送消息接口
KIMCore.instance().sendMessage(message, null)

自定义消息长按菜单

  • 长按菜单默认支持的类型有:

    • KIMCopyMenuItem - 复制

    • KIMDeleteMenuItem - 删除

    • KIMReplyMenuItem - 回复

    • KIMForwardMenuItem - 转发

    • KIMMultiSelectMenuItem - 多选

    • KIMRecallMenuItem - 撤回

  • 自定义消息默认支持 回复转发多选收藏撤回 5个菜单项

如果用户需要增加自定义的菜单项,可继承KIMMessageMenuItem定制的自己的菜单项

类名用途使用说明
KIMExpMessageMenuFactory长按菜单扩展工厂类用于实例化长按菜单项的自定义实现类对象
方法:
pressType:定义自定义消息长按的类型,主要用于跟消息气泡视图关联,KIMExpMessageDefaultItemView 的实现类中也需要覆写 pressType 方法指定同一个字符串类型
newProcessor:返回长按菜单自定义实现类的对象, 即KIMMessageMenuProcessor的实现类
KIMMessageMenuProcessor长按菜单项自定义实现处理类用于返回自定义的长按菜单项及处理菜单的点击事件
方法:
getSupportMenuItem: 返回自定义菜单项列表,可添加自定义的菜单项,支持添加多个
onMenuItemClick: 覆写该方法处理菜单项的点击跳转逻辑
KIMMessageMenuItem长按菜单项基类继承该类定制菜单项的图标,文本及排序
方法:
iconResId: 菜单图标
label: 菜单文本
priority: 菜单优先级排序

以自定义天气消息为例, 示例代码如下:

Kotlin
class WeatherMessageMenuFactory: KIMExpMessageMenuFactory() {

    override fun newProcessor(): KIMMessageMenuProcessor {
        return WeatherMessagePressProcessor()
    }

    override fun pressType(): String {
        return "weather_dynamic"
    }
}

class WeatherMessagePressProcessor: KIMMessageMenuProcessor() {

    override fun getSupportMenuItem(): MutableList<KIMMessageMenuItem> {
        return super.getSupportMenuItem().apply {
            add(WeatherDynamicItem())
        }
    }

    override fun onMenuItemClick(
        menuItem: KIMMessageMenuItem,
        message: KIMCoreMessage,
        view: View,
        extData: Any?
    ): Boolean {
        if (menuItem is WeatherDynamicItem) {
            WToastUtil.show("打开城市天气动图")
            return true
        }
        return super.onMenuItemClick(menuItem, message, view, extData)
    }
}

class WeatherDynamicItem : KIMMessageMenuItem() {
    override fun iconResId(): Int {
        return R.drawable.ic_input_panel_weather
    }

    override fun label(): String {
        return "天气动图"
    }

    override fun priority(): Int {
        return 100
    }
}

// 气泡视图关联pressType, 只有该类型消息才会使用上面自定义菜单项的扩展实现
class WeatherMessageItemView(val binding: ItemCustomizeWeatherMessageBinding) :
  KIMExpMessageDefaultItemView<WeatherCustomMessage, WeatherListItem>(binding.root) {

  override fun bindContentData(data: WeatherListItem, diff: KMessageListItemPayloadDiff?) {
  }

  override fun pressType(): String {
    return "weather_dynamic"
  }
}

自定义收藏页菜单

收藏消息列表,长按自定义消息,弹出的操作菜单如下图:

收藏消息详情页,点击右上角 ... 按钮,也会弹出操作菜单,弹出的操作菜单如下图:

上述页面中的 天气动图 即为自定义的操作菜单项,自定义步骤如下:

  • 自定义操作菜单, 继承 KIMCollectMessageMenuItem 覆写 title, onClick 方法实现菜单显示的文本及点击事件。

  • 自定义操作菜单创建的工厂类,继承 KIMCollectMessageMenuFactory 覆写 msgType, addMenuItems 方法关联对应的自定义消息类型及返回自定义的菜单列表项。

  • 在自定义消息入口类中注册 KIMCollectMessageMenuFactory 的实现类。

以自定义天气消息为例,示例代码如下:

Kotlin
class WeatherCollectMessageMenuFactory : KIMCollectMessageMenuFactory() {

    override fun msgType(): String {
        // 自定义消息的类型
        return WEATHER_MSG_TYPE
    }

    override fun addMenuItems(): MutableList<KIMCollectMessageMenuItem> {
        // 自定义的操作菜单项,支持多个返回列表
        return arrayListOf(WeatherCollectExtMenuItem())
    }
}

class WeatherCollectExtMenuItem : KIMCollectMessageMenuItem {

    override fun title(): Int {
        // 自定义菜单显示的文本resourceId
        return R.string.app_customize_message_dynamic_weather
    }

    override fun onClick(view: View, data: KIMCoreMessage) {
        // 自定义跳转逻辑
        WToastUtil.show("打开城市天气动图")
    }
}

class WeatherExtApplication : KIMSdkApplication() {

  override fun init(application: Application) {
      // ...
  }

  override fun confMeatsOnBone(): KConf<Meat> {
    return kConfOf(
        // 注册自定义菜单创建的工厂类
        KIMCollectMessageMenuFactory::class.java confTo WeatherCollectMessageMenuFactory::class.java,
      )
  }
}

消息快捷回复菜单

  • 自定义消息默认不显示快捷回复菜单项,用户要开启此功能需继承 KIMExpMessageList 类覆写 supportQuickReply 方法返回true。

  • KIMSdkApplication 的实现类中注册上述实现。

示例代码:

Kotlin
class WeatherMessageListConfig : KIMExpMessageList() {

    override fun supportQuickReply(message: KIMCoreMessage): Boolean {
        if(message.isAppCustomMessage()) {
            return true
        }
        return super.supportQuickReply(message)
    }
}

class WeatherExtApplication : KIMSdkApplication() {

  override fun init(application: Application) {
  }

  override fun confMeatsOnBone(): KConf<Meat> {
    // 注册消息列表自定义配置实现类
    return kConfOf(KIMExpMessageList::class.java confTo WeatherMessageListConfig::class.java)
  }
}

消息气泡生命周期

生命周期含义使用说明
onCreateView(parent: ViewGroup):IV气泡视图创建时被调用该方法被回调时,用户创建自定义视图View返回
参数:
parent:用于获取LayoutInflater来解析自定义布局使用
返回值:
IV:泛型,继承父类KIMExpMessageDefaultItemView,用户自定义的气泡视图
onBindData(view: IV, data: D, payloads: MutableList)气泡将要显示前做数据绑定该方法在气泡视图将被渲染显示前回调,用户给气泡视图设置自定义数据用于显示
参数:
IV:泛型,继承父类KIMExpMessageDefaultItemView,用户自定义的气泡视图
data: 用户自定义的消息数据类对象,用户获取该字段的数据用来设置视图
payloads: 用户携带的自定义数据
onAppear(view: IV)气泡进入屏幕可视区域显示该方法在气泡显示在屏幕可视区域时被回调,用户可以做一些自定义的业务逻辑
参数:
IV:泛型,继承父类KIMExpMessageDefaultItemView,用户自定义的气泡视图
使用示例:
如消息气泡上显示的是一个视频,进入屏幕时需要自动开始播放
onDisappear(view: IV)气泡离开屏幕可视区域不显示该方法在气泡上下滑动离开屏幕可视区域不显示时被回调,用户可以做一些自定义的业务逻辑
参数:
IV:泛型,继承父类KIMExpMessageDefaultItemView,用户自定义的气泡视图
使用示例:
如消息气泡上显示的是一个视频,离开屏幕可视范围后需要停止播放
onRecycled(view: IV)气泡被回收复用该方法在气泡被回收时回调
参数:
IV:泛型,继承父类KIMExpMessageDefaultItemView,用户自定义的气泡视图
用于气泡回收时,用户要清理一些缓存数据或者手动取消网络请求等场景