更新记录

2.4.1(2026-07-20) 下载此版本

  • 修复从插件市场导入后运行报 agora-player 组件路径错误:
    • pages_init.jsonusingComponents 路径改为以 / 开头,避免微信解析为相对页面目录
  • 修复网络恢复后 danger 级网络提示条需等待定时器才消失的问题
  • 修复 demo 首页输入框在跨设备粘贴/第三方输入法场景下不同步的问题
  • 插件目录与 ID 统一为 em-callkit-weixin(≤20 字符,符合 DCloud 规范)
  • 插件类型调整为前端模板,readme 与 package.json 增加 DCloud 插件市场链接

2.4.0(2026-07-20) 下载此版本

  • 新增群组多人音视频通话:
    • 主叫 inviteGroupCall / 通话中 inviteMoreParticipants 追加邀请
    • 被叫待接听页(群名、主叫方、被邀请成员,同意后才会加入)
    • 视频模式自适应网格布局(1 全屏 / 2 上下 / 3 一大两小 / 4 宫格 / 6 宫格 / 9 宫格,末行居中),本地与远端等权瓦片
    • 远端可见视频限 4 路,超出降级头像瓦片 + 隐藏 player 保活音频
    • 语音模式 3 列头像网格,等待中成员半透明展示
    • 新增 useGroupCallState 群聊状态 Store
  • 群聊通话页内置「邀请」入口:底部半屏成员多选面板(已在通话成员自动置灰),新增 getGroupMembers 数据源选项
  • 通话中新邀请的成员通过 participantStateChanged 即时以等待态上屏
  • callState 新增 localUserId,昵称展示链统一为 userInfoMap → participant.nickname → userId
  • 修复 agora-player 组件默认在画面右上角显示 RTC uid 水印(改为仅 debug 模式显示)
  • 修复群聊页瓦片坐标相对容器重复偏移导致顶部黑框
  • readme 补齐群聊接入文档、完整 API 表格与已知限制清单

平台兼容性

uni-app(5.07)

Vue2 Vue3 Vue3插件版本 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
× 2.4.1 × × × × × × ×
微信小程序 微信小程序插件版本 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
2.4.1 × × × × × × × × × × ×

Easemob CallKit UniApp 微信小程序插件

环信 CallKit UniApp 微信小程序插件,基于 @easemob-community/callkit-core 构建,提供开箱即用的 1v1 与群组音视频通话能力。

平台支持

  • ✅ UniApp Vue3
  • ✅ 微信小程序
  • ❌ App(App 端将单独建包)

快速开始

1. 导入插件

在 HBuilderX 中把本插件目录放入宿主项目的 uni_modules/ 下:

your-project/
├── pages.json
├── manifest.json
├── App.vue
└── uni_modules/
    └── em-callkit-weixin/   ← 本插件

2. 安装环信 IM SDK

宿主项目需要自行安装并初始化环信 IM SDK:

npm install easemob-websdk
# 或
pnpm add easemob-websdk

插件已内置 @easemob-community/callkit-coreagora-miniapp-sdk,无需额外安装。

3. 配置小程序权限与域名

⚠️ 类目资质要求:微信小程序的 live-pusher / live-player 组件仅对特定类目开放(如社交-直播、教育、医疗等)。请先在微信公众平台确认你的小程序类目具备实时音视频资质,否则真机上组件无法渲染,审核也会被驳回。参考:live-pusher 官方文档

manifest.jsonmp-weixin 节点中声明音视频权限:

{
  "mp-weixin": {
    "permission": {
      "scope.record": { "desc": "用于音视频通话" },
      "scope.camera": { "desc": "用于视频通话" }
    }
  }
}

并在微信小程序后台配置服务器域名:

  • socket 合法域名wss://im-api-wechat.easemob.com
  • uploadFile 合法域名https://a1.easemob.com
  • downloadFile 合法域名https://a1.easemob.com
  • live-pusher / live-player 域名:按声网控制台配置(通常包含 *.agoraio.cn 等)

4. 初始化 CallKit

在宿主项目的 App.vue 或业务入口中:

<script setup>
import { createIMConnectionAdapter, createUniappMpWeixinCallKit } from '@/uni_modules/em-callkit-weixin'
import SDK from 'easemob-websdk/uniApp/Easemob-chat'

// 1. 创建环信连接(宿主自行负责)
const conn = new SDK.connection({
  appKey: 'your-app-key',
  url: 'wss://im-api-wechat.easemob.com/websocket',
  apiUrl: 'https://a1.easemob.com'
})

// 2. 登录
await conn.open({ user: 'userId', accessToken: 'token' })

// 3. 包装成 CallKit 需要的形态
const imClient = createIMConnectionAdapter(conn)

