订阅消息语音提醒

从基础库 2.18.0 开始支持

当前微信小程序订阅消息通知与微信消息的通知的提示音是一样的,对于部分订阅消息模板,增加了语音提醒能力,播报语料中的部分字段支持开发者自定义。

当开发者调用wx.requestSubscribeMessage时,如果只订阅了1条消息,并且该模板支持开启语音提醒,用户在订阅时可以选择开启语音提醒。开启后,在接收订阅消息时会同步播报语音提醒。

当用户开启了语音提醒,开发者通过wx.getSetting获取该模板的订阅状态时,会显示为’acceptWithAudio’。

订阅弹窗的样式如下:

intro

当前支持开启语音提醒的模板及播报语料如下:

标题 类型 类目 播报语料
收款到账通知 长期订阅 金融业-银行、金融业-收单商户服务 微信小程序示例收款10元,其中“微信小程序示例”会播报为下发微信小程序的微信小程序简称,10会播报为模板中的收款金额

以下情况会导致语音提醒无法播报:

  1. 用户将服务通知设置为免打扰
  2. 用户开启了手机静音模式或手机音量过低
  3. 用户未打开微信新消息通知,可引导用户前往微信-“我”-“设置”-“新消息通知”中打开
  4. 用户未打开系统对微信的通知
  5. 用户开启了低电量模式
  6. 用户版本过低:需要iOS 8.0.6与安卓8.0.3及以上

新版一次性订阅消息开发指南

1 接入指引

1.1 接入前准备

开发者首先需要明确自己的服务业态,选择对应的业态卡片进行接入。

开发者根据不同卡片的模版规则,向平台进行同步。每个卡片有若干状态模版(如“呼叫车辆中”、“司机赶往上车点中”等),每个模版有不同的必填字段与选填字段(如“司机车牌号”、“预计到达上车点时间”等),平台依据状态流转信息向用户下发通知。

1.2 申请模版

开发者需要登录微信小程序管理后台 ,在「功能-订阅消息-公共模版库-一次性订阅」中查询可以申请的模板,审核通过后可使用。

模版有对应类目要求,符合类目要求的微信小程序可在公共模版库优先看到新版模版。

需要注意的是,添加此类模版后,模版id不支持通过原方式进行订阅与下发,请勿通过wx.requestSubscribeMessage向用户申请订阅该模版。

intro

此外,开发者、代开发服务商可通过服务端接口 addMessageTemplate 添加模版, tid 见下文, kidList 请传入空数组。

目前共支持支持模版情况如下:

notify_type 卡片业态 类目 下发code获取方式 模版定义 addMessageTemplate接口 tid
2001 购物(实体物流)服务动态 商家自营、电商平台/电商平台 将微信支付订单号作为 code 链接 10000001
2002 购物(自提)服务动态 商家自营、电商平台/电商平台 将微信支付订单号作为 code 链接 10000002
2003 购物(虚拟发货)服务动态 IT科技/基础电信运营商、IT科技/电信业务代理商、IT科技/转售移动通信、商家自营、电商平台/电商平台 将微信支付订单号作为 code 链接 10000003
2004 快递寄送服务动态 物流服务/邮政、物流服务/收件/派件、物流服务/快递柜、物流服务/货物运输 将微信支付订单号作为 code 链接 10000004
2005 保险购买服务动态 金融业/保险、金融业/银行 将微信支付订单号作为 code 链接 10000005
2006 购物&餐饮(同城配送)服务动态 商家自营、电商平台/电商平台、餐饮服务/外卖平台、餐饮服务/餐饮服务场所/餐饮服务管理企业 将微信支付订单号作为 code 链接 10000006
2007 购物&餐饮&本地生活(等候领取)服务动态 餐饮服务/餐饮服务场所/餐饮服务管理企业 将微信支付订单号作为 code 链接 10000007
2008 酒店预订服务动态 旅游服务/住宿服务 将微信支付订单号作为 code 链接 10000021
2009 机票服务动态 交通服务/航空 将微信支付订单号作为 code 链接 10000024
2010 火车票、汽车票、船票服务动态 交通服务/火车/高铁/动车、交通服务/长途汽车 将微信支付订单号作为 code 链接 10000022
2011 景区门票服务动态 旅游服务/景区服务 将微信支付订单号作为 code 链接 10000029
1001 打车服务动态 交通服务/出租车、交通服务/网约车、交通服务/顺风车/拼车 通过前端获取 code 链接 10000017
1003 同城配送服务动态 商家自营/保健品、商家自营/珠宝玉石、商家自营/食品饮料、商家自营/成人用品 (医疗器械类)、商家自营/酒类、商家自营/成品油、商家自营/纪念币、商家自营/生鲜/初级食用农产品、商家自营/电话卡销售、商家自营/预付卡、商家自营/成人情趣用品、商家自营/百货商场/购物中心、商家自营/母婴食品、电商平台/电商平台、餐饮服务/外卖平台、餐饮服务/餐饮服务场所/餐饮服务管理企业 通过前端获取 code 链接 10000019
1004 取餐等候服务动态 餐饮服务/餐饮服务场所/餐饮服务管理企业 通过前端获取 code 链接 10000020
1005 餐厅排队服务动态 餐饮服务/餐饮服务场所/餐饮服务管理企业 通过前端获取 code 链接 10000018

