更新记录
1.0.0(2026-11-11)
首个正式版本。
新增
基础能力
kefuInit:初始化客服 SDK(AppKey / TenantId / ConfigId),开启已读回执kefuRegister:注册访客账号kefuLogin:支持密码登录与 Token 登录kefuLogout:退出登录,可选解绑推送 TokenkefuIsLoggedIn:查询登录状态kefuOpenChat:Android 打开 EaseUI 原生会话页;iOS 为 stub(请自建页)
自建会话
kefuBindChat/kefuUnbindChat:绑定、解绑 IM 服务号会话kefuSendText:发送文本(可附带访客信息)kefuSendImage:发送图片(支持原图选项)kefuSendEmoji:发送大表情 / 自定义表情(远程 URL)kefuSendVoice:发送语音kefuSendVideo:发送视频(可选封面、时长)kefuSendFile:发送文件kefuSendOrderCard:发送订单卡片(OrderInfo)kefuSendProductCard:发送商品轨迹卡片(VisitorTrack)kefuLoadHistory:加载本地历史消息(JSON,支持分页startMsgId)kefuOnMessages:实时消息监听(keepAlive,传null取消)kefuOnMessageStatus:消息状态 / 已读回执变化回调
未读 / 已读 / 工具
kefuGetUnreadCount:单会话或全部未读数kefuMarkAllAsRead:会话标已读并发送已读回执kefuClearUnread:未读清零(可清全部)kefuGetMsgCount:会话消息条数kefuDetectMsgType:按消息 ID 检测类型kefuProbeReadStates:批量探测消息已读状态kefuResolveVideoUrl:解析历史视频可播放地址
满意度评价
kefuInviteEvaluation:主动发起评价邀请kefuSubmitEvaluation:提交评价(1~5 分)
推送
kefuBindPushToken:绑定推送 Token(Android:hms/fcm;iOS:APNs hex)kefuSetPushNickname:设置推送显示昵称
SDK 集成
- Android:
kefu-android-sdk-v1.3.3.9(EaseUI aar + player aar) - iOS:
kefu-iossdk-v1.5.4(HelpDesk + HyphenateChat xcframework,真机 arm64)
文档
- 新增详细
readme.md(API 参数、用法、消息结构、打包与 FAQ) - 新增本
changelog.md
说明
- 仅支持 App 端;需自定义调试基座或云打包
- wgt 热更新无法更新原生 SDK / UTS 代码
serviceIMNumber(IM 服务号)请使用小写
平台兼容性
uni-app(5.26)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | √ | - | √ | √ | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(5.26)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | √ | √ | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | × | √ |
huanxin-kefu(环信客服访客端)
环信客服云访客端 UTS 原生插件,适用于 uni-app / uni-app x(Vue2 / Vue3)。
Android / iOS 均为 无 UI 封装:插件只提供 SDK 能力,聊天界面需业务侧自建。
| 项 | 说明 |
|---|---|
| 插件 ID | huanxin-kefu |
| 版本 | 1.0.0 |
| 类型 | UTS 原生插件(仅 App) |
| 引擎要求 | HBuilderX ^3.96.0,uni-app / uni-app-x ^3.1.0 |
| 平台 | Android、iOS(不支持小程序 / H5 / Harmony) |
目录
1. SDK 来源与目录
| 平台 | 官方包 | 本插件已集成 |
|---|---|---|
| Android | kefu-android-sdk-v1.3.3.9 |
kefu-easeui-release.aar(内含 SDK jar + jni so)+ player-release.aar |
| iOS | kefu-iossdk-v1.5.4 |
HelpDesk.xcframework + HyphenateChat.xcframework(仅 ios-arm64 真机) |
uni_modules/huanxin-kefu/
├── package.json
├── readme.md
└── utssdk/
├── interface.uts # 类型声明(只写 type)
├── app-android/
│ ├── index.uts # Android 实现
│ ├── config.json
│ └── libs/ # aar
└── app-ios/
├── index.uts # iOS 实现
├── HxMsgCodec.swift
├── Info.plist
├── config.json
└── Frameworks/ # xcframework
说明
- Android 自带 EaseUI,可用
kefuOpenChat打开原生会话页;推荐仍用自建页。- iOS 官方访客包 不含 HelpDeskUI,
kefuOpenChat为 stub,请用自建聊天页。
2. 接入前准备
- 在环信客服云创建应用,拿到:
appKeytenantId(租户 ID)configId(可选,渠道配置 ID)serviceIMNumber(IM 服务号,必须小写,如kefuchannelimid_xxxx)
- 准备访客账号:建议服务端注册 + Token 登录;也可客户端
kefuRegister+ 密码登录。 - 制作 自定义调试基座(勾选本插件),再用自定义基座运行;正式发版走云打包。
文档参考:创建 APP 关联
3. 推荐接入流程
在客服页内初始化(不要写在 App.vue),顺序建议:
kefuInit → kefuLogin → kefuBindChat → kefuOnMessages / kefuOnMessageStatus → kefuLoadHistory
→ 收发消息 / 未读 / 评价 / 推送
离开页面 → kefuOnMessages(null) → kefuUnbindChat →(可选)kefuLogout
// #ifdef APP-PLUS
import {
kefuInit, kefuLogin, kefuBindChat, kefuUnbindChat,
kefuSendText, kefuLoadHistory, kefuOnMessages, kefuOnMessageStatus
} from '@/uni_modules/huanxin-kefu'
const appKey = '你的AppKey'
const tenantId = '你的租户ID'
const serviceIMNumber = 'kefuchannelimid_xxxx' // 必须小写
export default {
onLoad() {
const initRes = kefuInit({ appKey, tenantId, consoleLog: true })
if (initRes.code !== 0) return
kefuLogin({
username: 'visitor_001',
password: '123456', // 或 token: 'xxx'
complete: (res) => {
if (res.code !== 0) return
kefuBindChat(serviceIMNumber)
kefuOnMessages((raw) => {
const list = typeof raw === 'string' ? JSON.parse(raw) : raw
// 刷新消息列表
})
kefuOnMessageStatus(() => {
// 已读状态变化,可配合 kefuProbeReadStates 刷新
})
const hist = kefuLoadHistory({ serviceIMNumber, pageSize: 30 })
const messages = typeof hist === 'string' ? JSON.parse(hist) : hist
}
})
},
onUnload() {
kefuOnMessages(null)
kefuOnMessageStatus(null)
kefuUnbindChat()
}
}
// #endif
4. 通用约定
4.1 导入
import {
kefuInit, kefuRegister, kefuLogin, kefuLogout, kefuIsLoggedIn,
kefuOpenChat, kefuBindChat, kefuUnbindChat,
kefuSendText, kefuSendImage, kefuSendEmoji, kefuSendVoice,
kefuSendVideo, kefuSendFile, kefuSendOrderCard, kefuSendProductCard,
kefuLoadHistory, kefuOnMessages, kefuOnMessageStatus,
kefuGetUnreadCount, kefuMarkAllAsRead, kefuClearUnread, kefuGetMsgCount,
kefuDetectMsgType, kefuInviteEvaluation, kefuSubmitEvaluation,
kefuBindPushToken, kefuSetPushNickname,
kefuProbeReadStates, kefuResolveVideoUrl
} from '@/uni_modules/huanxin-kefu'
4.2 返回值
| 类型 | 结构 | 说明 |
|---|---|---|
KefuResult |
{ code, message } |
同步返回或异步 complete |
KefuCountResult |
{ code, message, count } |
未读数、消息条数 |
KefuMsgTypeResult |
{ code, message, msgType } |
消息类型检测 |
code === 0表示成功;非 0 为失败,message为人可读原因。- 常见错误码(插件侧约定,非环信官方错误码全集):
| code | 含义 |
|---|---|
0 |
成功 |
-1 |
未初始化 / 通用失败 |
-2 |
未登录 / appKey 为空等 |
-3 |
必填参数为空(如 IM 号、content、path) |
-4 |
会话不存在 / SDK init 失败等 |
-5 |
本地文件不存在 / 创建消息失败 |
-6 |
iOS 登录/注册进行中(防重入) |
-7 |
iOS 调用崩溃兜底 |
4.3 同步 vs 异步
| 模式 | 方法示例 |
|---|---|
| 同步 | kefuInit、kefuIsLoggedIn、kefuBindChat、kefuLoadHistory、kefuGetUnreadCount、kefuMarkAllAsRead、kefuClearUnread、kefuGetMsgCount、kefuDetectMsgType、kefuSetPushNickname、kefuProbeReadStates |
| 异步(complete) | kefuRegister、kefuLogin、kefuLogout、各类 kefuSend*、评价、推送绑定、kefuResolveVideoUrl |
| 长生命周期回调 | kefuOnMessages、kefuOnMessageStatus(@UTSJS.keepAlive,传 null 取消) |
4.4 serviceIMNumber
- 环信 IM 服务号,一律小写。插件内部会对传入值执行
toLowerCase(),但业务侧也建议直接传小写,避免会话 ID 不一致。 - 为空时部分接口行为不同,例如:
kefuGetUnreadCount('')返回全部会话未读合计;kefuClearUnread('')清全部会话未读。
4.5 本地文件路径
发图片 / 语音 / 视频 / 文件时:
- 支持绝对路径、
file://前缀(Android 会规范化)。 - Android 部分场景支持
content://(视频、文件)。 - 文件必须真实存在,否则返回
code: -5。
4.6 历史消息返回格式
kefuLoadHistory / kefuOnMessages 在双端均可能返回 JSON 字符串(数组)。业务侧建议统一:
function parseMsgs(raw) {
if (raw == null) return []
if (typeof raw === 'string') {
try { return JSON.parse(raw) } catch (e) { return [] }
}
return Array.isArray(raw) ? raw : []
}
5. 类型定义
以下与 utssdk/interface.uts 一致。
5.1 KefuInitOptions
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
appKey |
string |
是 | 环信 AppKey |
tenantId |
string |
是 | 租户 ID |
configId |
string |
否 | 渠道配置 ID |
consoleLog |
boolean |
否 | Android:打开 SDK 控制台日志 |
5.2 KefuVisitorInfo(访客信息,发送消息时可附带)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
nickName |
string |
是 | 昵称 |
name |
string |
否 | 真实姓名 |
phone |
string |
否 | 手机 |
email |
string |
否 | 邮箱 |
companyName |
string |
否 | 公司 |
qq |
string |
否 | |
desc |
string |
否 | 描述 |
userDefineColumn |
string |
否 | iOS 自定义字段 JSON 字符串;Android 扩展需后台配合 |
5.3 KefuChatMessage(历史 / 实时消息统一结构)
| 字段 | 类型 | 说明 |
|---|---|---|
msgId |
string |
消息 ID |
from |
string |
发送方 |
to |
string |
接收方 |
content |
string |
文本内容或占位文案(如 [图片]) |
msgType |
string |
见 消息类型 |
direction |
string |
send / receive |
timestamp |
number |
毫秒时间戳 |
mediaUrl |
string? |
图片/语音/视频/文件/表情地址 |
thumbUrl |
string? |
缩略图 |
duration |
number? |
语音/视频时长(秒) |
title |
string? |
订单/商品标题 |
orderTitle |
string? |
订单号等 |
price |
string? |
价格 |
imageUrl |
string? |
卡片图 |
itemUrl |
string? |
跳转链接 |
desc |
string? |
描述 |
inviteId |
string? |
评价邀请 ID(提交评价时回传,iOS 更完整) |
sessionId |
string? |
会话 ID(评价用) |
agentNick |
string? |
坐席昵称(区分人工 / 自动回复) |
isRead |
boolean? |
已读:发送=对方是否已读;接收=我方是否已读 |
6. API 详细说明
6.1 基础:初始化 / 账号
kefuInit(options): KefuResult
初始化客服 SDK。必须最先调用;重复调用若已成功会返回 already_inited。
const res = kefuInit({
appKey: 'xxx#xxx',
tenantId: '12345',
configId: '', // 可选
consoleLog: true // Android 调试建议开
})
if (res.code !== 0) {
console.error('init fail', res.message)
}
| 成功 message | 说明 |
|---|---|
init_ok |
首次初始化成功 |
already_inited |
已初始化,跳过 |
插件会开启单聊已读回执(requireAck / enableRequireReadAck),以便 isRead 能正确反映对方已读。
kefuRegister({ username, password, complete? })
注册访客 IM 账号。需先 kefuInit。
kefuRegister({
username: 'visitor_001',
password: '123456',
complete: (res) => {
if (res.code === 0) console.log('注册成功')
else console.error(res.message)
}
})
| 参数 | 必填 | 说明 |
|---|---|---|
username |
是 | 账号 |
password |
是 | 密码 |
complete |
否 | 异步结果 |
生产环境建议服务端注册,避免客户端暴露注册能力。
kefuLogin({ username, password?, token?, complete? })
登录。token 优先于 password;二者至少传一个。
// 密码登录
kefuLogin({
username: 'visitor_001',
password: '123456',
complete: (res) => { /* res.code === 0 */ }
})
// Token 登录(推荐)
kefuLogin({
username: 'visitor_001',
token: '从服务端拿到的token',
complete: (res) => {}
})
| 行为 | 说明 |
|---|---|
| 已登录 | 直接 complete({ code: 0, message: 'already_logged_in' }),不重复登录 |
| iOS 密码登录 | 同步调用 SDK,通过 complete 回传结果 |
| iOS Token 登录 | 异步 completion |
| 缺少凭证 | code: -1,请传 password 或 token |
kefuIsLoggedIn(): boolean
是否处于已登录状态(同步)。
if (!kefuIsLoggedIn()) {
// 去登录
}
kefuLogout(unbindDeviceToken, complete)
退出登录。
| 参数 | 类型 | 说明 |
|---|---|---|
unbindDeviceToken |
boolean |
是否解绑推送 deviceToken;一般退出账号传 true |
complete |
function \| null |
结果回调,可为 null |
kefuLogout(true, (res) => {
console.log(res.code, res.message)
})
kefuOpenChat(options)
打开原生客服会话页。
| 参数 | 必填 | 说明 |
|---|---|---|
serviceIMNumber |
是 | IM 服务号 |
visitorInfo |
否 | 访客信息 |
queue |
否 | 指定技能组(Android EaseUI) |
agent |
否 | 指定坐席(Android EaseUI) |
kefuOpenChat({
serviceIMNumber: 'kefuchannelimid_xxxx',
visitorInfo: { nickName: '访客小明', phone: '***' },
queue: '',
agent: ''
})
| 平台 | 行为 |
|---|---|
| Android | 启动 EaseUI IntentBuilder 原生页(需登录且已 init) |
| iOS | 空实现(无 HelpDeskUI),请用自建页 + kefuBindChat |
6.2 自建会话:绑定 / 解绑
kefuBindChat(serviceIMNumber): KefuResult
绑定与指定服务号的会话。自建页登录成功后必须调用。
const res = kefuBindChat('kefuchannelimid_xxxx')
// 成功:{ code: 0, message: 'bind_ok' }
前置条件:已 kefuInit、已登录、serviceIMNumber 非空。
kefuUnbindChat(): void
解绑当前会话。离开客服页时调用。
kefuUnbindChat()
6.3 发送消息
所有发送类接口共性:
- 需已初始化 + 已登录 +
serviceIMNumber有效。 - 可选
visitorInfo附带访客资料(Android 文本/图片等会addContent;卡片类同样支持)。 - 通过
complete({ code, message })获知结果。
kefuSendText(options)
| 字段 | 必填 | 说明 |
|---|---|---|
serviceIMNumber |
是 | 服务号 |
content |
是 | 文本,不能为空 |
visitorInfo |
否 | 访客信息 |
complete |
否 | 回调 |
kefuSendText({
serviceIMNumber,
content: '你好,我想咨询订单',
visitorInfo: { nickName: '小明' },
complete: (res) => console.log(res)
})
kefuSendImage(options)
| 字段 | 必填 | 说明 |
|---|---|---|
serviceIMNumber |
是 | 服务号 |
path |
是 | 本地图片路径 |
original |
否 | true 原图,默认压缩 |
visitorInfo |
否 | 访客信息 |
complete |
否 | 回调 |
uni.chooseImage({
count: 1,
success: (r) => {
kefuSendImage({
serviceIMNumber,
path: r.tempFilePaths[0],
original: false,
complete: (res) => console.log(res)
})
}
})
kefuSendEmoji(options)
发送大表情 / 自定义表情(远程 URL,不是本地上传图片)。
| 字段 | 必填 | 说明 |
|---|---|---|
serviceIMNumber |
是 | 服务号 |
url |
是 | 表情资源远程地址 |
emojiName |
否 | 表情名(类型已声明,按业务需要传) |
visitorInfo |
否 | 访客信息 |
complete |
否 | 回调 |
kefuSendEmoji({
serviceIMNumber,
url: 'https://example.com/emoji/smile.gif',
emojiName: 'smile',
complete: (res) => console.log(res)
})
kefuSendVoice(options)
| 字段 | 必填 | 说明 |
|---|---|---|
serviceIMNumber |
是 | 服务号 |
path |
是 | 本地语音文件路径 |
duration |
是 | 时长(秒) |
visitorInfo |
否 | 访客信息 |
complete |
否 | 回调 |
kefuSendVoice({
serviceIMNumber,
path: localVoicePath,
duration: 3,
complete: (res) => console.log(res)
})
kefuSendVideo(options)
| 字段 | 必填 | 说明 |
|---|---|---|
serviceIMNumber |
是 | 服务号 |
path |
是 | 本地视频路径(Android 支持 content://) |
thumbPath |
否 | 封面图本地路径 |
duration |
否 | 时长(秒) |
visitorInfo |
否 | 访客信息 |
complete |
否 | 回调 |
kefuSendVideo({
serviceIMNumber,
path: videoPath,
thumbPath: coverPath,
duration: 12,
complete: (res) => console.log(res)
})
历史消息中的视频播放地址请用 kefuResolveVideoUrl 解析(见 6.7)。
kefuSendFile(options)
| 字段 | 必填 | 说明 |
|---|---|---|
serviceIMNumber |
是 | 服务号 |
path |
是 | 本地文件路径 |
displayName |
否 | 展示文件名(iOS 使用;Android 主要靠路径) |
visitorInfo |
否 | 访客信息 |
complete |
否 | 回调 |
kefuSendFile({
serviceIMNumber,
path: filePath,
displayName: '说明书.pdf',
complete: (res) => console.log(res)
})
kefuSendOrderCard(options)
发送订单卡片(底层 OrderInfo)。
| 字段 | 必填 | 说明 |
|---|---|---|
serviceIMNumber |
是 | 服务号 |
title |
是 | 标题 |
orderTitle |
否 | 订单号 / 订单副标题 |
price |
否 | 价格 |
desc |
否 | 描述 |
imageUrl |
否 | 商品图 URL |
itemUrl |
否 | 点击跳转 URL |
visitorInfo |
否 | 访客信息 |
complete |
否 | 回调 |
kefuSendOrderCard({
serviceIMNumber,
title: '无线耳机',
orderTitle: 'ORD20261111001',
price: '¥199.00',
desc: '待发货',
imageUrl: 'https://example.com/p.png',
itemUrl: 'https://example.com/order/1',
complete: (res) => console.log(res)
})
kefuSendProductCard(options)
发送商品轨迹卡片(底层 VisitorTrack),字段同卡片共用类型,一般不用 orderTitle。
kefuSendProductCard({
serviceIMNumber,
title: '春季新款外套',
price: '¥299',
desc: '用户正在浏览',
imageUrl: 'https://example.com/goods.png',
itemUrl: 'https://example.com/goods/1001',
complete: (res) => console.log(res)
})
历史/实时消息中:订单 msgType === 'order',商品 msgType === 'track'。
6.4 历史消息与实时收消息
kefuLoadHistory(options): any
从本地会话加载历史(必要时 Android 会回退 EM 漫游)。
| 字段 | 必填 | 默认 | 说明 |
|---|---|---|---|
serviceIMNumber |
是 | — | 服务号 |
pageSize |
否 | Android 默认 20,iOS 默认 30 |
条数 |
startMsgId |
否 | 空 | 从该消息 ID 之前继续翻页;空串勿传当有效 ID(会导致查不到) |
// 第一页
let raw = kefuLoadHistory({ serviceIMNumber, pageSize: 30 })
let list = parseMsgs(raw)
// 上拉加载更多:传当前列表最旧一条的 msgId
if (list.length > 0) {
raw = kefuLoadHistory({
serviceIMNumber,
pageSize: 30,
startMsgId: list[0].msgId
})
const older = parseMsgs(raw)
list = older.concat(list)
}
| 说明 | 详情 |
|---|---|
| 返回值 | JSON 字符串数组(推荐按字符串 JSON.parse) |
| 排序 | 时间升序(旧 → 新) |
| 首屏 | Android 加载成功后会 markAllMessagesAsRead(无 startMsgId 时) |
| 失败/空 | 返回 '[]' |
kefuOnMessages(callback | null): void
注册实时消息监听。长生命周期回调,传 null 取消。
kefuOnMessages((raw) => {
const msgs = parseMsgs(raw)
msgs.forEach((m) => {
console.log(m.msgType, m.content, m.direction)
})
// 追加到 UI 列表
})
// 离开页面
kefuOnMessages(null)
实现使用
@UTSJS.keepAlive+export function,避免 UTS 回调只触发一次。
kefuOnMessageStatus(callback | null): void
发送状态 / 已读回执变化时回调(无参数)。页面可据此刷新气泡已读状态。
kefuOnMessageStatus(() => {
// 例如对当前列表 msgId 调 kefuProbeReadStates 后更新 isRead
})
kefuOnMessageStatus(null) // 取消
6.5 未读 / 已读 / 消息数
kefuGetUnreadCount(serviceIMNumber): KefuCountResult
const one = kefuGetUnreadCount('kefuchannelimid_xxxx')
// { code: 0, message: 'success', count: 3 }
const all = kefuGetUnreadCount('') // 全部会话未读合计
serviceIMNumber |
行为 |
|---|---|
| 非空 | 指定会话未读;无会话时 count: 0,message: 'no_conversation' |
| 空串 | 全部会话未读合计 |
kefuMarkAllAsRead(serviceIMNumber): KefuResult
将会话标为已读,并向对方发送已读回执(便于对方气泡变「已读」)。
const res = kefuMarkAllAsRead(serviceIMNumber)
// 成功:{ code: 0, message: 'marked' }
kefuClearUnread(serviceIMNumber): KefuResult
未读清零。
kefuClearUnread(serviceIMNumber) // 指定会话
kefuClearUnread('') // 全部会话
成功 message:cleared / all_cleared(Android 清全部时)。
kefuGetMsgCount(serviceIMNumber): KefuCountResult
指定会话本地消息总条数。
const res = kefuGetMsgCount(serviceIMNumber)
console.log(res.count)
kefuDetectMsgType(msgId): KefuMsgTypeResult
按消息 ID 检测类型。
const t = kefuDetectMsgType(msgId)
// { code: 0, message: 'success', msgType: 'image' }
msgType 可能值见 7.2。
kefuProbeReadStates(msgIdsJson): string
按消息 ID 批量探测已读(不拉历史)。
| 入参 | '["id1","id2"]' JSON 字符串 |
| 返回 | '{"id1":true,"id2":false}' JSON 字符串 |
语义:
- 自己发的:对方是否已读(
isAcked) - 对方发的:我方是否已读(
!isUnread)
const ids = list.map((m) => m.msgId)
const map = JSON.parse(kefuProbeReadStates(JSON.stringify(ids)))
list.forEach((m) => { m.isRead = !!map[m.msgId] })
6.6 满意度评价
kefuInviteEvaluation({ serviceIMNumber, sessionId?, complete? })
访客侧主动发起满意度评价邀请(是否允许取决于后台策略)。
kefuInviteEvaluation({
serviceIMNumber,
sessionId: '', // 可选
complete: (res) => console.log(res)
})
kefuSubmitEvaluation(options)
提交评价(score 1~5,插件内会钳制)。
| 字段 | 必填 | 说明 |
|---|---|---|
msgId |
是 | 评价邀请消息 ID |
score |
是 | 1~5 分 |
detail |
否 | 评价文案 |
evaluateWay |
否 | visitor / agent / system(类型声明;Android 当前主要走 MessageHelper) |
inviteId |
否 | 邀请 ID(iOS 提交时使用) |
sessionId |
否 | 会话 ID |
serviceIMNumber |
iOS 强烈建议 | iOS 实现要求非空;Android 可不依赖 |
complete |
否 | 回调 |
kefuSubmitEvaluation({
msgId: evalMsg.msgId,
score: 5,
detail: '服务很好',
inviteId: evalMsg.inviteId,
sessionId: evalMsg.sessionId,
serviceIMNumber,
complete: (res) => console.log(res)
})
收到 msgType === 'evaluation' 的消息时,用其 msgId(及 inviteId / sessionId)提交。
6.7 视频地址解析
kefuResolveVideoUrl({ msgId, serviceIMNumber?, complete? })
解析历史视频可播放地址:优先本地文件 → 触发 SDK 下载 → 失败回退远程直链。
成功时 complete 的 message 字段即为可播 URL(code === 0)。
kefuResolveVideoUrl({
msgId: videoMsg.msgId,
serviceIMNumber,
complete: (res) => {
if (res.code === 0) {
const playUrl = res.message
// 用 video 组件播放
}
}
})
6.8 推送
本插件只负责把 token / 昵称交给环信;厂商推送通道需 App 自行集成,拿到 token 后再调用。
kefuBindPushToken({ token, vendor?, complete? })
| 平台 | token |
vendor |
|---|---|---|
| Android | 厂商推送 token 字符串 | hms(默认)或 fcm |
| iOS | 设备 token 的 hex 字符串 | 可省略(内部按 APNs 绑定) |
// Android 华为
kefuBindPushToken({
token: hmsToken,
vendor: 'hms',
complete: (res) => console.log(res)
})
// Android FCM
kefuBindPushToken({ token: fcmToken, vendor: 'fcm', complete: (res) => {} })
// iOS:把 NSData deviceToken 转成 hex 再传
kefuBindPushToken({
token: deviceTokenHex,
complete: (res) => console.log(res)
})
kefuSetPushNickname(nickname): KefuResult
设置推送显示昵称(同步)。
const res = kefuSetPushNickname('访客小明')
// 成功:{ code: 0, message: 'nickname_ok' }
7. 消息结构与类型
7.1 使用建议
自建 UI 时按 msgType 分支渲染:
| msgType | UI 建议 |
|---|---|
txt |
文本气泡 |
image / emoji |
图片;表情可用 mediaUrl |
voice |
语音条,duration + mediaUrl |
video |
封面 thumbUrl,点击后 kefuResolveVideoUrl |
file |
文件行,mediaUrl / content |
order |
订单卡片:title / orderTitle / price / imageUrl / itemUrl |
track |
商品卡片:title / price / imageUrl / itemUrl |
evaluation |
评价邀请 UI → kefuSubmitEvaluation |
robot_menu / articles / form / cmd |
按业务扩展或降级为文本提示 |
direction:send 右对齐,receive 左对齐。
agentNick 可用于展示坐席名;无坐席时多为系统/机器人。
7.2 msgType 取值
txt | image | voice | video | file | emoji | order | track | evaluation | robot_menu | articles | form | cmd | general | unknown
8. 完整示例
// pages/kefu/chat.vue 片段(APP-PLUS)
import {
kefuInit, kefuLogin, kefuIsLoggedIn,
kefuBindChat, kefuUnbindChat,
kefuSendText, kefuSendImage, kefuSendVoice,
kefuLoadHistory, kefuOnMessages, kefuOnMessageStatus,
kefuMarkAllAsRead, kefuGetUnreadCount,
kefuSubmitEvaluation, kefuResolveVideoUrl, kefuProbeReadStates
} from '@/uni_modules/huanxin-kefu'
const CFG = {
appKey: 'YOUR_APP_KEY',
tenantId: 'YOUR_TENANT_ID',
serviceIMNumber: 'kefuchannelimid_xxxx'
}
function parseMsgs(raw) {
if (typeof raw === 'string') {
try { return JSON.parse(raw) } catch (e) { return [] }
}
return Array.isArray(raw) ? raw : []
}
export default {
data() {
return { messages: [], serviceIMNumber: CFG.serviceIMNumber }
},
onLoad() {
kefuInit({
appKey: CFG.appKey,
tenantId: CFG.tenantId,
consoleLog: true
})
const afterLogin = () => {
kefuBindChat(this.serviceIMNumber)
kefuOnMessages((raw) => {
this.messages = this.messages.concat(parseMsgs(raw))
})
kefuOnMessageStatus(() => this.refreshReadStates())
this.messages = parseMsgs(kefuLoadHistory({
serviceIMNumber: this.serviceIMNumber,
pageSize: 30
}))
kefuMarkAllAsRead(this.serviceIMNumber)
}
if (kefuIsLoggedIn()) afterLogin()
else {
kefuLogin({
username: 'visitor_001',
token: 'SERVER_TOKEN',
complete: (res) => { if (res.code === 0) afterLogin() }
})
}
},
onUnload() {
kefuOnMessages(null)
kefuOnMessageStatus(null)
kefuUnbindChat()
},
methods: {
sendText(text) {
kefuSendText({
serviceIMNumber: this.serviceIMNumber,
content: text,
visitorInfo: { nickName: '访客' },
complete: (res) => {
if (res.code === 0) {
// 可乐观插入或重新 loadHistory
}
}
})
},
refreshReadStates() {
const ids = this.messages.map((m) => m.msgId)
if (!ids.length) return
const map = JSON.parse(kefuProbeReadStates(JSON.stringify(ids)))
this.messages.forEach((m) => { m.isRead = !!map[m.msgId] })
},
playVideo(msg) {
kefuResolveVideoUrl({
msgId: msg.msgId,
serviceIMNumber: this.serviceIMNumber,
complete: (res) => {
if (res.code === 0) {
// res.message = 可播 url
}
}
})
},
submitEval(msg, score, detail) {
kefuSubmitEvaluation({
msgId: msg.msgId,
score,
detail,
inviteId: msg.inviteId,
sessionId: msg.sessionId,
serviceIMNumber: this.serviceIMNumber,
complete: (res) => console.log(res)
})
},
badge() {
return kefuGetUnreadCount(this.serviceIMNumber).count
}
}
}
9. 打包说明
- 运行 → 制作自定义调试基座(勾选
huanxin-kefu) - 安装基座后,用 自定义调试基座 运行调试
- 正式发版:发行 → 原生 App-云打包
- wgt 热更新无法更新原生 SDK / UTS;改
index.uts、aar、xcframework 后必须重打基座或云打包
Android 注意
- 不要再单独放
kefu-sdk-*.jar或重复libhyphenate.so,否则 Duplicate class / so 冲突。 minSdkVersion:21;ABI:armeabi-v7a、arm64-v8a。- 音视频坐席(Agora 等)未写入
config.json,避免云打包依赖失败;需要时再加。
iOS 注意
- Framework 仅
ios-arm64(真机);模拟器需自行换含模拟器切片的包。 - 部署版本:iOS 12.0+。
- 云打包勿保留
HyphenateChat.swiftmodule(会导致 module interface 报错)。 Info.plist已声明相机 / 麦克风 / 相册用途说明。
10. 权限与后台配置
权限(聊天收发媒体)
| 平台 | 用途 |
|---|---|
| Android | 相机、麦克风、存储(随业务申请) |
| iOS | NSCameraUsageDescription、NSMicrophoneUsageDescription、NSPhotoLibraryUsageDescription 等(插件 Info.plist 已带) |
环信后台
- AppKey、TenantId、IM 服务号(小写)
- APP 渠道关联:文档
- 用户账号建议服务端注册,客户端 Token 登录
- 推送:在环信控制台配置厂商证书 / APNs,App 取 token 后调
kefuBindPushToken
隐私声明(插件 package.json)
- 广告:无
- 数据:插件不采集业务数据,消息由环信云处理
- 权限:相机、麦克风、存储用于图片/语音等
11. 常见问题
Q: 标准基座里调用无反应 / 报找不到模块?
A: UTS 原生插件必须用自定义调试基座或云打包后的包。
Q: 历史一直为空?
A: 确认 serviceIMNumber 小写、已登录、已发过消息产生会话;startMsgId 不要传空串当有效 ID;可先不传 startMsgId 拉首页。
Q: iOS kefuOpenChat 没页面?
A: 预期行为。请自建聊天页,使用 kefuBindChat + 发送/历史/监听 API。
Q: 发送图片失败「文件不存在」?
A: 检查 path 是否为真实本地路径;Android 注意 file:// 与相册临时路径有效期。
Q: 已读状态不更新?
A: 确保走过 kefuInit(已开 ack);进入会话调 kefuMarkAllAsRead;监听 kefuOnMessageStatus 并用 kefuProbeReadStates 刷新。
Q: 视频点了播不了?
A: 历史视频的 mediaUrl 可能不可直接播,请用 kefuResolveVideoUrl,成功后用返回的 message 作为播放地址。
Q: 改了插件代码标准运行仍是旧逻辑?
A: 重做自定义基座 / 重新云打包;wgt 无法更新原生层。
API 速查表
| 方法 | 同步/异步 | 一句话 |
|---|---|---|
kefuInit |
同步 | 初始化 SDK |
kefuRegister |
异步 | 注册访客 |
kefuLogin |
异步 | 密码或 Token 登录 |
kefuLogout |
异步 | 退出 |
kefuIsLoggedIn |
同步 | 是否已登录 |
kefuOpenChat |
— | 原生页(仅 Android EaseUI) |
kefuBindChat |
同步 | 绑定会话 |
kefuUnbindChat |
— | 解绑会话 |
kefuSendText |
异步 | 发文本 |
kefuSendImage |
异步 | 发图片 |
kefuSendEmoji |
异步 | 发大表情(远程 URL) |
kefuSendVoice |
异步 | 发语音 |
kefuSendVideo |
异步 | 发视频 |
kefuSendFile |
异步 | 发文件 |
kefuSendOrderCard |
异步 | 发订单卡片 |
kefuSendProductCard |
异步 | 发商品轨迹 |
kefuLoadHistory |
同步 | 拉历史(JSON 字符串) |
kefuOnMessages |
回调 | 收消息;null 取消 |
kefuOnMessageStatus |
回调 | 状态/已读变化;null 取消 |
kefuGetUnreadCount |
同步 | 未读数 |
kefuMarkAllAsRead |
同步 | 会话标已读 + 回执 |
kefuClearUnread |
同步 | 未读清零 |
kefuGetMsgCount |
同步 | 会话消息条数 |
kefuDetectMsgType |
同步 | 检测消息类型 |
kefuProbeReadStates |
同步 | 批量探测已读 JSON |
kefuInviteEvaluation |
异步 | 发起评价邀请 |
kefuSubmitEvaluation |
异步 | 提交评价 1~5 |
kefuResolveVideoUrl |
异步 | 解析视频可播 URL |
kefuBindPushToken |
异步 | 绑定推送 token |
kefuSetPushNickname |
同步 | 推送昵称 |

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 4473
赞赏 36
下载 12758380
赞赏 1959
赞赏
京公网安备:11010802035340号