// 4. 初始化 CallKit
const callKit = createUniappMpWeixinCallKit({
  imClient,
  userProfile: {
    userId: 'userId',
    nickname: '我的昵称',
    avatarURL: 'https://...'
  }
})

// 5. 挂载到全局,供其他页面/组件使用
uni.$callKit = callKit
</script>

TypeScript 全局类型声明(可选)

如果宿主项目使用 TypeScript,建议在 types/ 目录添加全局声明,让 uni.$callKit 有类型提示:

// types/global.d.ts
import type { CallKitInstance } from '@/uni_modules/em-callkit-weixin'

declare global {
  interface UniApp {
    $callKit?: CallKitInstance
    $imClient?: any
  }
}

export {}

并在 tsconfig.jsoninclude 中确保包含 types/**/*.d.ts

5. 发起呼叫

在任意页面中:

<script setup>
function callUser(userId, callType) {
  uni.navigateTo({
    url: `/uni_modules/em-callkit-weixin/pages/single-call-page/single-call-page?targetUserId=${userId}&callType=${callType}`
  })
}

// 语音呼叫
callUser('targetUserId', 'audio')

// 视频呼叫
callUser('targetUserId', 'video')
</script>

6. 发起群组通话

通过 inviteGroupCall 发起群语音/群视频通话(主叫会自动进入内置群聊通话页):

import { CALL_TYPE } from '@/uni_modules/em-callkit-weixin'

// 群视频通话
await uni.$callKit.inviteGroupCall({
  groupId: 'group-id',
  participantIds: ['user1', 'user2', 'user3'], // 被邀请的群成员 userId 列表
  callType: CALL_TYPE.VIDEO_MULTI,
  ext: { groupName: '产品讨论群' }
})

// 群语音通话
await uni.$callKit.inviteGroupCall({
  groupId: 'group-id',
  participantIds: ['user1', 'user2'],
  callType: CALL_TYPE.AUDIO_MULTI,
  ext: { groupName: '产品讨论群' }
})

被叫方会收到群聊来电,进入待接听页面(显示群名、主叫方、被邀请成员),同意后才加入通话。

通话中邀请更多成员

群聊通话页底部控制栏内置了「邀请」按钮,点击后弹出底部半屏成员选择面板(已在通话中的成员自动置灰)。面板的数据源需要宿主在初始化时提供:

const callKit = createUniappMpWeixinCallKit({
  imClient,
  getGroupMembers: async (groupId) => {
    // 返回该群组全部成员,插件会把已在通话中的成员标记为不可选
    const res = await conn.listGroupMembers({ groupId, pageNum: 1, pageSize: 100 })
    return (res?.data || []).map((m) => ({
      userId: m.member || m.owner || m.admin,
      nickname: '可选昵称',
      avatarURL: '可选头像'
    }))
  }
})

未配置 getGroupMembers 时点击「邀请」仅提示不可用。也可以通过 API 直接邀请:

await uni.$callKit.inviteMoreParticipants(['user4'])

群聊通话页布局

  • 视频模式:自适应网格(1 人全屏 / 2 人上下分屏 / 3 人一大两小 / 4 人 2×2 / 5~6 人 2列3行 / 7~9 人 3×3),本地与远端成员等权显示
  • 语音模式:3 列头像网格,显示昵称、等待状态
  • 受微信小程序 live-player 并发能力限制,视频画面默认最多同时渲染 4 路,超出的成员显示头像占位(音频保持可听)

来电处理

插件提供三种来电处理方式,宿主可按需选择:

方式一:自行处理来电(推荐)

通过 onIncomingCall 回调完全自定义来电展示:

const callKit = createUniappMpWeixinCallKit({
  imClient,
  onIncomingCall: (payload) => {
    // payload: { callerUserId, callType, callId }
    console.log('收到来电', payload)
    // 展示自定义弹窗
    // 返回 true 表示宿主已处理,插件不再自动跳转
    return true
  }
})

方式二:使用内置通知条

App.vue 根节点放置组件:

<template>
  <view class="app-root">
    <invitation-notification :user-info-map="userInfoMap" />
    <!-- 页面内容 -->
  </view>
</template>

<script setup>
const userInfoMap = {
  'user1': { nickname: '张三', avatarURL: 'https://...' }
}
</script>

组件会自动监听 incomingCall 事件,在顶部显示来电通知条,并提供接听/拒绝按钮。

方式三:默认跳转

如果既未设置 onIncomingCall,也未使用 invitation-notification,收到来电时插件默认自动跳转到内置单聊通话页。

完整 API

createUniappMpWeixinCallKit(options)