1.3 将微信支付订单号作为 code 的模版开发指南

1.3.1 获取 code

当用户在微信小程序内进行支付后,根据下单渠道不同获取对应的code
(1)当前订单为普通微信支付订单
开发者可获得微信支付订单号,可直接作为 code
(2)当前订单为微信支付分订单
开发者可获得微信支付服务订单号,可直接作为 code

code 在当次服务进程中唯一,后续开发者更新用户的服务状态均通过此 code 进行。

注意事项:

  1. 需要注意的是,微信支付订单号从生成到可被校验存在一定的时延可能,若收到报错为notify_code 不存在,建议在1分钟后重试。
  2. 对于合单支付场景,需要使用子单的订单号作为 code ,多个子单可用于激活多个卡片,互不干扰。
  3. 仅支持当前微信小程序的微信支付订单号/微信支付服务订单号,请勿使用其他微信小程序、公众号支付、APP支付的订单号。
  4. 不同的下单渠道在调用服务端接口 setUserNotify 时,需要在传入的字段中进行相应的声明。

1.3.2 激活卡片

开发者需在支付完成24小时内调用服务端接口 setUserNotify 传入初始化卡片状态与状态相关字段(见1.1中各模版定义链接),以首次激活 code ,后续才可以继续通过 setUserNotify 更新服务的动态。

1.3.3 更新卡片状态

code 并激活后,开发者可在激活后30天内调用服务端接口 setUserNotify ,更新卡片状态与状态相关字段(见见1.1中各模版定义链接)。超过30天,或状态无可变更的下一状态时(如状态更新到“订单已完成”),不再允许开发者更新。

1.4 通过前端获取 code 的模版开发指南

1.4.1 获取 code

从基础库 2.26.2 开始支持

开发者需要在前端将触发服务的 button 组件的 open-type 的值设置为 liveActivity ,设置 activity-type 参数为notify_type。当用户点击 button 后,可以通过 bindcreateliveactivity 事件回调获取到 code

code 在当次服务进程中唯一,后续开发者更新用户的服务状态均通过此 code 进行。

注意事项:

  1. 平台会对相关 button 组件进行检测,包括是否诱导用户点击、通过与卡片无关的按钮获取 code 等。

代码示例:

<button open-type="liveActivity" activity-type="1001" bindcreateliveactivity="onLiveActivityCreate">立即呼叫</button>
Page({
  onLiveActivityCreate (evt) {
    console.log(evt.detail.code)
  }
})

1.4.2 激活卡片

开发者需要在获取后5分钟内调用服务端接口 setUserNotify 传入初始化卡片状态与状态相关字段(见1.1中各模版定义链接),以首次激活 code ,后续才可以继续通过 setUserNotify 更新服务的动态。

1.4.3 更新卡片状态

code 激活后,可在激活后24小时内调用服务端接口 setUserNotify ,更新卡片状态与状态相关字段(见1.1中各模版定义链接)。超过24小时,或状态无可变更的下一状态时(如状态更新到“订单已完成”),不再允许开发者更新。

1.5 监听事件开发指南

开发者调用服务端接口 setUserNotify 后,会触发平台下发订阅消息,开发者可通过接入微信小程序消息推送服务接收订阅消息下发失败事件。

订阅消息下发失败事件参数如下:

参数 描述
ToUserName 微信小程序账号ID
FromUserName 用户openid
CreateTime 时间戳
MsgType 消息类型,固定为”event”
Event 事件类型,固定为”notify_service_msg_send_result”
openid 用户openid
notify_code 动态更新令牌
notify_type 卡片id
card_status 状态id
fail_ret 错误码:-10001 系统错误;-10002 内容安全校验不通过;-1003 未添加订阅消息模版;-1004 用户拒收此模版;-1005 消息下发过于频繁被拦截
fail_msg 错误信息

JSON格式示例如下:

{
    "ToUserName":"gh_e5e82d93a62a",
    "FromUserName":"o7esq5PHRGBQYmeNyfG064wEFVpQ",
    "CreateTime":1699428279,
    "MsgType":"event",
    "Event":"notify_service_msg_send_result",
    "openid":"o7esq5PHRGBQYmeNyfG064wEFVpQ",
    "notify_code":"p1.4200002043202311087295582095",
    "notify_type":2006,
    "card_status":4,
    "fail_ret":-1004,
    "fail_msg":"user reject message "
}

1.6 其他功能开发指南

1.6.1 查询卡片状态

由于卡片状态的更新有一套严格的校验机制,在开发者向微信小程序平台同步信息的过程中,存在信息丢失、更新不及时等场景,因此开发者可以通过服务端接口 getUserNotify 查询 code 对应在平台侧存储的状态与服务相关信息。

