强制结束通话
参数
String roomId
可选。2.3.2 开始支持。
- 不传入时,挂断当前正在进行的通话;
- 传入时,仅在当前通话 roomId 与传入相同时,挂断当前正在进行的通话。(建议)
返回值
无
示例代码
const wmpfVoip = requirePlugin('wmpf-voip').default
wmpfVoip.forceHangUpVoip('some group id')
强制结束通话
可选。2.3.2 开始支持。
无
const wmpfVoip = requirePlugin('wmpf-voip').default
wmpfVoip.forceHangUpVoip('some group id')
本接口为异步接口,返回
Promise对象。需插件 2.4.0 版本开始支持
从手机客户端的微信小程序呼叫 Linux 设备、RTOS 设备。调用此接口后,会创建 VoIP 房间。开发者应自行向设备端推送通话提醒。详情参考《手机微信呼叫设备(Linux 直连)》。
本接口只能在微信客户端内使用,不可在 WMPF 内使用。建议先阅读接口介绍。
| 属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
|---|---|---|---|---|---|
| roomType | string | 是 | 通话类型。voice: 音频通话;video: 视频通话 | ||
| sn | string | 是 | 接听方设备 SN | ||
| modelId | string | 是 | 接听方设备 modelId | ||
| chargeType | string | ‘license’ | 否 | 计费方式。duration: 时长计费;license:license 计费 | |
| timeLimit | number | 否 | 最大通话时长,需为 > 0 的数字 | ||
| enableCallerCamera | boolean | true | 否 | 拨打方是否启用摄像头 | |
| enableListenerCamera | boolean | true | 否 | 接听方是否启用摄像头 | |
| nickName | string | 否 | 设备端显示的微信用户名称,仅记录 | ||
| deviceName | string | 否 | 微信端显示的设备名称 | 2.4.1 | |
| isCloud | boolean | false | 否 | 如果是呼叫 RTOS 设备,设置为 true 以触发消息回调 | |
| payload | string | 否 | 呼叫 RTOS 时,可以带 payload 到回调消息中 | ||
| encodeVideoFixedLength | number | 0 | 否 | 编码的长边值,可取 320、480、640 | |
| encodeVideoRotation | number | 0 | 否 | 编码的视频旋转方向。1: 发出正向流. 2: 保持发出旋转流 | |
| encodeVideoRatio | number | 0 | 否 | 视频的比例, 宽/高*100 | |
| encodeVideoMaxFPS | number | 0 | 否 | 视频的最大 FPS, 8-15 |
本接口调用失败会抛出异常。
接口调用成功时,返回如下:
| 属性 | 类型 | 说明 | 最低版本 |
|---|---|---|---|
| roomId | string | 本次通话的房间号 |
const wmpfVoip = requirePlugin('wmpf-voip').default
try {
const { roomId } = await wmpfVoip.callDevice({
roomType: 'video',
sn: '设备 SN',
modelId: '设备 modelId',
nickName: '设备端显示的微信用户名称',
})
if (/* 当前不在插件页面 */) {
wx.redirectTo({
url: wmpfVoip.CALL_PAGE_PATH,
})
}
} catch (e) {
console.error('callDevice failed:', e)
wx.showToast({
title: '呼叫失败',
icon: 'error',
})
}
本接口为异步接口,返回
Promise对象。需插件 2.4.0 版本开始支持
从手机客户端的微信小程序呼叫运行安卓 WMPF 的设备。调用此接口后,会创建 VoIP 房间,并且向设备推送 WMPF pushMsg 提醒。详情参考《手机微信呼叫设备(安卓)》。
本接口只能在微信客户端内使用,不可在 WMPF 内使用。建议先阅读接口介绍。
| 属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
|---|---|---|---|---|---|
| roomType | string | 是 | 通话类型。voice: 音频通话;video: 视频通话 | ||
| sn | string | 是 | 接听方设备 SN | ||
| modelId | string | 是 | 接听方设备 modelId | ||
| pushToken | string | 是 | 从设备获取的 pushToken | ||
| nickName | string | 是 | 设备端显示的微信用户名称 | ||
| deviceName | string | 否 | 微信端显示的设备名称 | 2.4.1 | |
| chargeType | string | ‘license’ | 否 | 计费方式。duration: 时长计费;license:license 计费 | |
| timeLimit | number | 否 | 最大通话时长,需为 > 0 的数字 | ||
| enableCallerCamera | boolean | true | 否 | 拨打方是否启用摄像头。 | |
| enableListenerCamera | boolean | true | 否 | 接听方是否启用摄像头。 | |
| envVersion | string | ‘release’ | 否 | 接听方打开的微信小程序类型。 取值:release: 正式版; trial: 体验版; develop: 开发版。 正式版微信小程序只能拨打给正式版,设置这一字段无效。 | |
| customQuery | string | 否 | 接听方打开微信小程序时,会作为 query 拼接到插件页面路径后,格式如 a=1&b=2。可在接听端微信小程序内通过 getPluginOnloadOptions 或 getPluginEnterOptions 接口获取到 |
本接口调用失败会抛出异常。
接口调用成功时,返回如下:
| 属性 | 类型 | 说明 | 最低版本 |
|---|---|---|---|
| roomId | string | 本次通话的房间号 |
const wmpfVoip = requirePlugin('wmpf-voip').default
try {
const { roomId } = await wmpfVoip.callWMPF({
roomType: 'video',
sn: '设备 SN',
modelId: '设备 modelId',
nickName: '设备端显示的微信用户名称',
pushToken: 'xxxx*****xxxx',
})
if (/* 当前不在插件页面 */) {
wx.redirectTo({
url: wmpfVoip.CALL_PAGE_PATH,
})
}
} catch (e) {
console.error('callWMPF failed:', e)
wx.showToast({
title: '呼叫失败',
icon: 'error',
})
}
插件提供设备端和微信用户直接通话的能力。
开发者请根据场景选择不同的通话接口。
使用 initByCaller 接口,businessType 传 1。
Linux 设备不运行微信小程序插件,请使用微信小程序音视频通话 SDK (Linux 设备)。
callWMPF 接口。需插件 2.4.0 开始支持。若使用 license 计费,必须使用本接口。initByCaller 接口,businessType 传 2。此方式不支持 license 计费。使用 callDevice 接口。需插件 2.4.0 开始支持。
请注意:呼叫 Linux 设备时,微信不进行消息推送,需要开发者自行将设备端加入房间所需参数(如 roomId 等)从微信端推送到设备端。
发起通话的几个接口既可以在微信小程序页面调用,也可以在插件页面调用。但是最终通话流程必须在插件页面才能进行。
// 发起通话成功后,仅在当前不是插件页面的情况下需进行跳转。
wx.redirectTo({
// 此处只需要传入 path 即可,如果开发者有其他参数需要传递给<a href="https://weixin-xiaochengxu-kaifa.yuannext.com">微信小程序</a>,也可以自行拼接 query,并通过插件 getPluginOnloadOptions 接口获取。
url: wmpfVoip.CALL_PAGE_PATH,
// 插件 2.3.9 开始支持 CALL_PAGE_PATH, 低版本请传入 'plugin-private://wxf830863afde621eb/pages/call-page-plugin/call-page-plugin',
})
为了降低开发者的开发成本,插件提供了限制最大通话时长的能力。最大通话时长应为 > 0 的数字。
通话时长从 startVoip 事件开始计时,超时后通话自动结束并弹 toast 提示用户,同时触发 hangUpVoip 事件,origin 为 'timeLimit'。
在插件 2.4.0 以下版本中,通话房间 ID 被称为 groupId,这个名字比较容易与设备组的 ID 产生混淆,因此从 2.4.0 开始,房间号统一更名为 roomId,但为保持向下兼容,groupId 参数仍予以保留。
二者除名字不同外,无其他差异。
本接口为异步接口,返回
Promise对象。
发起通话并获取通话房间号。调用此接口后,会创建 VoIP 房间,并且向接听方推送接听提醒。
建议先阅读接口介绍。
| 属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
|---|---|---|---|---|---|
| roomType | string | 是 | 通话类型。voice: 音频通话;video: 视频通话 | ||
| caller | Object | 是 | 拨打方信息 | ||
| caller.id | string | 是 | 拨打方 id,参考 businessType 的说明 | ||
| caller.name | string | 否 | 显示的拨打方名字。设备端发起通话时无效 | ||
| caller.cameraStatus | number | 0 | 否 | 是否启用摄像头。0: 开启;1: 关闭 | |
| listener | Object | 是 | 接听方信息 | ||
| listener.id | string | 是 | 接听方 id,参考 businessType 的说明 | ||
| listener.name | string | 否 | 显示的接听方名字。 | ||
| listener.cameraStatus | number | 0 | 否 | 是否启用摄像头。0: 开启;1: 关闭 | |
| businessType | number | 0 | 否 | 业务类型。详见 businessType 的说明 | |
| voipToken | string | 否 | 拨打票据,部分情况下必填,参考 businessType 的说明 | ||
| miniprogramState | string | formal | 否 | 接听方点击通知时打开的微信小程序类型。 取值:formal: 正式版; trial: 体验版; developer: 开发版。 2.1.8 起,正式版微信小程序只能拨打给正式版,设置这一字段无效。 | |
| customQuery | string | 否 | 接听方点击通知打开微信小程序时,会作为 query 拼接到插件页面路径后,格式如 a=1&b=2。可在接听端微信小程序内通过 getPluginOnloadOptions 或 getPluginEnterOptions 接口获取到 | ||
| timeLimit | number | 否 | 最大通话时长,需为 > 0 的数字 | 2.3.8 |
由于历史原因,本接口调用失败可能会抛出异常(一般是参数错误),也可能会返回 isSuccess: false(一般是后台错误)。
接口成功返回后,仍需要使用 isSuccess 字段判断调用是否最终成功。
接口调用成功时,返回如下
| 属性 | 类型 | 说明 | 最低版本 |
|---|---|---|---|
| isSuccess | boolean | 是否调用成功,此时为 true | |
| roomId | string | 本次通话的房间号 | 2.4.0 |
| groupId | string | 与 roomId 相同 | |
| chargeType | string | 计费方式。取值:duration: 时长计费;license: license 计费 | 2.3.8 |
调用失败时,接口返回如下:
| 属性 | 类型 | 说明 | 最低版本 |
|---|---|---|---|
| isSuccess | boolean | 是否调用成功,此时为 false | |
| object | 错误对象,已废弃。{ err_code: string, errMsg: string } | ||
| errCode | number | 错误码,取值参考错误码文档 | |
| errMsg | string | 错误信息 | |
| errObj | VoipError | 错误对象 | 2.4.0 |
不同 businessType 对应的部分参数含义不同,参数获取的具体方式请参考对应业务的文档。
| businessType | 业务类型 | caller.id | listener.id | voipToken |
|---|---|---|---|---|
| 1 | 硬件设备呼叫手机微信 | 设备 SN | 微信用户 openId | 使用设备认证 SDK注册的设备传入 deviceToken. 使用 WMPF 注册的设备不能有这个字段(插件 2.3.0 支持) |
| 2 | 手机微信呼叫硬件设备 | 微信用户 openId | 设备 SN | 从设备获取的 pushToken |
businessType=2 仅支持安卓 WMPF,呼叫 Linux 设备请使用 callDevice。businessType=2 不支持 license 计费,手机微信呼叫安卓 WMPF 建议使用 callWMPF。const wmpfVoip = requirePlugin('wmpf-voip').default
try {
const { isSuccess } = await wmpfVoip.initByCaller({
caller: {
id: '拨打方 Id',
name: '拨打方名字',
},
listener: {
id: '接听方 Id',
name: '接听方名字',
},
roomType: 'video',
businessType: 1,
voipToken: 'xxxx*****xxxx',
miniprogramState: 'developer', // 开发阶段建议使用开发版
})
if (isSuccess /* && 当前不在插件页面 */) {
wx.redirectTo({
url: wmpfVoip.CALL_PAGE_PATH,
})
} else {
wx.showToast({
title: '呼叫失败',
icon: 'error',
})
}
} catch (e) {
wx.showToast({
title: '呼叫失败',
icon: 'error',
})
}
本插件主要用于提供「微信小程序音视频通话(for 硬件)」的部分基础能力和统一的通话界面。完整的接入流程和开发指南请参考相关文档。
插件接入可参考:微信小程序示例代码
关于微信小程序插件详细说明请参考微信小程序使用插件文档
在「微信小程序管理后台」添加插件后,使用者还需要在微信小程序的 app.json 中声明本插件。可以在主包引入,也可以在分包引入。
// 主包引入
{
"plugins": {
"wmpf-voip": {
"version": "latest", // latest 表示自动使用最新版本。也可使用具体版本,如 2.3.8
"provider": "wxf830863afde621eb"
}
}
}
// 分包引入
{
"subpackages": [
{
"root": "xxxx",
"pages": [],
"plugins": {
"wmpf-voip": {
"version": "latest", // latest 表示自动使用最新版本。也可使用具体版本,如 2.3.8
"provider": "wxf830863afde621eb"
}
}
}
]
}
完成声明后,可以在微信小程序中来确认是否引入成功
const wmpfVoip = requirePlugin('wmpf-voip').default
console.log(wmpfVoip) // 有结果即表示引入插件成功
从功能上,插件提供的接口可以分为以下几类
发起通话的过程中,插件主要负责通话房间创建、发送接听提醒和通话页面的展示。可以在微信小程序页面或插件页面调用initByCaller 发起通话。
通常情况下,通话结束需要用户点击操作。某些场景下,微信小程序也可以调用 forceHangUpVoip 主动结束当前通话。
非用户点击结束通话可能有以下场景:
initByCaller 的 timeLimit 参数。插件低版本也可以根据 calling 事件的 keepTime 字段计算通话时长。开发者可以通过 onVoipEvent 绑定通话事件的监听,以便更好地分析通话过程。
插件提供下列接口对通话过程和界面进行设置
setCustomBtnText:自定义接听页面按钮。setVoipEndPagePath:设置插件功能执行完成后的跳转页面路径。setUIConfig:设置插件通话界面。在微信客户端内,可以使用wx.getDeviceVoIPList查询当前登录的用户同意或拒绝授权了哪些设备。
在硬件端,可以通过插件getIotBindContactList接口查询用户是否授权某台设备。
推荐开发者在微信用户授权设备时,即 wx.requestDeviceVoIP 回调 success 后,在后台存储 SN 与 openId。在设备端联系人页面中,配合 getIotBindContactList 接口进行授权验证。
微信小程序可以通过插件getPluginEnterOptions获取从插件页面进入微信小程序时的启动参数。
如果微信小程序在前台时进入插件页面,则需要使用getPluginOnloadOptions获取插件通话页面 onLoad 时页面路径中的参数。
请参考《微信小程序音视频通话插件更新日志》
接入流程和常见问题也可参考微信小程序音视频通话(for 硬件) 使用手册
借助微信小程序音视频通话插件,硬件开发者可以通过微信小程序硬件框架(WMPF)、Linux SDK 接入、云云接入三种方式实现智能设备和手机微信端的一对一音视频通话,满足实时触达场景,提升通话体验。
下图为手机端的示意图,授权弹窗、通话提醒、通话界面为微信提供的统一界面,硬件微信小程序接入微信 VOIP 通话插件后,可实现上述功能。

