前言
最近用uniapp云开发搞了个小程序,大部分功能都已经实现了,结果卡死在了订阅消息这个功能上,由于订阅是前端实现,发送是后端实现,而uniapp云开发里面又单独封装了一个公共模块供开发者使用,所以导致文档看起来就很乱,不知道该看哪个了。
经过反复研究和沸点JYM给的思路,算是将这个功能完成了,接下来就把实现过程和踩过的坑记录一下,也给大家一个参考。
★
这里只讲解uniapp云开发中的公共模块
uni-subscribemsg
的使用,主要结合云开发去实现,不使用其他后端。”
uni-subscribemsg 公共模块
这个公共模块将微信公众号模板消息、微信小程序订阅消息都封装起来了,可以很方便的使用云函数/云对象去操作发送。
点击进入 uni-subscribemsg 公共模块 插件地址
按照一般的思路,我们会在云函数中直接请求微信服务端接口
POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN
// 在云函数中请求微信服务端API(发送订阅消息)
const sendMsg = await uniCloud.httpclient.request(
"https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + access_token, {
method: "POST",
...
});
通过引入公共模块之后,就可以直接使用公共模块中的方法去发送订阅消息
// 引入uni-subscribemsg公共模块
const UniSubscribemsg = require('uni-subscribemsg');
// 初始化实例
let uniSubscribemsg = new UniSubscribemsg({
dcloudAppid: "你项目的dcloudAppid",
provider: "weixin-mp",
});
// 发送订阅消息
let res = await uniSubscribemsg.sendSubscribeMessage({
touser: "用户openid",
template_id: "消息模板id",
page: "pages/index/index", // 小程序页面地址
miniprogram_state: "developer", // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
lang: "zh_CN",
data: {
name1: {
value: "张三"
},
time2: {
value: "2023-12-21 15:30:20"
}
}
});
基础部分已说明,公共模块中的代码会在云函数/云对象中进行说明
获取公共模块中的参数
dcloudAppid: “你项目的dcloudAppid”
此参数在uniCloud后台获取点击进入uniCloud后台
-
列表中的Appid即为此参数的值
template_id: “消息模板id”
此参数在小程序后台获取点击进入小程序后台
-
侧边栏选择订阅消息
-
在我的模板中点击右侧
选用
按钮
-
右侧搜索
签到
就会出现类似的订阅模板了,直接选用你想要的就可以了 -
你可以搜索其他关键词,和你的小程序类目相关即可
-
添加好模板之后,在模板列表中就会出现一个模板ID,复制下来,粘贴到发送消息的参数位置
touser: “用户openid”
此参数在用户登录时获取,可以参考我写的这篇文章。使用 Uniapp + UniCloud 云开发微信小程序获取用户信息
建表
★
根据自己的需求建立
用户表
、签到表
等,下面只介绍消息订阅表
”
-
在项目 – uniCloud – database上右键,新建 DB Schema
// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema
{
"bsonType": "object",
"required": [],
"permission": {
"read": false,
"create": false,
"update": false,
"delete": false
},
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"user_id": {
"title": "关联用户表中的id,订阅者",
"bsonType": "string",
"trim": "both"
},
"openid": {
"title": "微信openid",
"bsonType": "string",
"trim": "both"
},
"state": {
"title": "订阅状态",
"bsonType": "int",
"trim": "both",
"defaultValue": 1,
"enum": [{
"text": "正常",
"value": 1
}
],
"description": "过滤掉非正常的用户,方便发送订阅消息"
},
"type": {
"title": "类型",
"bsonType": "int",
"trim": "both",
"enum": [{
"text": "签到",
"value": 1
}
]
}
}
}
-
具体字段可以根据自己的需要去修改
-
新建完成后,右键即可上传至云空间了
-
云空间中有了这张表之后,就表示创建完成了。
用户触发订阅消息
-
当用户签到完成后,弹出订阅框(如果用户没有勾选“总是保持以上选择,不再询问”,则每次签到都会弹出)
-
用户订阅成功之后,将订阅状态存入表中(上面新建的用户订阅表),方便发送时获取openid
const _this = this
// 弹出签到提醒的订阅消息,让用户订阅
uni.requestSubscribeMessage({
tmplIds: [""wb0SXQ86lR*****************liHZ7Y"],
success: (res) => {
// 判断是否订阅了
if (res["wb0SXQ86lR*****************liHZ7Y"] === 'accept') {
// 订阅之后,就得将此用户信息记录下来,方便后续发送订阅消息
uniCloud.callFunction({
name: 'a_subscribe_sign',
data: {
action: 'setSubscribeUserInfo',
user_id: _this.user._id,
openid: _this.user.openid,
state: 1, // 正常
type: 1 // 签到
},
success: (res) => {
uni.showToast({
title: '订阅成功',
icon: 'success'
})
},
fail: () => {
uni.showToast({
title: '订阅失败',
icon: 'error',
duration: 2000
})
}
})
}
}
});
-
用 * 号加密的部分是微信后台自己添加的订阅模板ID哦!
-
其他参数根据自己的需求去获取即可。
云对象发消息
新建云对象
-
在项目 – uniCloud – cloudfunctions目录上右键 – 新建云函数/云对象
-
在弹出框里面选择
云对象
-
输入云对象名称
-
点击
添加公共模块或扩展库依赖
-
管理扩展库中选择
uni-subscribemsg
公共模块
-
新建完成后,就可以在目录中看到新建的云对象了
// 一个空的云对象代码
module.exports = {
_before: function() {
}
}
云对象定时发送
★
由于签到的订阅消息是在用户订阅之后,每天都会发送的,所以需要给一个定时任务,便于每天定时触发
”
★
注意:下面的操作均在DCloud控制台中完成
”
-
根据图片中的步骤说明,找到对应的云对象,点击后面的 详情 按钮
-
进入详情页后,找到 定时器触发 模块,点击 编辑 按钮
["0 0 18 * * *"]
-
将上面这个数组复制进去即可
-
表示 每天下午六点整 准时触发
★
如需修改定时器时间,可以点击查看定时器文档
”
定时任务方法
-
在uniCloud中,给云对象内置了一个定时触发的方法
module.exports = {
_timing: function () {
console.log('triggered by timing')
}
}
-
_timing
就是内置的定时触发方法
接下来,我们就可以把发送订阅消息的代码复制进来了,引入模块的内容放在module.exports
外层。
此处的源码就是上面介绍公共模块时的代码,稍加修改即可。
// 云对象教程: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj
// jsdoc语法提示教程:https://ask.dcloud.net.cn/docs/#//ask.dcloud.net.cn/article/129
// 引入uni-subscribemsg公共模块
const UniSubscribemsg = require('uni-subscribemsg');
// 初始化实例
let uniSubscribemsg = new UniSubscribemsg({
dcloudAppid: "__U*******B9", // https://dev.dcloud.net.cn/pages/app/list
provider: "weixin-mp",
});
// 这里是签到定时任务
// 会定时推送微信订阅消息给用户
module.exports = {
_before: function() { // 通用预处理器
},
// 定时触发内置方法
_timing: async function() {
// 发送订阅消息
let res = await uniSubscribemsg.sendSubscribeMessage({
touser: "olhn80For3o23OrxC*********", // 用户openid
template_id: "wb0SXQ86lRoa*************liHZ7Y", // 消息模板id
page: "pages/login/login", // 小程序页面地址
miniprogram_state: "trial", // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
lang: "zh_CN",
data: { // 模板参数
phrase6: {
value: "未签到"
},
thing2: {
value: "签到最高可获得20积分哦~"
},
time3: {
value: "2019年10月1日 15:01:01"
},
thing5: {
value: "点击去签到"
}
}
});
}
}
-
源码中加了 * 号的都是需要自己定义的内容,均在上文中有讲解说明
★
订阅消息中的 data 对象中的内容,需要和订阅消息模板中的内容保持一致。(此处有不明白的,可以评论中提问)
”
此时就可以等待下午六点
准时触发定时任务后下发订阅通知
云函数发消息
★
由于云对象中无法调用云函数(获取用户openid)的接口,所以放弃了使用云对象下发定时任务的方法
”
新建云函数
-
和新建云对象是一样的,只是选项不同哦!
-
新建云函数的时候同样需要引入公共模块
云函数定时发送
在云函数中,也有一种方法去判断定时任务,通过云函数自带的 context
字段
exports.main = async (event, context) => {
let source = context.SOURCE // 当前云函数被何种方式调用
// client 客户端callFunction方式调用
// http 云函数url化方式调用
// timing 定时触发器调用
// server 由管理端调用,HBuilderX里上传并运行
// function 由其他云函数callFunction调用
}
-
会根据
source
最终的值去判断是否为定时任务触发的
let source = context.SOURCE // 云函数调用来源
// 判断来源是否为定时任务触发调用
if (source === 'timing') {
// 这里面就是云对象中定时任务方法里面的代码,复制进来即可
}
动态获取用户openid
根据建表时定义的字段,我们可以将state
和type
作为查询参数
const db = uniCloud.database();
// 获取 `a-subscribe-user` 集合的引用(定于用户表)
const a_subscribe_sign = db.collection('a-subscribe-user');
// 循环判断客户端传递过来的 action
// 通过 action 判断请求对象
let result = {};
switch (event.action) {
// setSubscribeUserInfo用户触发订阅时的方法,添加到订阅用户表中
case 'setSubscribeUserInfo':
const res_sign = await a_subscribe_sign.add({
user_id: event.user_id,
openid: event.openid,
state: event.state,
type: event.type
})
break;
// getAllOpenId获取所有订阅的openid
case 'getAllOpenId':
// 获取所有正常用户的openid
// 用于发送订阅消息
const res_all_val = await a_subscribe_sign.where({
state: 1,
type: 1
}).get()
return res_all_val.data
}
将方法定义好之后,我们就可以在定时任务判断逻辑中引用了。
云函数完整代码
★
下面是云函数的所有代码,可以根据注释进行理解
”
'use strict';
exports.main = async (event, context) => {
//event为客户端上传的参数
// console.log('event : ', event)
const db = uniCloud.database();
// 获取 `a-subscribe-user` 集合的引用(定于用户表)
const a_subscribe_sign = db.collection('a-subscribe-user');
// 条件查询必备语法
// const dbCmd = db.command
// 循环判断客户端传递过来的 action
// 通过 action 判断请求对象
let result = {};
switch (event.action) {
case 'setSubscribeUserInfo':
const res_sign = await a_subscribe_sign.add({
user_id: event.user_id,
openid: event.openid,
state: event.state,
type: event.type
})
break;
case 'getAllOpenId':
// 获取所有正常用户的openid
// 用于发送订阅消息
const res_all_val = await a_subscribe_sign.where({
state: 1,
type: 1
}).get()
return res_all_val.data
break;
}
// 引入uni-subscribemsg公共模块
const UniSubscribemsg = require('uni-subscribemsg');
// 初始化实例
let uniSubscribemsg = new UniSubscribemsg({
dcloudAppid: "__UNI__C40B1B9", // https://dev.dcloud.net.cn/pages/app/list
provider: "weixin-mp",
});
let source = context.SOURCE // 云函数调用来源
// 判断来源是否为定时任务触发调用
if (source === 'timing') {
console.log('获取用户信息')
let callFunctionResult = await uniCloud.callFunction({
name: "a_subscribe_sign",
data: {
action: 'getAllOpenId'
}
})
console.log('callFunctionResult*****', callFunctionResult.result)
// 获取到所有数据后,循环拿出openid
let openids = []
for (let i in callFunctionResult.result) {
openids.push(callFunctionResult.result[i].openid)
}
// 过滤掉重复的openid
openids = [...new Set(openids)]
// 获取时间,并格式化
function formatDate(date, cut) {
var date = new Date(date);
var YY = date.getFullYear() + cut;
var MM =
(date.getMonth() + 1 < 10 ?
"0" + (date.getMonth() + 1) :
date.getMonth() + 1) + cut;
var DD = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
var hh =
(date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":";
var mm =
(date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) +
":";
var ss = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
return YY + '年' + MM + '月' + DD + '日' + " " + hh + mm + ss;
}
console.log('我是定时任务!', openids)
// 循环发送订阅消息(给所有获取到的openid)
for (let i in openids) {
// 发送订阅消息
let res = await uniSubscribemsg.sendSubscribeMessage({
touser: openids[i], // 用户openid
template_id: "wb0SXQ86lRoaJO8j4DxheOKpgVUuw-iER-gDRliHZ7Y", // 消息模板id
page: "pages/login/login", // 小程序页面地址
miniprogram_state: "trial", // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
lang: "zh_CN",
data: { // 模板参数
phrase6: {
value: "未签到"
},
thing2: {
value: "签到最高可获得20积分哦~"
},
time3: {
value: formatDate()
},
thing5: {
value: "点击去签到"
}
}
});
console.log('订阅消息打印一下****', res)
}
}
//返回数据给客户端
// return event
};
总结
由于微信小程序订阅消息的限制,无法一次性批量触发,只能通过循环获取openid的方式去给每个用户发送。
由于uniapp云对象的限制,有些逻辑只能放在云函数里面,如果有更好的云对象操作方法,可以在评论区讨论一下,毕竟云对象我觉得相对于云函数来说是比较简单的。
原文始发于微信公众号(猿来是前端):【订阅消息】uniapp云开发给订阅用户发送微信小程序订阅消息(实战 + 踩坑)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/250299.html