微信官方为提升小程序模板消息能力的使用体验,对模板消息的下发条件进行了调整。原有的小程序模板消息接口于 2020 年 1 月 10 日下线,届时将无法使用旧的小程序模板消息接口发送模板消息,取而代之的是新的一次性订阅消息和长期订阅消息。
订阅消息给小程序开发者带来了更好的触达用户的能力,在具体实施过程中,开发者如何把模板消息换成新的订阅消息,是否需要购买服务器来实现服务器鉴权,怎样才能在用户订阅之后一段时间后,给用户发送长期或一次性订阅消息呢?
小程序·云开发最近支持了通过云调用免 access_token 发送订阅消息,还新增支持了在定时触发器中实现云调用,这些能力可以帮助开发者轻松玩转小程序订阅消息。
我们今天会利用小程序·云开发进行一个小程序中实现订阅开课提醒的实战,帮助大家了解如何基于小程序·云开发快速接入小程序订阅消息。
整体时序图
环境准备
- 注册小程序帐号
- 开通云开发服务
获取订阅消息模板 ID
在微信小程序管理后台中,新增一个订阅消息的模板,这里我们新增了一个开课提醒的模板。
引导用户订阅
微信小程序提供了wx.requestSubscribeMessage
接口来发起申请订阅权限界面。
在 “ 订阅开课提醒 ” 的按钮上绑定 tap 事件,事件处理器我们这里用的 onSubscribe
index.wxml
<button
class="btn"
data-item="{{item}}"
bindtap="onSubscribe"
hover-class="btn-hover"
>
订阅开课提醒
</button>
在 onSubscribe
函数内,我们会调用微信 API wx.requestSubscribeMessage
申请发送订阅消息权限,当用户在弹窗同意订阅之后,我们会收到 success
回调,将订阅的课程信息调用云函数 subscribe
存入云开发数据库,云函数 subscribe
的实现在下文会讲。
index.js
onSubscribe: function(e) {
// 获取课程信息
const item = e.currentTarget.dataset.item;
// 调用微信 API 申请发送订阅消息
wx.requestSubscribeMessage({
// 传入订阅消息的模板 id,模板 id 可在小程序管理后台申请
tmplIds: [lessonTmplId],
success(res) {
// 申请订阅成功
if (res.errMsg === 'requestSubscribeMessage:ok') {
// 这里将订阅的课程信息调用云函数存入云开发数据
wx.cloud
.callFunction({
name: 'subscribe',
data: {
data: item,
templateId: lessonTmplId,
},
})
.then(() => {
wx.showToast({
title: '订阅成功',
icon: 'success',
duration: 2000,
});
})
.catch(() => {
wx.showToast({
title: '订阅失败',
icon: 'success',
duration: 2000,
});
});
}
},
});
},
将订阅消息存入云开发数据库
接下来我们创建一个云函数 subscribe
,这个云函数的作用是将用户的订阅信息存入云开发数据库的集合 messages
中,等待将来需要通知用户时进行调用。
在微信开发者工具的云开发面板中创建数据库集合 messages
创建一个 subscribe
云函数,在云函数中我们将小程序端发送过来的课程订阅信息,存储在云开发数据库集合中,开发完成后,在微信开发者工具中右键上传并部署云函数。
cloudfunctions/subscribe/index.js
const cloud = require('wx-server-sdk');
cloud.init();
const db = cloud.database();
exports.main = async (event, context) => {
try {const {OPENID} = cloud.getWXContext();
// 在云开发数据库中存储用户订阅的课程
const result = await db.collection('messages').add({
data: {
touser: OPENID, // 订阅者的 openid
page: 'index', // 订阅消息卡片点击后会打开小程序的哪个页面
data: event.data, // 订阅消息的数据
templateId: event.templateId, // 订阅消息模板 ID
done: false, // 消息发送状态设置为 false
},
});
return result;
} catch (err) {console.log(err);
return err;
}
};
利用定时触发器来定期发送订阅消息
接下来我们需要实现一个定时执行的云函数send
,来检查数据库中是否有需要发送给用户的订阅消息。如果有需要发送的订阅消息,会通过云调用 cloud.openapi.subscribeMessage.send
将订阅消息发送给用户。
创建一个名叫 send
的云函数,首先要配置云函数,在 config.json
的 permissions
中新增 subscribeMessage.send
的云调用权限,然后新增一个 sendMessagerTimer
的定时触发器,定时触发器的语法和 linux
的 crontab
类似,比如,我们配置的 "0 * * * * * *"
代表每分钟执行一次云函数。
cloudfunctions/send/config.json
{
"permissions": {"openapi": ["subscribeMessage.send"]
},
"triggers": [
{
"name": "sendMessagerTimer",
"type": "timer",
"config": "0 * * * * * *"
}
]
}
接下来是实现发送订阅消息的云函数,这个云函数会从云开发数据库集合 messages
中查询等待发送的消息列表,检查数据库中是否有需要发送给用户的订阅消息,发送条件可以根据自己的业务实现,比如开课提醒可以根据课程开课日期来检查是否需要发送订阅消息,在我们下面的代码示例里做了简化,筛选条件只检查了状态为未发送。
查询到待发送的消息列表之后,我们会循环消息列表,依次发送每条订阅消息,发送成功后将数据库中消息的状态改为已发送。
cloudfunctions/send/index.js
const cloud = require('wx-server-sdk');
exports.main = async (event, context) => {cloud.init();
const db = cloud.database();
try {
// 从云开发数据库中查询等待发送的消息列表
const messages = await db
.collection('messages')
// 查询条件这里做了简化,只查找了状态为未发送的消息
// 在真正的生产环境,可以根据开课日期等条件筛选应该发送哪些消息
.where({done: false,})
.get();
// 循环消息列表
const sendPromises = messages.data.map(async message => {
try {
// 发送订阅消息
await cloud.openapi.subscribeMessage.send({
touser: message.touser,
page: message.page,
data: message.data,
templateId: message.templateId,
});
// 发送成功后将消息的状态改为已发送
return db
.collection('messages')
.doc(message._id)
.update({
data: {done: true,},
});
} catch (e) {return e;}
});
return Promise.all(sendPromises);
} catch (err) {console.log(err);
return err;
}
};
最终效果
源代码
https://github.com/binggg/tcb-subscribe-demo
关于我
binggg(Booker Zhao) @腾讯
- 先后就职于迅雷、腾讯等,个人开源项目有 mrn.js 等
- 创办了迅雷内部组件仓库 XNPM,参与几个迅雷前端开源项目的开发
- 热衷于优化和提效,是一个奉行“懒惰使人进步”的懒人工程师
社交资料
- ???? GitHub: https://github.com/binggg
- ???? 简书: https://www.jianshu.com/u/60f22559b79f
- ???? 掘金: https://juejin.im/user/58d31f130ce4630057edb3ba
- ????️????️ 微博: https://weibo.com/being99
- ???? 思否: https://segmentfault.com/u/binggg
- ???? 博客园: https://www.cnblogs.com/binggg/
- ???? 开源中国: https://my.oschina.net/u/4217267
- ???? 极术社区: https://aijishu.com/u/binggg
- ???? 今日头条: https://www.toutiao.com/c/user/102306299647
- ????CSDN: https://blog.csdn.net/weixin_42541867
微信公众号 binggg_net
, 欢迎关注