参数 类型 必填 说明
imClient IMAdaptedConnection createIMConnectionAdapter 包装后的环信连接
userProfile { userId, nickname?, avatarURL? } 当前用户资料
rtcAdapter RtcAdapter 自定义 RTC 适配器,默认使用声网小程序 SDK
onIncomingCall (payload) => boolean \| void 来电回调,返回 true 拦截默认跳转
showDefaultToast boolean 是否显示内置的通话结束状态 Toast("对方已拒绝"等),默认 true;宿主若已通过 onEvent 自行处理可设为 false
getGroupMembers (groupId) => Promise<GroupMemberInfo[]> 群成员数据源,群聊通话页「邀请」面板通过它拉取候选人

返回值CallKitInstance

属性/方法 说明
core CallKitCore 实例,提供 inviteCall / answerCall / hangup 等核心 API
rtcAdapter RtcAdapter 实例,提供 RTC 原子操作
setUserInfo(userId, info) 设置单个用户资料(昵称/头像),通话页与来电通知展示用
setUserInfoMap(map) 批量设置用户资料
onEvent(handler) 订阅通话事件(callEnded / callRefused / participantJoined 等),返回取消订阅函数
inviteGroupCall(params) 发起群组通话,见上文「发起群组通话」
inviteMoreParticipants(ids) 群聊通话中追加邀请成员
getGroupMembers(groupId) 宿主配置的群成员数据源(如已配置),供邀请面板拉取候选人

createIMConnectionAdapter(connection)

把环信 IM SDK 的 connection 包装成 CallKit 需要的形态。

参数:环信 SDK 的 connection 实例

返回值IMAdaptedConnection

useCallState()

获取通话状态 Store:

import { useCallState } from '@/uni_modules/em-callkit-weixin'

const { state } = useCallState()
// state.status: 'idle' | 'inviting' | 'ringing' | 'in_call' | 'ended'
// state.callType: 'audio' | 'video'
// state.duration: number
// ...

useGroupCallState()

获取群聊通话状态 Store(自定义群聊通话页时使用):

import { useGroupCallState } from '@/uni_modules/em-callkit-weixin'

const { state } = useGroupCallState()
// state.session: { groupId, groupName, callType, callerUserId } | null
// state.participants: GroupParticipant[]  // 已入会成员(含流地址、等待状态)
// state.invitedParticipants: GroupParticipant[]  // 被邀请成员(响铃页展示)
// state.callStatus: 'idle' | 'ringing' | 'in_call' | 'ended'

createMpWeixinLogger(options?)

创建平台 Logger,可控制日志级别和上报:

import { createMpWeixinLogger } from '@/uni_modules/em-callkit-weixin'

const logger = createMpWeixinLogger({
  level: 'warn', // 'verbose' | 'debug' | 'info' | 'warn' | 'error' | 'silent'
  prefix: '[CallKit][微信小程序]'
})

默认根据环境自动判断:开发/体验版输出 debug,正式版只输出 warn/error

已知限制

  • 声网小程序 SDK 并发上限:单频道最多 17 人同时发送视频流、32 人同时发送纯音频流(视频+音频合计亦受限),详见声网文档
  • 视频渲染路数:受微信小程序 live-player 并发能力限制,群视频默认最多同时渲染 4 路画面,超出成员显示头像占位(音频正常)
  • 网格上限:群视频网格最多显示 9 个瓦片,更多成员以头像占位
  • 远端成员状态:远端成员的静音/摄像头开关状态暂不透传到 UI(信令层未携带该字段)
  • 来电响铃/震动:暂未内置,可通过 onEvent 监听 incomingCall 自行接入 uni.vibrateLong / innerAudioContext
  • App 端:本插件仅支持微信小程序,App 端将单独建包

常见问题

1. 真机上没有声音/画面

  • 检查是否已申请 scope.record / scope.camera 权限
  • 检查微信小程序后台是否配置了服务器域名(live-pusher/live-player 需要)
  • 查看控制台是否有 [CallKit][微信小程序] 开头的错误日志

2. 收到来电没有弹窗

  • 确认 imClient 已正确传入
  • 确认 onIncomingCall 没有返回 true(否则插件不会自动跳转)
  • 检查 IM 是否在线,是否能收到文本消息

3. 正式版日志太多

import { createMpWeixinLogger } from '@/uni_modules/em-callkit-weixin'

const logger = createMpWeixinLogger({ level: 'error' })

4. 如何自定义通话页面

通过 onIncomingCall 拦截来电后,自行导航到自定义页面,并调用 core.answerCall / core.hangup 等 API 控制通话。

开发

# 同步 callkit-core + agora-miniapp-sdk 到插件 vendor/
pnpm sync:all

# 类型检查
pnpm typecheck

详细开发规范见 skills/callkit-uniapp-mp-weixin-plugin.md

隐私、权限声明

1. 本插件需要申请的系统权限列表:

摄像头、麦克风

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

License

MIT License

Copyright (c) Easemob

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

暂无用户评论。