适用于校园话机、门禁机、智能门锁、智慧中控屏、智能电视、智能摄像头、智能音箱、智慧养老等多种设备和场景,支持硬件设备和手机端双向通话,实现通话强提醒。
借助微信小程序音视频通话插件里的摄像头能力,开发者能够快速的将摄像头类产品接入微信小程序生态(云对云的方式),用户查看摄像头流媒体也更加方便,培养用户微信小程序观看摄像头的习惯。
针对摄像头涉及的功能,分成组件必选、组件可选、自定义等部分。
| 类型 | 模块 | 功能点 | 描述 |
|---|---|---|---|
| 组件必选 | 播放器 | 播放 | 播放、暂停 |
| 组件必选 | 播放器 | 画面缩放 | 放大、缩小 |
| 组件必选 | 播放器 | 音量 | 音量、静音 |
| 组件必选 | 播放器 | 屏幕 | 小屏、全屏 |
| 组件必选 | 对讲 | 设备呼叫手机 | VoIP功能 |
| 组件可选 | 播放器 | 清晰度 | 开发者传入 |
| 组件可选 | 对讲 | 手机呼叫设备 | 呼叫、挂断 |
| 自定义(举例) | 轮盘 | 方向控制 | 一般用来控制摄像头转动 |
| 自定义(举例) | 增值服务 | 云存储 | |
| 自定义(举例) | 增值服务 | AI服务 |
微信小程序界面:

