集成微信小程序
微信 VoIP 通话涉及小程序、业务服务端、探鸽云平台、设备端四方交互。小程序端负责用户登录、设备 VoIP 授权、发起/接听通话、中止呼叫。
接口归属说明:
- 微信提供:
wx.login、wx.requestDeviceVoIP、wx.getDeviceVoIPList、wmpf-voip插件(callDevice、onVoipEvent等)- 业务服务端提供:所有
/v1/voip/user/*和/v1/user/*路径的 HTTP 接口,需业务方按 集成业务服务端 自行实现
阅读本文前,请先了解 通话流程 和 集成业务服务端。小程序申请与配置见 微信小程序申请与配置。
一、需要实现什么
按开发顺序,小程序 VoIP 模块需要依次完成:
| 顺序 | 模块 | 做什么 |
|---|---|---|
| 1 | 微信登录 | wx.login → 业务服务端换取 openid |
| 2 | VoIP 授权 | SN Ticket → wx.requestDeviceVoIP → 上报授权关系 |
| 3 | 授权状态查询 | wx.getDeviceVoIPList 判断设备是否已授权 |
| 4 | 呼叫设备 | wmpf-voip 插件 callDevice → 进入通话页面 |
| 5 | 取消呼叫 | onVoipEvent('cancelVoip') → 通知业务服务端 |
二、微信登录
调用业务服务端 POST /v1/voip/user/wechat-mini-login。小程序先用 wx.login() 获取临时 code,发给服务端换取 openid。
// 获取 openid
const res = await wx.login()
const { data } = await request({
url: `${server}/v1/voip/user/wechat-mini-login`,
method: 'POST',
data: { code: res.code }
})
// data.wx_user_openid 即为当前用户 openid服务端内部调微信 jscode2session,返回 openid。openid 是后续所有 VoIP 操作的用户标识。
三、VoIP 设备授权
用户首次使用某设备通话前,需完成微信侧授权。
3.1 获取 SN Ticket
调业务服务端 POST /v1/voip/user/sn-ticket:
const { data } = await request({
url: `${server}/v1/voip/user/sn-ticket`,
method: 'POST',
data: { device_id: 'TIRZ00000001' }
})
// data.sn_ticket服务端内部调微信 getsnticket 接口签发。
3.2 调用微信授权
wx.requestDeviceVoIP({
sn: deviceId,
snTicket: ticket,
modelId: '<微信 IoT 后台配置的 ModelID>',
deviceName: deviceId,
success: () => { /* 授权成功 */ },
fail: (err) => {
// errCode 10001 表示已授权,等同于成功
if (err.errCode === 10001) { /* 已授权 */ }
}
})3.3 上报授权关系到业务服务端
授权成功后,调业务服务端 POST /v1/voip/user/report-auth:
await request({
url: `${server}/v1/voip/user/report-auth`,
method: 'POST',
data: {
device_id: deviceId,
wx_open_id: openId,
wx_model_id: modelId
}
})服务端存储后通过下行通道向设备推送 callers_update,设备可感知授权变更。
3.4 查询授权状态
wx.getDeviceVoIPList({
success: (res) => {
const authed = (res.list || [])
.filter(i => i.status === 1)
.map(i => i.sn)
// authed 中为已授权设备列表
}
})status === 1 表示已授权。通常在设备列表页面调用,与业务服务端设备列表交叉比对,显示哪些设备可通话。
四、呼叫设备
使用微信官方 wmpf-voip 插件。在 app.json 中声明:
{
"plugins": {
"wmpf-voip": {
"version": "latest",
"provider": "wx069abb402f7b1df9"
}
}
}4.1 发起呼叫
const wmpfVoip = requirePlugin('wmpf-voip').default
const { roomId } = await wmpfVoip.callDevice({
sn: deviceId,
modelId: '<微信 IoT ModelID>',
roomType: 'voice', // 'voice' 或 'video'
nickName: '用户昵称',
isCloud: true, // 必须为 true
payload: JSON.stringify({ // 自定义透传数据,服务端和设备端约定
wxa_from: 'app',
call_id: '<唯一呼叫 ID>'
})
})
// 保存当前通话上下文,供取消呼叫时使用
this.currentCall = { deviceId, roomId }
// 跳转到 VoIP 插件提供的通话页面
wx.redirectTo({ url: wmpfVoip.CALL_PAGE_PATH })| 参数 | 说明 |
|---|---|
sn | 设备 SN,与设备 ID 一致 |
modelId | 微信 IoT 后台配置的 ModelID |
roomType | "voice" 或 "video" |
isCloud | 必须为 true,使用云代理模式 |
payload | 自定义 JSON 字符串,微信透传至服务端和设备端。建议约定 wxa_from(标识主叫方)和 call_id(唯一呼叫标识) |
4.2 通话页面
callDevice 成功后跳转至 wmpfVoip.CALL_PAGE_PATH,插件提供完整的通话 UI(来电界面、接通/挂断按钮、音视频渲染)。无需自行开发通话页面。
五、未接通时取消呼叫
小程序主叫、被叫尚未接听时,用户主动取消。监听 wmpf-voip 插件事件:
const wmpfVoip = requirePlugin('wmpf-voip').default
App({
onLaunch() {
wmpfVoip.onVoipEvent((event) => {
if (event.eventName === 'cancelVoip') {
this._handleCancel(event)
}
})
},
_handleCancel(event) {
if (!this.currentCall) return
const { deviceId, roomId } = this.currentCall
this.currentCall = null
// 调业务服务端 POST /v1/voip/user/cancel,由服务端推送 call_cancel 至设备
wx.request({
url: `${server}/v1/voip/user/cancel`,
method: 'POST',
data: { device_id: deviceId, wx_room_id: roomId }
})
}
})服务端收到后通过下行通道向设备推送 call_cancel,设备收到后结束振铃。
六、解绑时删除授权
用户解绑设备时,同步调业务服务端删除 VoIP 授权记录:
// 调业务服务端 DELETE /v1/user/device/reset(解绑设备)
await request({
url: `${server}/v1/user/device/reset`,
method: 'DELETE',
data: { device_id: deviceId }
})
// 调业务服务端 POST /v1/voip/user/delete-auth(删除 VoIP 授权)
await request({
url: `${server}/v1/voip/user/delete-auth`,
method: 'POST',
data: {
device_id: deviceId,
wx_open_id: openId
}
})服务端自动通过下行通道推送 callers_update 至设备。
七、完整流程示例
1. 用户登录
wx.login → code → POST /v1/voip/user/wechat-mini-login → openid
2. 首次使用设备:
a. POST /v1/voip/user/sn-ticket → sn_ticket
b. wx.requestDeviceVoIP({ sn, snTicket, modelId })
c. POST /v1/voip/user/report-auth → 上报授权关系
d. 服务端推送 callers_update → 设备
3. 呼叫设备:
a. wmpfVoip.callDevice({ sn, modelId, roomType, isCloud: true })
b. 拿到 roomId,保存 currentCall = { deviceId, roomId }
c. wx.redirectTo({ url: CALL_PAGE_PATH })
4. 取消呼叫(被叫未接听):
wmpfVoip.onVoipEvent('cancelVoip') → POST /v1/voip/user/cancel八、实现要点
| 要点 | 说明 |
|---|---|
isCloud 必须为 true | 微信 VoIP 必须使用云代理模式 |
modelId 与 IoT 后台一致 | 不一致则 requestDeviceVoIP 报错 |
| SN Ticket 由服务端签发 | 不直接在客户端调微信 getsnticket |
cancelVoip 事件仅未接通时触发 | 已接通后的挂断由插件内部处理 |
| payload 透传 | 自定义字段经微信→服务端→设备全程透传,建议约定 wxa_from 和 call_id |
wx_app_id 可选 | 上述业务服务端接口均可传 wx_app_id;不传则服务端使用默认 AppID。多小程序时建议传入 |