1.6.2 传入扩展信息

开发者通过此功能除了可以向用户下发通知,还可以通过服务端接口 getUserNotifyExt 传入更多服务相关信息,实现更多功能,当前支持的能力包括:

  1. 交易评价升级:https://docs.qq.com/doc/DV2J4U1ltSExScnBB

2 相关接口文档

激活与更新卡片:setUserNotify

查询卡片状态:getUserNotify

配置更多服务相关信息:setUserNotifyExt

3 Q&A

以下Q&A回答了部分开发者关心的内容,更多提问可前往微信开放社区提问。

激活与更新机制

通知机制

Q:为什么有的状态变更会下发通知,有的不会?对于不下发通知的状态,我是否没有必要按照模版传入? A:微信小程序将根据用户需求,动态调整下发内容,因此开发者可将所有的状态变按照模版传入,无需根据微信小程序侧调整重新接入。

Q:为什么有的字段传入后会在卡片中展示,有的不会?对于不展示的字段,我是否没有必要按照模版传入? A:微信小程序将根据用户需求,动态调整下发内容,因此开发者可将所有的字段变按照模版传入,无需根据微信小程序侧调整重新接入。

Q:通过此方案下发的通知,部分会与以前的订阅消息冲突,会不会重复打扰用户? A:对于通过此方式下发的消息,建议开发者先手动不下发相似的订阅消息模版,且不再弹出相似的订阅消息申请弹窗。后续微信小程序侧将上线一定的策略统一帮助开发者拦截。

模版

Q:我当前的业务形态没有被满足,后续是否还会开放更多的模版? A:平台会不断根据用户、开发者反馈设计新的模版,也欢迎开发者提交模版设计

微信小程序订阅消息

功能介绍

消息能力是微信小程序能力中的重要组成,我们为开发者提供了订阅消息能力,以便实现服务的闭环和更优的体验。

订阅消息推送位置:服务通知

订阅消息下发条件:开发者通过一定的方式触发用户主动订阅

订阅消息卡片跳转能力:点击查看详情可跳转至该微信小程序的页面

消息分类

新版一次性订阅消息Beta

新版一次性订阅消息是一种无需用户在弹窗中主动订阅即可向用户下发消息的能力,用户的订阅方式为:

  1. 当用户在微信小程序中进行微信支付后,开发者可将微信支付订单号作为 code 向用户下发服务通知
  2. 开发者可在微信小程序中将触发服务的 button 组件的 open-type 的值设置为 liveActivity,当用户点击 button 后可获得 code ,后续可使用此 code 向用户下发服务通知

此下发方式由平台定义模版,开发者根据自身业务选择模版进行接入。

详见订阅消息接入 Beta开发指南文档。

一次性订阅消息(用户通过弹窗订阅)

一次性订阅消息用于解决用户使用微信小程序后,后续服务环节的通知问题。

开发者在微信小程序中调用 requestSubscribeMessage 接口后,将向用户展示弹窗,用户可打开自己想要接受的消息开关。用户订阅后,开发者可不限时间地下发一条对应的服务消息;每条消息可单独订阅或退订。

详见微信小程序订阅消息开发指南文档。

长期订阅消息(用户通过弹窗订阅)

一次性订阅消息可满足微信小程序的大部分服务场景需求,但线下公共服务领域存在一次性订阅无法满足的场景,如航班延误,需根据航班实时动态来多次发送消息提醒。为便于服务,我们提供了长期性订阅消息,用户订阅一次后,开发者可长期下发多条消息。

目前长期性订阅消息仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下公共服务业务。

详见微信小程序订阅消息开发指南文档。

同时长期订阅消息支持语音提醒与添加提醒能力。

长期订阅限频消息

为满足介于长期订阅与一次性订阅之间的部分业务场景需求,长期订阅消息现细分为「不限频」与「限频」两种类型。其中,限频类型支持用户完成一次订阅后,开发者按照预设频次(如每日一次、每月一次等)向用户下发消息。

需特别说明的是,限频消息引入「必填字段」概念,该字段将作为频次校验的核心标识(code)。例如:用户持有三张当月到期的保单(保单 1、保单 2、保单 3),若对应的「保单到期提醒」消息模版频次限制为每月一次,则开发者在「保单编号」这一必填字段中分别填入保单 1、保单 2 的编号时,可分别触发一次消息下发(即每张保单每月可基于该模版触发一次消息下发)。

限频消息的开发方式与长期订阅消息保持一致,开发者可进入公共模版库,选择与自身微信小程序类目匹配的消息模版。当前限频消息暂向金融等指定行业开放,若开发者存在更多模版需求,可通过行业对接人员反馈,或前往微信开放社区提交需求反馈。

设备订阅消息

设备订阅消息是一种特殊类型的订阅消息,它属于长期订阅消息类型,且需要完成「设备接入」才能使用。

设备订阅消息用于在设备触发某些需要人工介入的事件时(例如设备发生故障、设备耗材不足等),向用户发送消息通知。

