微信小程序的坑 (二)只能触发一次的一次性订阅消息
第一次接触微信小程序的订阅消息,之前见过的是公众号内部推送的那种模板消息。
先来看一下官方文档的介绍:传送门。
功能介绍
- 订阅消息推送位置:服务通知
- 订阅消息下发条件:用户自主订阅
- 订阅消息卡片跳转能力:点击查看详情可跳转至该小程序的页面
操作流程
步骤一:获取模板 ID
在微信公众平台手动配置获取模板 ID,模板 ID 用于步骤三中接口下发订阅消息。
步骤二:获取下发权限
详见小程序端消息订阅接口 wx.requestSubscribeMessage
有点像获取用户授权,但使用 getSetting
获取需要另加字段。需要用户点击 “总是允许”,才有具体的已订阅模板记录返回。
步骤三:调用接口下发订阅消息
详见服务端消息发送接口 subscribeMessage.send
一次性订阅的坑
微信小程序这个一次性订阅需要理解透才能不掉到坑里,我对接的时候是掉过好几次才勉强算是成功,一步一坑。
步骤一获取模板的坑
相对于一次性模板,那应该有对应的长久或者永久模板吧,但就是没有。公共模板库下方有一个 一次性订阅
的按钮,猜测之前应该是做筛选用的,现在无反应。没有尝试所有模板,但我通过 申请模板
创建的订单相关的几个模板成功后类型都是一次性的。
这一步要获取的信息有两个部分,一个是模板 ID,另一个是详细内容。模板 ID 确定是哪一个模板,详细内容决定展示的字段和顺序。
[notice]注意:详细内容中定义的字段名很重要,在步骤三中接口需要用到,少一个都不行。[/notice]
步骤二获取下发权限的坑
wx.requestSubscribeMessage(Object object)
小程序前端调用这个 API 获取订阅权限是存在很多限制条件的:
- 首先,基础库 2.4.4 开始支持这个 API,这个限制主要针对开发工具,线上基础库用户大多用的都是 2.10.4 了。
- 只有在真机上调用
wx.requestSubscribeMessage(Object object)
才能选择 “总是允许” 的勾选项;只有选择 “总是允许” 后,wx.getSetting
接口才能获取到具体的已订阅模板记录。 - 订阅模板 ID 对应的 tmplIds 参数在低版本基础库 2.4.4~2.8.3 只支持一个,也只能放一个,多了报错;在基础库 2.10.0 之后到目前 2.11.0 为止也只支持三个,也就是说你一次授权订阅消息,只能传三个,多了一样会报错。
- 2.8.2 版本开始到现在 2.11.0 为止,用户发生点击行为或者发起支付回调后,才可以调起订阅消息界面。什么意思呢,就是只能在
bindTap
或者wx.requestPayment
的success
回调中调用wx.requestSubscribeMessage(Object object)
小程序才会真的执行获取权限这个动作。其他的任何情况调用wx.requestSubscribeMessage(Object object)
是无效的,内部代码并不执行。
还有一个比较重要的坑点,因为订阅消息的一次性,决定了你需要在每次调用接口下发订阅消息前,都必须确保已经再次获取到了订阅权限。获取一次订阅权限,只能发送一次订阅消息。这么坑爹的设定,让我不禁想要口吐芬芳。这种 SB 一次性订阅消息意味着,它自己提供的公共模板库里 99.99% 的模板消息都触发不了。难道我要给小程序前端加一个按钮,让用户没事点两下?
步骤三调用接口下发订阅消息的坑
前面提到了,微信小程序接口不稳定,改动比较大且频繁。订阅消息服务端接口除了请求地址变化以外,作为模板内容的 data 参数也要做适配修改。
之前的 data
形式:
'data' => [
'keyword1' => [
'value' => $goods_names,
'color' => '#333333',
],
'keyword2' => [
'value' => $this->order->express,
'color' => '#333333',
],
'keyword3' => [
'value' => $this->order->express_no,
'color' => '#333333',
],
'keyword4' => [
'value' => '订单已发货',
'color' => '#333333',
],
现在的 data
:
'data' => [
'thing1' => [
'value' => $goods_names,
'color' => '#333333',
],
'character_string2' => [
'value' => $this->order->order_no,
'color' => '#333333',
],
'amount3' => [
'value' => $this->order->total_price,
'color' => '#333333',
],
'thing4' => [
'value' => $remark,
'color' => '#333333',
],
],
这里面的字段名要完全与(微信公众号后台申请的)模板消息详情里字段名一致,一个都不能少,字段值不能为空。颜色 color
字段看官方文档上已经没有了,但并没有报错。请求参数中的 form_id
在新版本里也不再需要。
测试下发订阅消息的过程中,频繁报错:43101 user refuse to accept message.
官方说明:“用户拒绝接受消息,如果用户之前曾经订阅过,则表示用户取消了订阅关系。” 但是我反复查看小程序前端设置里的订阅权限都没发现问题,无果。
在微信小程序文档的帖子里看到很多人提到这个问题,知道原因的比较少还讲不清楚。其实这就是上面提到的订阅消息一次性造成的。每次后台想要发送订阅消息,都得要小程序前端向用户发出申请。一次订阅,一次发送,点了 “总是允许” 也没有 “软” 用。前端根据 wx.getSetting
判断是否已获取订阅权限不仅没有 “软” 用,还会在后续造成逻辑上不能再获取订阅权限的 bug,所以必须去掉这样的判断逻辑。
总结
我的需求是,在用户支付成功,客户 O2O 配送之后给下单的用户发送一条到货信息(派送成功通知)。如果在用户支付成功后给用户发送订单支付成功的信息,那么后续再想发送到货信息就不太现实了。所以解决方案就是,去掉支付成功后发送订阅消息的代码。用户支付成功订阅一次,客户到货后台发送一次。
讲了这么多,总结一句话就是,微信小程序一次性订阅消息很坑,对接需谨慎。如果有其他消息通知的选择,比如短信之类的,还是不要趟这趟浑水了。
扩展阅读:
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
43101的问题解决了吗
43101的问题可以规避掉,只要遵循一次订阅,一次发送的基本规则,就不会报这个错。
怎么解决