这是我参与更文挑战的第3天,活动详情查看: 更文挑战
1. 前言
小程序消息订阅其实是个挺常见的功能。因项目已有封装好的第三方依赖包、故一直没去研究小程序的消息订阅是如何实现的, 最近踩了个坑: 消息订阅面板偶尔出现偶而不出现, 百思不得其解, 痛下决心要好好理一理, 故有了此文。
2. 小程序消息
小程序的消息能力分为以下四种:
- 订阅消息: 需要用户主动订阅消息通知, 开发者才可向用户推送、不受时间限制.
- 统一服务消息
- 客服消息
- 位置消息
此文围绕小程序的订阅消息做讲解, 若对其它消息感兴趣, 请前往官网查看: developers.weixin.qq.com/miniprogram…
订阅消息: 为开发者提供了订阅消息能力, 以便实现服务的闭环和更优的体验. 先来看看官网提供的基础知识: 需要留意下的是微信开发者工具vs真机的消息面板存在差异.
先来看看微信开发者工具(居中出现): 再来看看真机效果图(从底部弹起面板): 坑: 微信开发者工具上无法显示订阅消息的所有列表且无法勾选选择、也无法显示'总是保持以上选择, 不再询问'的选项.
基础知识具备了、接下来我们看看如何实现小程序的订阅消息!
3. 使用说明
3.1 获取模板ID
A. 打开微信公众平台地址,扫码登录后台, 并找到订阅消息tab.
微信公众平台链接请戳此: mp.weixin.qq.com/
若您未开通消息订阅模板, 会先提示您去开通此功能.
以下是开通后的截图:
B. 手动配置模板ID(若在公共模板库中没有找到合适的,可以申请添加新模板、审核通过后即可使用).
首先, 选定xxx模板, 点击选用(为演示方便、选中公共模板库中的)
然后, 会跳转至订阅消息设置页:在这里,可去配置订阅消息模板并会实时预览(左侧)
配置完成后提交, 你就会在我的模板看到该条订阅消息相关信息.
至此、我们就可以复制这个模板到代码处。
3.2 获取下发权限
关于小程序端消息订阅接口, 请戳此链接: developers.weixin.qq.com/miniprogram…
在发送小程序的订阅消息前由用户来决定是否需要收到订阅消息(即订阅面板)。
wx.requestSubscribeMessage(Object object) API可获取下发权限 调起客户端小程序订阅消息界面, 返回用户订阅消息的操作结果。
当用户勾选了订阅面板中的'总是保持以上选择、不再询问'时, 模板消息会被添加到用户的小程序设置页, 通过wx.getSetting接口可获取用户对相关模板的订阅状态。
2.8.2版本开始, 用户发生点击行为或者发起支付回调后、才可以调起订阅消息界面.
调用成功的回调函数说明如下:
调用失败的回调函数如下(官网有提供错误码及其含义):
接下来我主要演示下如何使用.
// wxml
<text class="user-motto" bind:tap="subscribe">点我唤起订阅面板</text>
// js
const app = getApp()
Page({
subscribe () {
wx.requestSubscribeMessage({
tmplIds: ['xxxxxxxxxx'],
success (res) {
console.log('接口调用成功的回调函数', res)
},
fail (err) {
console.log('接口调用失败的回调函数', err)
},
complete () {
console.log('接口调用结束的回调函数(调用成功、失败都会执行)')
}
})
}
})
点击按钮会出现订阅消息面板、点击允许/取消、均会给到相关回调、具体场景如下演示.
3.2.1 成功订阅(单条)
tmplIds只配置了一条、未勾选'总是保持以上选择, 不再询问'选项,点击允许接口调用成功、会回调如下信息:
用户再次点击仍可唤醒订阅面板.
3.2.2 取消订阅(单条)
tmplIds只配置了一条、未勾选'总是保持以上选择, 不再询问'选项,点击取消接口调用成功、会回调如下信息:
到了这里你会发现、只要接口调用成功、触发的都是success回调、只是模板ID对应的值可能是accept/reject/ban/filter.
模板ID值 | 意义说明 |
---|---|
accept | 用户同意订阅该条id对应的模板消息 |
reject | 用户拒绝订阅该条id对应的模板消息 |
ban | 已被后台封禁 |
filter | 该模板因为模板标题同名被后台过滤 |
3.2.3 部分订阅(多条)
假设现在有2条订阅消息、一条勾选、一条不勾选, 然后点击允许 成功回调里面会显示有条同意、有条拒绝了, 如下图: 第二次点击会再重新弹窗授权。 这里有几个地方需要注意下:
一次授权调用里面,每个tmpId对应的模板标题不能存在相同的, 若出现相同的、则保留一个.
一次调用最多可订阅3条消息(需要留意客户端版本)
iOS客户端7.0.6版本、Android客户端7.0.7版本之后的一次性订阅/长期订阅才支持多个模板消息;
iOS客户端7.0.5版本、Android客户端7.0.6版本之前的一次订阅只支持一个模板消息;
若真超过了3条、微信小程序会直接抛出异常: requestSubscribeMessage:fail Templates count out of max bounds
// 获取应用实例
const app = getApp()
Page({
subscribe () {
wx.requestSubscribeMessage({
tmplIds: ['xxxx1','xxxx2','xxxx3','xxx4'], // 4个模板ID不一样
success (res) {
console.log('接口调用成功的回调函数', res)
},
fail (err) {
console.log('接口调用失败的回调函数', err)
},
complete () {
console.log('接口调用结束的回调函数(调用成功、失败都会执行)')
}
})
}
})
详细报错截图如下:
3.2.4 全部订阅(多条)
假设现在有2条订阅消息、全部勾选, 然后点击允许 成功回调里面会显示2条都同意了, 如下图: 第二次点击会再重新弹窗授权.
3.2.5 手动关闭订阅按钮(设置页)
跑去小程序原生设置页-通知管理-关闭接收通知
第二次点击时不会唤醒订阅面板, 请看如下提示.
从提示里面得知: 'The main switch is switched off'.
3.3.6 勾选'总是保持以上选择, 不再询问'
假设现在有2条订阅消息、全部勾选, 并勾选'总是保持以上选择, 不再询问', 然后再点击允许. 成功回调如下图: 第二次点击时不会出现重新弹窗授权, 但代码是继续执行的.
坑: 若勾选了'总是保持以上选择, 不再询问'选项, 代码层面仍会调用wx.requestSubscribeMessage()这个函数、只是不会出现弹窗而已, 若需要修改设置、要去到小程序原生设置页.
3.3.7 获取用户订阅通知权限
wx.getSetting可获取用户订阅通知权限.
// wx.getSetting()默认情况下是没法获取用户是否授权订阅消息的, 需要传参withSubscriptions
wx.getSetting({
withSubscriptions: true,
success (res) {
console.log(res.subscriptionsSetting)
// res.subscriptionsSetting = {
// "4xijn4T0leWUq6-aQnwPm2TCmmyttczwEktotiAuVhY": "reject",
// "F3GZ_x07Hc-tM7r2zOX7yRNgROoNIKx70C48mrHaTrs": "accept",
// "itemSettings": {
// "4xijn4T0leWUq6-aQnwPm2TCmmyttczwEktotiAuVhY": "reject",
// "F3GZ_x07Hc-tM7r2zOX7yRNgROoNIKx70C48mrHaTrs": "accept"
// },
// "mainSwitch": false
// }
}
})
用户在设置页开启或关闭订阅消息授权(wx.openSetting)、小程序目前没有提供相应的回调方法, 需要开发者调用wx.getSetting()去查看授权信息。
3.3 调用接口下发订阅消息
若用户在3.2中同意接收订阅消息、实现3.3后用户就可以接收到订阅消息了;
若用户在3.2中拒绝接收, 那么执行3.3用户也不会收到订阅消息.
先附赠官网详细说明: developers.weixin.qq.com/miniprogram…
调用方式:
1.在云函数目录下的config.json中的permissions.openapi字段增加要调用的接口名字.
{
"permissions": {
"openapi": [
"subscribeMessage.send"
]
}
}
2.在云函数中使用云调用
云函数需要使用的版本号至少是0.4.0的wx-server-sdk, 建议始终保持最新, 保证云函数目录下的 package.json 的 wx-server-sdk 字段为 latest,如本地安装依赖,请执行 npm install --save wx-server-sdk@latest
若没安装过wx-server-sdk, 必须先安装.
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
env: cloud.DYNAMIC_CURRENT_ENV,
})
exports.main = async (event, context) => {
try {
const result = await cloud.openapi.subscribeMessage.send({
"touser": cloud.getWXContext().OPENID, // 通过 getWXContext 获取 OPENID
"page": '/pages/logs/logs?title=云开发传参',
"lang": 'zh_CN',
"data": {
"date01": {
"value": '2015年01月05日'
}
},
"templateId": '0bzzt22P68jQtzFfWJHUEVKqVSOHDj48be3WAvuVJvw',
"miniprogramState": 'developer'
})
return result
} catch (err) {
return err
}
}
这一步要你先够好云开发环境、然后才能真正实现.
3.4 小程序页面接收订阅消息传进来的参数
点击服务通知卡片、会直接跳转至小程序卡片配置的页面路径, 开发者可以在onLoad生命周期函数中去接受传参数。
onLoad(options) {
console.log(options,'跳转传参数')
}
4. 踩坑记录
4.1 订阅面板没法出现
报错代码如下:
subscribe () {
this.setData({
status: 1
},()=>{
wx.requestSubscribeMessage({
tmplIds: ['0bzzt22P68jQtzFfWJHUEVKqVSOHDj48be3WAvuVJvw'],
success (res) {
console.log('接口调用成功的回调函数', res)
},
fail (err) {
console.log('接口调用失败的回调函数', err)
},
complete () {
console.log('接口调用结束的回调函数(调用成功、失败都会执行)')
}
})
})
}
报错提示如下: 报错原因: wx.requestSubscribeMessage()必须是同步的、不允许放在回调函数里面去实现(除了支付回调)
4.2 实现UI最后的坚持
设计师总是会有些花里胡哨的需求, 比如: 用户未订阅前、按钮文案显示: 提醒我订阅; 用户订阅后、按钮文案显示: 已设置订阅.
But若用户退出去、再从其它入口进来该页面、仍显示的是提醒我订阅文案(即使在退出页面前已订阅)
开发者无法得知该用户是否订阅过(初始状态下)
// wxml
<view>{{ isSubscribed ? '已设置订阅': '提醒我订阅'}}</view>
<text class="user-motto" bind:tap="subscribe">点我唤起订阅面板</text>
// js
const app = getApp()
Page({
data:{
isSubscribed: false
},
subscribe () {
const tmpId = 'F3GZ_x07Hc-tM7r2zOX7yRNgROoNIKx70C48mrHaTrs'
// 戳按钮前获取消息订阅权限
wx.getSetting({
withSubscriptions: true,
success: (res) => {
console.log('订阅消息设置', res)
const { subscriptionsSetting } = res
// 判定该订阅消息是否订阅过
if (subscriptionsSetting && subscriptionsSetting.itemSettings && subscriptionsSetting.itemSettings[tmpId] && subscriptionsSetting.itemSettings[tmpId] === 'accept') {
console.log('已订阅')
return
}
// 未订阅后、允许出现订阅面板
this.doSubscribe(tmpId)
},
fail: () => {
// 未订阅后、允许出现订阅面板
this.doSubscribe(tmpId)
}
})
},
doSubscribe (tmpId) {
const _this = this
if(tmpId){
wx.requestSubscribeMessage({
tmplIds: [tmpId],
success (res) {
console.log('接口调用成功的回调函数', res)
const { errMsg } = res
// 若用户点击允许、将文案改成: 已设置订阅
if(errMsg === 'requestSubscribeMessage:ok' && res[tmpId] === 'accept'){
_this.setData({
isSubscribed: true
})
}
// 若用户点击取消、文案不变, 点击再次唤醒订阅面板
},
fail (err) {
console.log('接口调用失败的回调函数', err)
},
complete () {
console.log('接口调用结束的回调函数(调用成功、失败都会执行)')
}
})
}
}
})
5. 总结
- wx.requestSubscribeMessage()必须是同步的、若放在异步操作后请求, 则会提示如下报错: 'can only be invoked by user tap gesture'(只能由用户点击手势调用)
- 若用户勾选了'总是保持以上选择, 不再询问'选项, 那么第二次请求不会再出现订阅面板;
- 用户点击过订阅消息的允许或拒绝, 还不知道如何去清除用户订阅消息授权记录.
6. 写在最后
若有错误之处, 恳请留言, 定会及时更正!
若觉着对您有帮助的话恳请点个赞或着收藏吧!