详见设备订阅消息文档。

打开半屏微信小程序

从基础库 2.20.1 开始支持

当微信小程序需要打开另一个微信小程序让用户进行快捷操作时,可将要打开的微信小程序以半屏的形态跳转。

avatar

调用流程

打开半屏微信小程序

  1. 2.23.1以下版本基础库,开发者需要在全局配置app.jsonembeddedAppIdList字段中声明需要半屏跳转的微信小程序,若不配置将切换为普通的微信小程序跳转微信小程序。2.23.1及以上版本起无需配置

配置示例:

{
  "embeddedAppIdList": ["wxe5f52902cf4de896"]
}
  1. 开发者通过调用wx.openEmbeddedMiniProgram半屏跳转微信小程序

半屏微信小程序环境判断

开发者可以通过调用wx.getEnterOptionsSync读取apiCategory参数,当值为embedded时,可以判断此时微信小程序被半屏打开。

返回原微信小程序

被半屏打开的微信小程序可以以通过调用wx.navigateBackMiniProgram返回上一个微信小程序。

使用限制

使用过程有以下限制,若不符合以下所有条件将被自动切换为普通的微信小程序跳转微信小程序,不影响用户使用:

  1. 被半屏跳转的微信小程序需要通过来源微信小程序的调用申请,开发者可在 微信小程序管理后台「设置」-「第三方设置」-「半屏微信小程序管理」板块发起申请,最多可以申请添加100个微信小程序(单个微信小程序最多可被 10000 个微信小程序添加);
  2. 2.23.1版本以下基础库,被半屏打开的微信小程序需要在app.jsonembeddedAppIdList字段中声明;
  3. 当前微信小程序需为竖屏;
  4. 被半屏跳转的微信小程序需为非个人主体微信小程序(不含小游戏)。

打开 App

此功能需要用户主动触发才能打开 APP,所以不由 API 来调用,需要用 open-type 的值设置为 launchApp 的 button 组件的点击来触发。

当微信小程序从 APP 打开的场景打开时(场景值 1069),微信小程序会获得返回 APP 的能力,此时用户点击按钮可以打开拉起该微信小程序的 APP。即微信小程序不能打开任意 APP,只能 跳回 APP。

在一个微信小程序的生命周期内,只有在特定条件下,才具有打开 APP 的能力,这个能力的规则如下:

当微信小程序从 1069 场景打开时,可以打开 APP。

当微信小程序从非 1069 的打开时,会在微信小程序框架内部会管理的一个状态,为 true 则可以打开 APP,为 false 则不可以打开 APP。这个状态的维护遵循以下规则:

  • 当微信小程序从以下场景打开时,保持上一次打开微信小程序时打开 App 能力的状态:
    • 从其他微信小程序返回微信小程序(场景值1038)时(基础库 2.2.4 及以上版本支持)
    • 微信小程序从聊天顶部场景(场景值1089)中的「最近使用」内打开时
    • 长按微信小程序右上角菜单唤出最近使用历史(场景值1090)打开时
    • 发现栏微信小程序主入口,「最近使用」列表(场景值1001)打开时(基础库2.17.3及以上版本支持)
    • 浮窗(场景值1131、1187)打开时(基础库2.17.3及以上版本支持)
  • 当微信小程序从非以上场景打开时,不具有打开 APP 的能力,该状态置为 false。

双人音视频对话

通过双人音视频通话功能(1v1 VoIP),用户可以直接在微信小程序内进行一对一视频通话或音频通话,提升微信小程序服务质量,且功能所需的开发成本极低。

从基础库 2.20.1 开始支持

申请开通

暂只针对国内主体如下类目的微信小程序开放,需要先通过类目审核,再在微信小程序管理后台,「开发」-「开发管理」-「接口设置」中自助开通该接口权限。

一级类目/主体类型 二级类目 应用场景
教育 在线视频课程 一对一辅导、答疑
医疗 互联网医院、公立医疗机构、私立医疗机构 在线问诊
金融 银行、信托、公募基金、私募基金、证券/期货、证券/期货投资咨询、保险、征信业务、新三板信息服务市场、股票信息服务市场(港股/美股)、消费金融 金融产品视频客服理赔等
汽车 汽车预售服务 汽车预售等
政府主体账号 / 政府相关工作在线咨询等
IT科技 多方通信、音视频设备、基础电信运营商 提供语音会议/视频会议等服务;硬件在线销售及服务等;提供在线客服等服务
工具 视频客服 不涉及以上几类内容的一对一客服服务,如企业售后一对一视频/音频通话等

前端接口

  • 开启双人通话:wx.setEnable1v1Chat
  • 加入(创建)双人通话:wx.join1v1Chat
  • 退出(销毁)双人通话:wx.exitVoIPChat
  • 更新房间麦克风/耳机静音设置:wx.updateVoIPChatMuteConfig
  • 监听房间成员变化:wx.onVoIPChatMembersChanged
  • 监听房间成员通话状态变化:wx.onVoIPChatSpeakersChanged
  • 监听通话中断:wx.onVoIPChatInterrupted
  • 监听实时语音通话成员视频状态变化:wx.onVoIPVideoMembersChanged