全屏界面:

目前支持安卓系统、Linux 系统、RTOS 系统的设备。每台设备只能绑定一个微信小程序,只能和一个微信小程序进行通话。
目前支持 「设备直连」和「云对云」 两种接入模式:
安卓系统设备端运行微信小程序硬件框架(WMPF),WMPF 内运行开发者微信小程序,直接与用户手机微信内的微信小程序进行通话;
设备应满足下列基本要求:
Linux 系统设备端调用 微信小程序音视频通话 SDK (Linux),直接与用户手机微信内的微信小程序进行通话。
设备应满足下列基本要求:
目前支持部分低功耗 Linux、RTOS 等系统的设备。设备端进行设备验证,经由开发者后台中转,与用户手机微信内的微信小程序进行通话。
设备应满足下列基本要求:
以下几个环节可以同时进行,涉及到多个平台侧的审核流程,请提前预留时间。
注册微信终端合作平台和微信开放平台账号、登记设备信息等环节均涉及平台审核,请提早准备。
参考文档指引,完成「微信终端合作平台 (wecooper)」企业主体账号注册、移动应用绑定和硬件注册的流程。
本步骤主要是将设备接入微信的设备体系,完成设备与 APP,以及 APP 与微信小程序之间的关联。
此环节涉及平台审核,请提早准备。
微信小程序想要使用音视频通话能力能力,需要在微信小程序管理平台申请开通「微信小程序音视频能力」设备能力。详见「设备接入」文档和微信小程序音视频通话(for 硬件) 使用手册中的流程指引,并关注《硬件 VoIP 审核验证要求》。
完成接入后,开发者可获得由平台分配的 model_id。model_id 对应一种设备类型,是调用微信小程序设备能力相关接口的重要凭证。
获取 model_id 后,开发者可以调用获取设备票据接口获取 snTicket,用于后续的设备验证流程。
微信小程序音视频通话的主要功能通过「VOIP 通话」这一微信小程序插件(appId: wxf830863afde621eb)提供。
在微信小程序管理后台完成「微信小程序音视频能力」申请并通过后,微信小程序可以直接使用 VOIP 通话插件,无需额外申请。
如果开发者想要提前进行调试,可以手动进行申请:登录「微信小程序管理后台」——「设置」——「第三方设置」——「插件管理」,点击「添加插件」,搜索并添加「VOIP 通话」插件。
开发者需要开发(或使用现有)微信小程序,接入「VOIP 通话」插件,实现拨打和接听音视频通话的能力。
至少使用微信客户端 8.0.30 及以上版本,建议使用当前最新版本。
微信小程序开发主要有以下环节,请参考各环节的文档:
通话相关异常,请参考《通话异常排查指南》
VoIP 通话流程暂不支持在微信开发者工具进行调试,请使用真机进行。
安卓设备端可指定使用「开发版/体验版微信小程序」进行调试。请参考《开发设备端应用(安卓)》「3.2 运行开发版/体验版微信小程序」。
接听方收到消息推送点击接听后,默认打开的是正式版的微信小程序。
在开发阶段,建议在调用 wmpfVoip.initByCaller 时额外传入 miniprogramState 参数指定打开开发版/体验版微信小程序。
const result = await wmpfVoip.initByCaller({
// 其他参数省略
miniprogramState: 'developer', // formal/正式版(默认);trial/体验版;developer/开发版
})
使用微信小程序音视频通话 SDK (Linux)时,可以在初始化时设置 wxa_flavor 指定使用开发版/体验版接听通话。
注意:
wx.getAccountInfoSync 接口判断当前的微信小程序版本。RTOS 设备使用云对云方案时,需要进行服务端开发。设备直连(Linux、Android)无需服务端开发。
请参考《常见问题(FAQ)》
微信小程序框架已适配手表穿戴类设备,可针对 RTOS(实时操作系统)等低功耗设备场景,实现最小可用的微信小程序运行。
由于市场主流穿戴设备的 CPU 性能和内存大小十分有限(整机内存小于 8M),我们针对性实现了最小可用的微信小程序框架,提供:
穿戴设备的硬件资源十分有限。为减小存储占用,该微信小程序框架只提供普通微信小程序的功能子集,请开发者严格按照本文档提供的特性列表实现微信小程序。由于接口能力的差异较大,一般需要开发者针对穿戴设备单独开发新的微信小程序。
可以使用微信小程序中 Page、Component能力。支持完整的 WXML、WXSS 语法。
可以在微信小程序中使用 App、getApp、Page、getCurrentPages、Component。支持 ES6 import / export 与 CommonJS require 两种 JS 模块加载机制。
使用微信小程序组件框架时应注意下列差异:
wx://component-export。以下能力暂未支持
Chaining API
behavior
WXS
暂不支持自定义组件的下列方法:
目前仅支持下列内置组件
属性:无
属性:
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| src | string | 否 | 图片资源地址。如果使用代码包内图片资源,src需为绝对路径。 |
说明:
属性:无
穿戴设备微信小程序框架的专属组件,能够根据输入的文本生成并渲染二维码。
考虑到资源消耗,穿戴设备不建议使用图片展示二维码。
对于需要展示微信小程序码的情况,可以参考扫普通链接二维码打开微信小程序
。
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| value | string | 否 | “” | 二维码文本内容 |
| light-color | HexColor | 否 | #000000 | 二维码颜色 |
| dark-color | HexColor | 否 | #FFFFFF | 二维码背景颜色 |
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| enable-flex | boolean | false | 否 | 启用 flexbox 布局。开启后,当前节点声明了 display: flex 就会成为 flex container,并作用于其孩子节点。 |
swiper 支持属性:
| 属性 | 类型 | 默认值 | 必填 | 说明 |
|---|---|---|---|---|
| current | number | 0 | 否 | 当前所在滑块的 index |
| bind:change | eventhandle | 否 | current 改变时会触发 change 事件,event.detail = {current, source} |
不支持子元素选择器、后代选择器、接续兄弟选择器、后续兄弟选择器,若有相关开发需求,请通过普通选择器实现。
注意:WXML支持内联样式,但不支持binding(不可以通过setData()修改WXML组件的style属性值)。
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
| entryPagePath | string | 否 | 微信小程序默认启动首页 |
| pages | string[] | 是 | 页面路径列表 |
| networkTimeout | Object | 否 | 网络超时时间 |
| window | Object | 否 | 全局的默认窗口表现 |
| usingComponents | Object | 否 | 全局自定义组件配置 |
用于设置微信小程序的状态栏、导航条、标题、窗口背景色。穿戴设备微信小程序框架只支持设置窗口背景色。
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| backgroundColor | HexColor | 否 | #FFFFFF | 窗口的背景色 |
各类网络请求的超时时间,单位均为毫秒。穿戴设备微信小程序框架只支持设置request的超时时间。
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| request | number | 否 | 60_000 | wx.request 的超时时间,单位:毫秒。 |
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
| component | boolean | 否 | 一个自定义组件由 json、wxml、wxss、js 4个文件组成。如设置component为true,将声明这一组文件为自定义组件 |
| styleIsolation | string | 否 | 样式隔离 |
| usingComponents | Object | 否 | 全局自定义组件配置 |
| 值 | 说明 |
|---|---|
| isolated | 启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值) |
| apply-shared | 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面 |
| shared | 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。 |
每一个微信小程序页面可以使用同名.json文件来对本页面的窗口表现进行配置,页面中配置项会覆盖 app.json 的 window 中相同的配置项。
| 属性 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| backgroundColor | HexColor | 否 | #FFFFFF | 窗口的背景色 |
wx.getWindowInfo 新增返回值
| 属性 | 类型 | 说明 |
|---|---|---|
| screenShape | string | rect: 方形屏幕;round 圆形屏幕 |
wx.getDeviceInfo 新增返回值
| 属性 | 类型 | 说明 |
|---|---|---|
| deviceType | string | 可选值:watch, phone, tv, vehicle, pc |
注意:
本框架不提供wx.getSystemInfo系列接口,请使用getWindowInfo/getDeviceInfo代替。
wx.request()
注意
注意:暂未提供tabBar
注意
注意:暂无 navigationBar、tabBar、homeButton
其中事件对象仅支持 type, target, currentTarget 字段,target/currentTarget 仅支持 dataset 字段。
前置条件:名下需有普通微信小程序的AppID,并作为该微信小程序的管理员。
步骤:
装好插件后,将开发模式切换到「低功耗硬件微信小程序模式」
点击「详情」,确保其中设置的AppID与微信开发者平台一致。
我们不建议开发者将JS代码编译为ES5。穿戴设备微信小程序框架支持ES2023,减少不必要的polyfill有助于显著节省最终微信小程序代码包体积,进而节省运行时内存占用。
完成开发后,可在「微信开发者工具」中点击「上传」。新上传的版本将覆盖旧的「开发版微信小程序」。
开发者可以前往微信开发者平台,管理微信小程序版本、提交审核、发布上线。
有合作意向的硬件厂商、微信小程序开发者,欢迎发送邮件联系我们:wx_iot@tencent.com。
设备身份是微信 VOIP 业务能够正常运行的基础,开发者在接入 VOIP 业务时,会通过如下两个流程来进行身份的确定:
对于没有 TEE 的机器,我们要求设备系统里能够操作 EMMC 存储的 RPMB 区域,并且需要将 RPMB 的归属权给到 VOIP 业务,VOIP 在设备注册时会将与设备对应的唯一密钥写入存储的 KEY 区域,用来做身份校验。
而对于有 TEE 的机器,我们信赖 TEE 的结果,但需要 TEE 里按照规范完成 TA 的开发。
不管是 optee,还是 trusty 或 qsee 等,TEE 的使用流程通常如下:
打开 TEE 环境 > 开启一个会话 > 发送命令 > 获取信息 > 结束会话 > 关闭 TEE 环境
这里我们需要定义如下标准:
设备开发者需要根据规范进行如下开发:
TA 在逻辑上将存储分为两个区域。需要注意的是,这些数据最终应都存在于 EMMC 或 UFS 的 rpmb 分区,或其它 REE 访问不到的安全器件区域。
TA 的名称统一为 ta_devauth
定义三个命令,分别是读数据、写数据、写密钥。
#define TA_DEVAUTH_CMD_READ 0x10
#define TA_DEVAUTH_CMD_WRITE 0x11
#define TA_DEVAUTH_CMD_PROKEY 0x12
详细说明:
| 命令 | TA_DEVAUTH_CMD_READ 0x10 |
| 功能 | 读 1 个 Block 的数据 |
| 参数 | 输入:Block 地址 输入/输出:Block 数据 BUFFER,284字节,见 2.3 数据定义。 输出:签名 BUFFER,=32字节 |
| 返回 | 0:成功读取,并返回 284 字节数据和 32 字节签名 -1:参数错误。 -2:地址越界。 -3:密钥区还没被写。 -5:其它错误。 |
| 特别说明 | 若密钥区还没被写(例如裸数据全是0x00,或没有TEE文件系统里的文件?),这种情况认为是一台全新的未激活设备,需要读取错误返回 -3。 |
| 命令 | TA_DEVAUTH_CMD_WRITE 0x11 |
| 功能 | 写 1 个 Block 的数据 |
| 参数 | 输入:Block 地址 输入:Block 数据 BUFFER,=284字节,见 2.3 数据定义。 输入:对应的签名 BUFFER,=32字节 |
| 返回 | 0:写入成功。 -1:参数错误。 -2:地址越界。 -3:密钥区还没被写。 -4:签名错误。 -5:其它错误。 |
| 特别说明 | 若密钥区还没被写(例如裸数据全是0x00,或没有TEE文件系统里的文件?),这种情况认为是一台全新的未激活设备,需要返回 -3。 此功能在写数据前,需要计算数据对应的签名,并且与参数传入的签名比对,若比对不成功返回 -4 |
| 命令 | TA_DEVAUTH_CMD_PROKEY 0x12 |
| 功能 | 写密钥 |
| 参数 | 密钥 BUFFER,=32字节 |
| 返回 | 0:写入成功。 -1:参数错误。 -3:密钥区已有数据。 -5:其它错误。 |
| 特别说明 | 若密钥区已有数据(例如裸数据不为0x00,或有文件?),则需要返回 -3。 |
与 TA 交互时传入传出 Buffer 的大小为 284 字节,它的定义如下:
struct ta_data {
uint8_t data[256]; // 此 256 字节是 TA 写入到1个Block的内容
uint8_t nonce[16]; // 一般为随机字节,传入与传出的一定要一致。
uint32_t reserve1;
uint16_t reserve2;
uint16_t reserve3;
uint16_t reserve4;
uint16_t reserve5;
};
// sizeof(struct ta_data) = 284
签名 Buffer 大小为 32 字节。
CA 与 TA 交互消息定义:
struct ta_message {
uint32_t cmd; // 命令号
uint32_t block; // 读写地址
struct ta_data data; // 284 字节数据
uint8_t key[32]; // 32 字节 Key
uint8_t hmac[32]; // 32 字节 hmac
int ret; // 返回值
};
CA 侧参考伪代码:
static int tee_send_cmd_req(struct ta_message* ta_msg) {
int rc = 0;
if (ca_handle == 0) {
printf("not connected\n");
return -EINVAL;
}
if (tee_send_msg(ca_handle, ta_msg) < 0) {
return -1;
}
if (tee_resp_msg(ca_handle, ta_msg) < 0) {
return -1;
}
return 0;
}
数据签名的算法为 HMAC_SHA256。
读数据时,TA 的流程:
写数据时,TA 的流程:
写密钥时,TA 的流程:
一个签名的数据示例,开发者可以此为基准来验证自己的 hmac_sha256:
char *key = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHH";
uint8_t buffer[284] = {0};
int main(int argc, char **argv) {
uint8_t hmac[32] = {0};
memset(buffer, 0x55, 284);
hmac_sha256(key, 32,
buffer, 284,
hmac, sizeof(hmac)
);
for (int i=0; i < 32; i++) {
printf("%02x ", hmac[i]);
}
return 0;
}
// 以上代码输出:
// 61 16 67 22 a0 93 66 74 bb 75 f8 87 0e 5e d4 59 2c d6 99 c0 14 a6 93 70 bd ff ea 3e 8e 84 52 4e
hmac_sha256 为标准算法,一般 tee 里已有此类算法,如果没有,可参考开源实现。
按照 HAL 规范完成 HAL 的开发,HAL 里使用 CA 代码与 TA 进行交互,完成 TEE 的使用。
HAL 路径:android/hardware/interface/devauth
types.hal
package android.hardware.devauth@1.0;
enum TA_CMD : uint32_t {
TA_DEVAUTH_CMD_READ = 0x10,
TA_DEVAUTH_CMD_WRITE = 0x11,
TA_DEVAUTH_CMD_PROKEY = 0x12,
};
struct ta_data {
uint8_t[256] data; // 此 256 字节是 TA 写入到1个Block的内容
uint8_t[16] nonce; // 一般为随机字节,传入与传出的一定要一致。
uint32_t reserve1;
uint16_t reserve2;
uint16_t reserve3;
uint16_t reserve4;
uint16_t reserve5;
};
struct ta_message {
uint32_t cmd; // 命令号
uint32_t block; // 读写地址
ta_data data; // 284 字节数据
uint8_t[32] key; // 32 字节 Key
HMacBuffer hmac; // 32 字节 hmac
int8_t ret; // 返回值
};
typedef uint8_t[32] HMacBuffer;
typedef uint8_t[32] ProKeyBuffer;
typedef ta_data ta_data_t;
typedef ta_message ta_message_t;
IDevauth.hal
package android.hardware.devauth@1.0;
interface IDevauth {
/**
* 读 Block 数据
*
* @param addr: Block 地址
* @param data: 输入的 struct ta_data
* @return retval: 返回值,返回值说明请见规范
* @return data: 返回的 struct ta_data,284 字节。
* @return hmac: 返回的签名, 32 字节。
*
*/
read_block(uint16_t addr, ta_data data) generates (int8_t retval, vec<uint8_t> data, vec<uint8_t> hmac);
/**
* 写 Block 数据
*
* @param addr: Block 地址
* @param data: 输入输出数据,对应规范里的 struct ta_data,284 字节。
* @param hmac: HAL 写数据时用的签名, 32 字节
*
* @return retval: 返回值说明请见规范
*/
write_block(uint16_t addr, ta_data data, HMacBuffer hmac) generates (int8_t retval);
/**
* 写 Key
*
* @param key: 32 字节key
*
* @return retval: 返回值说明请见规范
*/
program_key(ProKeyBuffer key) generates(int8_t retval);
};
hardware/interfaces/devauth/1.0/ 下放置 IDevauth.hal、types.hal,内容如上。
然后使用如下方式来生成代码:
LOC=hardware/interfaces/devauth/1.0/default
PACKAGE=android.hardware.devauth@1.0
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport ${PACKAGE}
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport ${PACKAGE}
./hardware/interfaces/update-makefiles.sh
此时 hal 目录应该如下:
root~/android> tree hardware/interfaces/devauth/
hardware/interfaces/devauth/
└── 1.0
├── Android.bp
├── default
│ ├── Android.bp
│ ├── Devauth.cpp
│ └── Devauth.h
├── IDevauth.hal
└── types.hal
2 directories, 6 files
再按照 HAL 接口定义,在相应的接口函数里完成 CA 代码的开发即可。
开发者完成 TEE 的 TA 开发后,应该进行测试用例开发,以验证 TA 的功能与逻辑。 前置条件:ta_deauth 所管理的区域无任何数据,再按顺序进行以下测试项。
可在官方测试用例代码的基础上,加上自己的 CA 实现,以快速验证 TA。
开发者完成 HAL 开发后,可用测试用例进行测试,
也可以直接下载已编译好的 tee_hal_test 进行测试,测试方法如下
tee_hal_test a 进行一次全新的测试,需要一个 ta_devauth 所管理的区域无任何数据。tee_hal_test 不带任何参数,可在 1. 后运行。4.2 中的测试用例通过后,下载 rpmbd_tee 并集成到系统中以服务方式运行起来即可,参考:
service rpmbd_tee /system/bin/rpmbd_tee
class main
user root
group root system
注意:License 计费不再支持使用设备认证 SDK 认证的设备,请尽快切换到使用 WMPF 认证设备,无需维护 deviceToken,接入更便捷。
在系统集成 rpmbd 后,开发者需要在 Launcher 应用中接入设备认证 SDK,SDK 主要提供以下能力:
registerDevice:将 model_id 和 SN 与设备绑定。一旦成功后 model_id 和 SN 不可修改。getDeviceToken:进行设备认证并从微信后台获取凭证,设备端发起通话时传给 VOIP 通话插件的 initByCaller 接口的 voipToken 参数。请在 此处 下载 SDK 的 aar 文件。
建议使用 1.3 及以上版本(物联网卡应使用 1.3.1 及以上版本)。低版本不支持并发调用 registerVoipDevice,请务必注意在前一次调用返回前不要重复调用。
voipsdk-x.x-release.aar和 safeguard-release.aar 两个 aar 文件voipsdk-x.x-release.aar注意:使用设备认证 SDK 前,需先保证 rmpbd 服务正常运行。
registerDevice将 model_id 和 SN 与设备绑定,一旦成功后 appid、model_id、SN 均不能更换。
int registerDevice(String appid, String model_id, String sn, String sn_ticket) throws Exception
cert fail),可以清理 APK 的数据再以相同的 appid、model_id、SN调用接口重新申请即可。| 参数 | 类型 | 说明 |
|---|---|---|
| appid | String | 微信小程序的 appid |
| model_id | String | 设备接入时从「微信小程序管理后台」申请获得的 model_id |
| sn | String | 设备序列号。厂商自己生成,长度不能超过 128 字节。字符只接受数字,大小写字母,下划线(*)和连字符(-)。 此处使用的 sn 必须与 WMPF 激活设备使用的 deviceId 一致 |
| sn_ticket | String | 通过获取设备票据接口获得 |
其他异常说明请参考设备验证常见问题
| 名称 | 值 | 描述 |
|---|---|---|
| OK | 0 | 成功 |
| ERR_ARGS | -1 | 参数错误 |
| ERR_IO | -2 | 通用 IO 错误 |
| ERR_KEY_IO | -3 | KEY 不匹配 |
| ERR_RESPONSE | -4 | 网络请求无回复 |
| ERR_PEM | -5 | 权限错误 |
| ERR_INVALID_KEY | -6 | KEY 不可用 |
| ERR_SERVICE | -7 | rpmbd 服务没运行 |
| ERR_EMMC_UFS_CONFUSED | -8 | EMMC/UFS 不匹配。里面已经存在 SN |
| ERR_EMMC_UFS_IO | -9 | EMMC/UFS IO 错误 |
| ERR_REG_NOPEM | -10 | 密钥不存在 |
getDeviceToken进行设备认证,并从微信后台获取设备凭证。设备发起通话时需要将这一凭证传给 VOIP 通话插件的 initByCaller 接口的 voipToken 参数。
String getDeviceToken(String appid, String model_id) throws Exception
如果设备是使用 v1.5 及以上版本 SDK 进行注册设备的,可以使用无参数的版本。
String getDeviceToken() throws Exception
| 参数 | 类型 | 说明 |
|---|---|---|
| appid | String | 微信小程序的 appid |
| model_id | String | 设备接入时从「微信小程序管理后台」申请获得的 model_id |
getDeviceSn(仅调试用)获取 registerDevice 接口写入的 SN。
String getDeviceSn()
getDeviceModelid(仅调试用)获取使用 registerDevice 接口写入的 modelId。仅在设备是使用 v1.5 及以上版本 SDK 进行注册设备时有效。
String getDeviceModelid()
initSDK 初始化,其它接口在调用之前需要保证 init 成功。
boolean init()
registerVoipDevice参考 2.1 registerDevice。
getCallerTicket参考 2.2 getDeviceToken
GetDeviceSn(仅调试用)同 2.3 getDeviceSn