调用流程

  1. 通过 wx.setEnable1v1Chat 接口将用户的接听状态enable设置为true,该设置仅在当次微信小程序生命周期有效,微信小程序每次冷启动后均需要重新设置。
  2. 通过 wx.join1v1Chat 接口传入呼叫方信息caller与接听方信息listener发起呼叫,接听方与呼叫方均需在微信小程序内。

计费

微信为单个微信小程序提供每个自然月1000分钟的免费通话时长,1分钟语音通话时长扣除1分钟免费通话时长,1分钟视频通话时长扣除15分钟免费时长。超出部分需另行付费。 免费时长领取与套餐包购买需前往微信服务市场进行操作。

多人音视频对话

用于实现微信小程序内多人音视频对话的功能。

申请开通

微信小程序管理后台,「开发」-「接口设置」中自助开通该组件权限。相关接口 wx.joinVoIPChat 和组件 voip-room。

调用流程

开发者仅需提供房间唯一标识,即可加入到指定的房间。传入相同唯一标识的用户,会进到相同的房间。为了保证前端传入的 groupId 可信,wx.joinVoIPChat 接口要求传入签名。详见 签名算法。当加入视频房间时,可结合 voip-room 组件显示成员画面。

前端接口

  • 创建/加入房间:wx.joinVoIPChat
  • 离开房间:wx.exitVoIPChat
  • 更新房间麦克风/耳机静音设置:wx.updateVoIPChatMuteConfig
  • 监听房间成员变化:wx.onVoIPChatMembersChanged
  • 监听房间成员通话状态变化:wx.onVoIPChatSpeakersChanged
  • 监听通话中断:wx.onVoIPChatInterrupted
  • 监听实时语音通话成员视频状态变化:wx.onVoIPVideoMembersChanged
  • 订阅视频画面成员:wx.subscribeVoIPVideoMembers

签名算法

生成签名需要传入四个参数:

参数名 说明
appId 微信小程序的 appId
groupId 游戏房间的唯一标识,由游戏自己保证唯一
nonceStr 随机字符串,长度应小于 128
timeStamp 生成这个随机字符串的 UNIX 时间戳(精确到秒)

签名算法为:

// hmac_sha256需要开发者自行引入
signature = hmac_sha256([appId, groupId, nonceStr, timeStamp].sort().join(''), sessionKey)

具体来说,这个算法分为几个步骤:

  1. appId groupId nonceStr timeStamp 四个值表示成字符串形式,按照字典序排序;
  2. 将排好序的四个字符串拼接在一起;
  3. 使用 session_key 作为 key,使用 hmac_sha256 算法对 2 中的结果字符串做计算,所得结果即为 signature

示例:

appId = 'wx20afc706a711eefc'
groupId = '1559129713_672975982'
nonceStr = '8AP6DT9ybtniUJfb'
timeStamp = '1559129714'
session_key = 'gDyVgzwa0mFz9uUP7M6GQQ=='

str = [appId, groupId, nonceStr, timeStamp].sort().join('') = '1559129713_67297598215591297148AP6DT9ybtniUJfbwx20afc706a711eefc'
signature = hmac_sha256('1559129713_67297598215591297148AP6DT9ybtniUJfbwx20afc706a711eefc', sessionKey) = 'b002b824688dd8593a6079e11d8c5e8734fbcb39a6d5906eb347bfbcad79c617'

使用云开发完成签名

在云开发中,无法获取 session_key,但提供了单独的函数 cloud.getVoIPSign 来计算签名。

const cloud = require('wx-server-sdk')
cloud.init()

exports.main = async (event, context) => {
  const signature = cloud.getVoIPSign({
    groupId: 'xxx',
    timestamp: 123,
    nonce: 'yyy'
  })
  return signature
}

人数限制

每个房间最多同时加入 10 个人。

频率限制

对于每个微信小程序,每天最多允许创建 100000 个房间。当所有人退出房间时,房间即被销毁。此时如果传入之前用过的 groupId 重新加入房间,会被计算为新开一个房间。

分享数据到微信运动

从基础库 2.14.0 开始支持

可将用户在微信小程序内的运动数据分享到微信运动。

申请开通

微信小程序管理后台,「开发」-「接口设置」中自助开通该组件权限。 只针对「体育-在线健身」类目的微信小程序开放。

调用流程

开发者通过调用wx.shareToWeRun传入用户的运动数据,会触发弹窗,用户点击确定后即可在微信运动排行榜与详情页中展示运动数据。 avatar

注意事项

  1. 对于开发版和体验版微信小程序,可以在微信小程序内正常调用该接口,但不会展示到微信运动中。开发者在开发时可以以调用接口是否成功作为是否打卡成功的依据。
  2. 用户每次打卡都会记录到微信运动中,请开发者妥善处理用户打卡成功的场景,避免重复打卡。
  3. 微信运动排行榜中,展示的是最近一次打卡的第一条记录。

运动类型

当前支持以下运动类型的与不同运动类型支持传入的单位如下:

运动类型 typeId 支持传入单位
锻炼 1001 time/calorie
体能训练 1002 time/calorie
功能性训练 1003 time/calorie
瑜伽 2001 time/calorie
钓鱼 2002 time/calorie
广场舞 2003 time/calorie
踢足球 2004 time/calorie
打篮球 2005 time/calorie
打羽毛球 2006 time/calorie
打乒乓球 2007 time/calorie
打网球 2008 time/calorie
跑步 3001 time/distance/calorie
登山 3002 time/distance/calorie
骑车 3003 time/distance/calorie
游泳 3004 time/distance/calorie
滑雪 3005 time/distance/calorie
跳绳 4001 number/calorie
俯卧撑 4002 number/calorie
深蹲 4003 number/calorie

设置时最多传入一个单位,不支持同时传入多个单位。不同单位支持传入的数量限制如下:

单位 说明 有效值
number 运动个数,单位:个 有效值1-10000,需为整数
distance 运动距离,单位:米 有效值1-100000,需为整数
time 运动时间,单位:分钟 有效值1-1440,需为整数

代码示例

wx.shareToWeRun({
      recordList: [{
        typeId: 4001,
        number: 180
      }, {
        typeId: 3001,
        distance: 100000
      }],
      success(res) {
        wx.showToast({
          title: '打卡成功',
        })
      },
      fail(res) {
        wx.showToast({
          icon: "none",
          title: '打卡失败',
        })
      }
    })

微信小程序加密网络通道

从基础库 2.17.3 开始支持

一、功能介绍

在前后端开发联调过程中,开发者通常会使用代理软件对自己开发的项目服务做请求转发,便于切换开发环境和进行测试。

代理软件可以在 客户端 与 真实服务器 之间进行数据传输。

这时,代理软件可以解密并查看通过 SSL 加密的数据,然后再重新加密数据发送给原始目的地。对于客户端和服务器来说,它们仍然认为自己处于一个安全的加密连接中,实际上数据的安全性已被破坏。

除了监听之外,由于代理软件可以解密 SSL 加密的通信,因此也支持修改传输中的数据,甚至插入恶意内容。上述这种中间人代理,也会被不法分子恶意使用,用于任意监听自己设备中的所有请求。

他们会在自己的设备中运行其他开发者开发的「微信小程序」、「WEB 网页」 或「原生APP」,然后通过中间代理获取和篡改正常请求的「请求包」和「响应包」,并有针对的对目标请求进行重放,用于实现恶意的目的(比如刷经验、修改游戏结果、创建 1 分钱订单等)。

为了防止中间人代理攻击,我们就需要在 SSL 加密的基础上,对请求包和响应包的明文再进行一次加密,这种方法可以提供额外的安全层次,保障数据即使在被代理软件解密后仍保持安全。

目前微信团队针对加密网络通道提供两种解决方案:

  1. API 自实现方案: 微信平台维护了一个用户维度的可靠 Key,开发者可以分别通过微信小程序前端 API 和微信后台提供的服务端接口获取到,并自己实现对请求包的加密。
  2. 微信网关方案: 微信团队结合多年安全防护经验积累推出的微信网关,具备系统化、多层级的安全防护能力。开发者接入后,就会将「微信小程序」到「开发者服务端」的通信链路自动从公网链路切换到微信专线链路,并且全程对请求内容进行二层加密,有效防止中间人代理攻击。

获取加密 key 信息需要向微信平台发送请求,产生耗时,从而对业务性能产生负担。如开发者希望安全加密的同时减少业务无关的耗时,可以使用微信网关方案。

二、API 自实现方案

为了避免微信小程序与开发者后台通信时数据被截取和篡改,微信平台维护了一个用户维度的可靠 Key,用于微信小程序和后台通信时进行加密和签名。

开发者可以分别通过微信小程序前端 API 和微信后台提供的服务端接口,获取到用户加密 key。

微信平台只提供可靠的加密 key,开发者需自行实现加密方式,对向服务端接口请求的数据进行端处加解密。

在微信小程序中开发者可以使用UserCryptoManager.getLatestUserKey获取获取用户最新的加密密钥信息。

2.1 前端调用示例

const somedata = 'xxxxx'
const userCryptoManager = wx.getUserCryptoManager()
userCryptoManager.getLatestUserKey({
    success({encryptKey, iv, version, expireTime}) {
        const encryptedData = someAESEncryptMethod(encryptKey, iv, somedata)
        wx.request({
           data: encryptedData,
           success(res) {
                const decryptedData = someAESDEcryptMethod(encryptKey, iv, res.data)
                console.log(decryptedData)
           }
        })
    }
})

someAESEncryptMethod 和 someAESDEcryptMethod 分别为加解密函数,由开发者自行引入加解密库来实现,基础库暂时不提供加解密能力。

开发者可参考开源加密库: https://github.com/flash1293/aes-wasm https://github.com/ricmoo/aes-js

根据自身业务情况,寻找合适的加密方式:

  • 非对称加密: 客户端和服务器维护两组公私加密密钥,每次接口请求时,先对明文数据进行加密,另一方收到密文后用对应的反向密钥解密。常见的非对称加密有 RSA、DSA、ECC,非对称加密安全性高,但加解密速度慢,不太适合请求体或响应体太大的情况。
  • 对称加密: 客户端和服务端维护一组密钥,每次接口请求时,对明文数据进行加密,另一方收到时用同样的密钥解密。常见的对称加密有 DES、3DES、IDEA、RC5、RC6、Blowfish,对称加密加解密速度快,适合对大数据做加解密处理,安全性有所下降。
  • 整合方案: 请求时,客户端对明文用对称加密方式加密,对称密钥随机生成,然后用非对称加密方式加密前面的对称密钥,最后将密文和加密后的对称密钥内容合并发出;服务端收到时,按照反向流程进行解密,响应包也是相同的处理流程。

在开发者服务端,可以调用getUserEncryptKey后台接口获取用户最近三次的key。在获取key的同时,接口会携带version信息,开发者可以比较version版本来选择使用对应的key对数据进行加解密。

2.2 服务端调用示例

curl -X POST "https://api.weixin.qq.com/wxa/business/getuserencryptkey?access_token=ACCESS_TOKEN&openid=OPENID&signature=SIGNATURE&sig_method=hmac_sha256"

三、微信网关方案

可以参考此文档接入微信网关:微信小程序一键接入微信网关

安全键盘

从基础库 2.18.0 开始支持

很多微信小程序业务需要输入一些敏感信息,比如密码口令,身份证,手机号等。不专业的做法是使用明文提交到业务后台,在网络传输中非常容易泄漏出去,同时也不满足合规要求。也有一些改进的做法,利用javascript对敏感信息进行加密,比如把明文的密码口令加密成为密文后再提交到业务后台。但因为微信小程序本质是基于H5技术,安全性不高,比如在H5上使用javascript比较容易能看到加密逻辑,或者加密强度不够,第三方输入法监听,内存遍历等,还是会造成口令泄露等问题。

为提高微信开放平台生态安全性,针对微信小程序内数字密码输入场景中可能存在的安全问题,微信侧在input组件开放了安全键盘类型。通过引入安全键盘,微信小程序可以在用户输入过程中对关键信息时进行加密,防止键盘窃听,内存保护,有效保障用户数据资产的安全。

安全键盘保护原理

安全键盘采用非对称加解密算法,该算法需要两个密钥,一个叫公钥,可以公开,另一个叫私钥,需要私密保管。其中公钥加密的密文,只有私钥才能解开,而且通过公钥没办法计算出私钥,这样黑客即使拿到公钥也没办法解密密文。我们一般把公钥放到客户端上(比如微信小程序环境)做加密,私钥放到业务后台,这样就只有后台才能解密。黑客比较容易攻击本地客户端,但是攻破后台则难很多,甚至有些业务把私钥存储到硬件加密机芯片里面,这种情况黑客更是没办法获取得到私钥,因此采用非对称加解密算法是安全键盘推荐的模式,安全性可以得到保障。 为了保证私钥的私密性价值,我们要求不同的微信小程序业务使用自己独有的公钥私钥对,这样就可以完美的做到业务加密的数据隔离,业务A的公钥加密数据,就只有业务A自己的私钥可以解开,业务A的责任就是负责保护好自己的独有私钥即可。 为了证明一个公钥是属于业务A的,我们会颁发一个数字证书给到业务A的开发者,数字证书由腾讯官方签名,保证了可靠性与不可篡改性,数字证书里面会绑定一个业务独有的公钥, 业务的私钥是在向腾讯申请数字证书的过程中产生的,业务负责管理好自己的私钥,这个过程中,腾讯仅能接触到公钥,没办法得到业务自己的私钥,意味着即使是腾讯也没办法去解密微信小程序业务的用户输入的密码口令。为了国家合规的要求,我们颁发的是国产密码算法的数字证书,意味着非对称加解密算法是使用sm2算法,而非rsa等国际算法。

不同微信小程序业务,可能要加密的数据的格式可能有不同的要求,比如当用户输入的口令是“123456”,有些业务直接对明文做加密即可, 有些业务可能想先做一个哈希处理再加密,比如使用md5(“123456”), 做了哈希后,能更有效的保护用户的明文密码,让业务都不好推测用户实际密码是什么, 另一些业务可能采用sha1哈希算法sha1(“123456”), 也有业务采用更合规的国产密码哈希算法sm3(“123456”),甚至有些业务希望加上一些混淆字符(密码学中叫加盐)到口令明文里面,做更好的保护,就可能会变成sm3(“123456+abc”), 这里面”+abc”就是额外加上的混淆字符示例。 所以为了能让不同的微信小程序业务有符合自己业务需求的加密格式,微信小程序安全键盘也开放了密码格式配置的能力,从而更好的跟自己的整体业务结合在一起,但是这个格式做不到万能兼容所有,所以当你应用微信小程序安全键盘的时候,可能会涉及部分后台验密服务的改造工作量,请提前评估可行性。

使用流程

1 生成证书签署请求

开发者可自行生成公钥私钥、证书签署请求,也可通过微信侧提供的工具生成证书签署请求。通过微信侧提供的工具(Windows / Mac)生成证书签署请求的步骤如下:

  1. 通过SM2 Generate Key Pair功能生成公钥私钥

  1. 通过SM Generate Cert CSR功能生成CSR

2 生成证书

在微信小程序管理后台「开发」-「开发管理」-「开发设置」-「安全键盘证书」板块填入CSR进行生成。

3 使用证书

  1. 将生成的证书放入微信小程序代码包中。
  2. 在input组件中设置type=“safe-password”,并设置相关参数(safe-password-cert-path、safe-password-time-stamp、safe-password-length、safe-password-nonce、safe-password-salt、safe-password-custom-hash)。

代码示例

<input 
  style="border: 1px solid blue;"
  type="safe-password"
  placeholder="123456"
  safe-password-cert-path="/minipro_test_cert.crt" 
  safe-password-time-stamp="1618390369" 
  safe-password-nonce="1618390369" 
  safe-password-salt="zefengwang" 
  safe-password-custom-hash="md5(sha1('foo' + sha256(sm3(password + 'bar'))))"
  bind:blur="onBlur"
  bind:input="onInput"
  value="{{value}}"
></input>
<button bind:tap="onClear">clear</button>

<view>{{detail}}</view>
Page({
  data: {
    value: '123'
  },
  onInput(res) {
    console.log('onInput', res)
    this.setData({
      value: res.detail.value,
    })
  },
  onClear() {
    this.setData({
      value: '',
    })
  },
  onConfirm() {
    console.log('confirm')
  },
  onBlur(res) {
    console.log('onBlur', res)
    this.setData({
      detail: JSON.stringify(res.detail, null, 2)
    })
  },
})

密文

密文格式

安全键盘为了保护用户口令,采用了各种密码学算法来保护用户敏感信息,这些算法是可以根据微信小程序业务的实际需要做灵活配置的,因为不同的微信小程序,采用的口令加密格式不同,所以有必要做符合自己业务的配置。

微信小程序安全键盘对用户密码口令加密后的通用格式如下:

'V02_' + sm2(header + timestamp + '\0' + pbkdf_hmac_hex(password, salt) + '\0' + nonce + '\0' + 随机数)

其中,pbkdf_hmac_hex()为安全键盘计算hash的算法表达式,可通过safe-password-custom-hash属性进行设置。 header前两个字节,用于标识密码hash算法:

  1. 0x00 0x00: custom hash
  2. 0x00 0x07: pbkdf_hmac_hex

这个格式考虑了几点安全因素:

  1. 防重放:传入正确的时间戳timestamp,每次加密nonce 保持自增,保证了即使口令相同,每次加密密文也不相同
  2. 防暴力破解:sm2非对称算法本身保证了防暴力破解的可能
  3. 防追溯原文:内置pbkdf_hmac_hex 算法,也可以自定义hash算法;
  4. 防彩虹表攻击:微信小程序开发者可以自定义动态salt;

微信小程序开发者如果打算使用安全键盘,首先在本地生成sm2 秘钥对,然后前往微信小程序管理后台申请微信小程序安全键盘数字证书。证书下发下来后,需要和微信小程序代码一起发布。 微信小程序调用安全键盘时,需要传入微信小程序安全键盘数字证书,完成证书合法性校验之后,再提取证书公钥并采用sm2 算法对用户数据进行加密。 由于采用证书公钥加密,只有用开发者自己持有的私钥才可以解密出数据明文。网络传输过程中,即使密文被恶意拦截,攻击者也无法拿到明文。

如何解密或验密

'V02_' + sm2(header + timestamp + '\0' + hash(password, salt) + '\0' + nonce + '\0' + 随机数)

后台接收到密文后,参照以上格式进行解析: 1、 移除密文4字节前缀; 2、 使用微信小程序安全键盘证书对应的sm2 私钥解密,得到明文数据; 3、 解析明文数据,可以得到时间戳、密码hash、nonce 等字段;

首先,微信小程序开发者后台只能得到脱敏后的密码hash,无法得到明文。当然,根据合规要求,后台也不应该获取到用户密码明文。 其次,微信小程序开发者后台应妥善保存密码hash,作为匹配用户密码是否一致的依据。比如在用户注册或修改密码流程中,后台SM2 私钥解密出密码hash 之后,应当在数据库中(或者其它存储技术)持久化保存该密码hash。在后续用户登录或其它需要校验密码的场景,通过对比用户请求过来的密码hash 和之前保存的密码hash 是否一致,来确定密码是否验证通过。