热爱摄影的程序员
喜欢编码的设计师
擅长设计的剪辑师
一位高冷无情的编码爱好者
大家好,我是全栈 IT 工程师摘星人
欢迎分享 / 收藏 / 赞 / 在看!
开发业务时时常遇到需要向用户发送一些通知,如欠费通知、会员到期通知等等。
这里使用官方提供的 uni-subscribemsg 公共模块实现推送功能
uni-subscribemsg 公共模块可以方便开发者快速接入小程序订阅消息和微信公众号模板消息。
目前 uni-subscribemsg 支持:
uni-subscribemsg 公共模块仅能在云函数/云对象内使用。
uni-subscribemsg 插件市场地址
如果觉得模板不好用,可以自己添加提交审核成功后就可以使用。
进入 微信小程序后台 - 点击【订阅消息】- 点击【公共模板库】- 点击【选用】。
这里的【模板ID】后面会使用到。
点击详情来到模板详情页面,注意这里的字段对应关系,后面会进行赋值操作。
进入 微信公众号后台 - 点击【模板消息】- 点击【从历史模板库中添加】。
uni-subscribemsg 自身没有配置文件,其依赖 uni-open-bridge 的配置。
这里简单列出如何配置使用的步骤,详细内容请点击:官网 uni-open-bridge
uni-open-bridge 插件市场地址
如果没有appid 和 secret ,需要先向微信申请
然后在项目的 uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json 文件中配置
如果不需要定时刷新 access_token、ticket、也不需要通过外部系统访问凭据时可单独引入 uni-open-bridge-common,然后在云函数或云对象中直接调用相关方法
// uni-id-config 中 uni-id 示例代码
// uniCloud/cloudfunctions/common/uni-config-center/uni-id/config.json
{
"dcloudAppid": "__UNI__xxxxxx", // 在项目的 manifest.json 中
"mp-weixin": { // 微信小程序
"tokenExpiresIn": 259200,
"oauth": {
"weixin": {
"appid": "", // 微信公众平台申请的小程序 appid
"appsecret": "" // 微信公众平台申请的小程序 secret
}
}
},
"web": {
"oauth": {
"weixin-h5": { //微信公众号h5
"appid": "", // 微信公众平台申请的网页授权 appid
"appsecret": "" // 微信公众平台申请的网页授权 secret
}
}
}
}
在 weixin-mp、weixin-h5 平台,通过调用 uni-open-bridge-common 的get相关方法可自动从微信服务器获取 access_token、encrypt_key、ticket 时需要用到配置文件中的 appid、appsecret
暂时不需要配置 weixin-web、weixin-app、qq-mp、qq-app,后续支持这些平台时需要再次补充配置,但仍然可通过调用 uni-open-bridge-common 的方法传入设置值
注意:拷贝此文件内容时需要移除 注释。标准 json 不支持注释。在 HBuilderX 中可用多选 // 来批量移除注释。
在 uni-config-center 目录下新建子目录 uni-open-bridge, 新增 config.json,配置 dcloudAppid ,详情见下面的示例代码
// uni-id-config 中 uni-open-bridge 示例代码
// uniCloud/cloudfunctions/common/uni-config-center/uni-open-bridge/config.json
{
"schedule": {
"__UNI__xxxxxx": { // dcloudAppid, 需要和 `uni-config-center` uni-id中的配置一致
"enable": true, // 任务全局开关,优先级最高
"weixin-mp": { // 平台,目前仅支持 微信小程序、微信 H5,详情参见 https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#platform
"enable": true, // 当前平台任务开关
"tasks": ["accessToken"] // 要执行的任务,微信小程序支持 accessToken
},
"weixin-h5": {
"enable": false,
"tasks": ["ticket"] // 支持微信 H5 ticket,因 ticker 依赖微信 H5 accessToken,内部自动先获取 accessToken。此处的 accessToken 和微信小程序的 accessToken 不是一个值
}
}
},
"ipWhiteList": ["0.0.0.0"] // 用于 URL化后 http 调用的服务器IP白名单,即指定ip的服务器才可以访问URL化后的`uni-open-bridge云对象
}
云对象 uni-open-bridge 上传到服务空间后,会每隔一个小时自动运行一次,从微信服务器获取相关凭据并保存到数据库。
在数据库 opendb-open-data 中会看到数据。如开通 Redis 则在 Redis 的 uni-id 分组中查看。
如果异常,请在 uniCloud Web 控制台,找到云函数/云对象 uni-open-bridge 检查运行日志。很可能是第一步或第二步的配置出错了。
当然如果不需要定时任务,可以修改云对象 package.json 里的定时任务配置并重新上传。或在 uniCloud web 控制台修改定时任务。一般不推荐修改定时任务设置。
注意:
如需获取微信公众号 H5 平台的 access_token,需要处理服务空间的固定出口 IP 问题。因为需将 IP 白名单填入到微信公众平台,然后才能在从微信服务器拿到该凭据。uniCloud 中默认没有固定 IP,获取固定 IP 需另见文档 固定 IP。
笔者使用云对象操作,新建云对象后,右击【管理公共模块或扩展库依赖】,在弹出的窗口上将【uni-subscribemsg】钩上,点击确定。
可以根据官方提供的 API 实现不同的订阅需求
订阅消息顾名思义,需要先订阅,才可以发送消息,因此前端需要先让用户订阅。
调用 uni.requestSubscribeMessage API 即可让用户订阅。
uni.requestSubscribeMessage({
tmplIds: ["xxx"], // 改成你的小程序订阅消息模板id
success: () => {
uni.showToast({
title: "订阅成功",
icon: "none"
})
}
});
const dcloudAppid = '__UNI__xxx'
// 引入uni-subscribemsg公共模块
const UniSubscribemsg = require('uni-subscribemsg');
module.exports = {
_before: function() {},
/**
* 获取openid
* @param {Object} code
*/
async getOpenid(code) {
// 初始化实例
let uniSubscribemsg = new UniSubscribemsg({
dcloudAppid: dcloudAppid,
provider: "weixin-mp",
});
return await uniSubscribemsg.getOpenid({
code: code
})
},
/**
* 发送订阅消息
* @param {Object} obj
*/
async sendSubscribeMessage(obj) {
let {
touser, // 接收者(用户)的 openid
template_id, // 所需下发的订阅模板id
page, // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
data, // 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
miniprogram_state, // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
} = obj;
// 初始化实例
let uniSubscribemsg = new UniSubscribemsg({
dcloudAppid: dcloudAppid,
provider: "weixin-mp",
});
// 发送订阅消息
let res = await uniSubscribemsg.sendSubscribeMessage({
touser: touser,
template_id: template_id,
page: page, // 小程序页面地址
miniprogram_state: miniprogram_state, // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
lang: "zh_CN",
data: data
});
return res;
},
}
<template>
<view>
<u-button @click="getOpenid">获取openid</u-button>
<u-button @click="sendSubscribeMessage">订阅</u-button>
</view>
</template>
<script>
const mjchPush = uniCloud.importObject('mjch-subscribe-push')
export default {
data() {
return {
code: '',
form: {
touser: '', // 接收者(用户)的 openid
template_id: 'xxx', // 所需下发的订阅模板id
page: '/pages/index/index', // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转。
data: {
// 活动名称
thing11: {
value: "“舞蹈杯”全国舞蹈大赛"
},
// 活动内容
thing4: {
value: "点击即可抢红包,最高可得200元红包"
},
// 活动开始
date2: {
value: "2023-01-01 20:00"
},
// 活动截止
date3: {
value: "2023-01-31 20:00"
},
// 温馨提示
thing5: {
value: "活动即将开始,请做好准备"
}
}, // 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
miniprogram_state: "developer", // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
}
};
},
async onLoad() {
this.login()
},
methods: {
/**
* 登录获取code
*/
async login() {
let that = this
uni.login({
provider: 'weixin',
success: function(res) {
that.code = res.code
}
});
},
/**
* 根据code获取openid
*/
async getOpenid() {
mjchPush.getOpenid(this.code).then(res => {
const openid = res.openid
const session_key = res.session_key
this.form.touser = openid
}).catch(err => {
console.log(err);
})
},
/**
* 返送订阅消息
*/
async sendSubscribeMessage() {
mjchPush.sendSubscribeMessage(this.form).then(res => {
console.log('res', res);
}).catch(err => {
console.log(err);
})
}
}
}
</script>
<style lang="scss">
</style>
请求参数:
属性 | 类型 | 必填 | 说明 |
---|---|---|---|
touser | string | 是 | 接收者(用户)的 openid |
template_id | string | 是 | 所需下发的订阅模板id |
page | string | 否 | 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转 |
miniprogram_state | string | 是 | 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版 |
lang | string | 是 | 进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为 |
data | string | 是 | 模板内容,格式形如 { “key1”: { “value”: any }, “key2”: { “value”: any } }的object |
返回参数:
参数 | 说明 |
---|---|
errCode | 为0代表发送成功,其他均为失败,与微信公众号官方返回码一致 微信公众号全局返回码 |
errMsg | 失败后的提示 ,与微信公众号官方错误提示一致 |
// 引入uni-subscribemsg公共模块
const UniSubscribemsg = require('uni-subscribemsg');
// 初始化实例
let uniSubscribemsg = new UniSubscribemsg({
dcloudAppid: "你项目的dcloudAppid",
provider: "weixin-h5", // 注意,这里是weixin-h5
});
// 发送模板消息
let res = await uniSubscribemsg.sendTemplateMessage({
touser: "用户openid",
template_id: "消息模板id",
url: "https://uniapp.dcloud.net.cn", // 用户点击消息后跳转的链接地址
data: {
first: {
value: "您购买的套餐已到期!",
color: "#666666"
},
keyword1: {
value: "[email protected]",
color: "#666666"
},
keyword2: {
value: "阿里云空间",
color: "#666666"
},
keyword3: {
value: "2023-12-21 15:30:20",
color: "#666666"
},
remark: {
value: "请及时续费",
color: "#666666"
}
}
});
请求参数:
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
touser | String | 是 | 接收者openid |
template_id | String | 是 | 模板ID |
url | String | 否 | 模板跳转链接(海外帐号没有跳转能力) |
miniprogram | Object | 否 | 跳小程序所需数据,不需跳小程序可不用传该数据 |
– appid | String | 是 | 所需跳转到的小程序appid(该小程序 appid 必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏) |
– pagepath | String | 否 | 所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏 |
data | Object | 是 | 模板数据 |
color | String | 否 | 模板内容字体颜色,不填默认为黑色 |
client_msg_id | String | 否 | 防重入id。对于同一个openid + client_msg_id, 只发送一条消息,10分钟有效,超过10分钟不保证效果。若无防重入需求,可不填 |
返回参数:
参数 | 说明 |
---|---|
errCode | 为0代表发送成功,其他均为失败,与微信公众号官方返回码一致 微信公众号全局返回码 |
errMsg | 失败后的提示 ,与微信公众号官方错误提示一致 |
uni-subscribemsg 版本需 ≥ 1.0.2
// 引入uni-subscribemsg公共模块
const UniSubscribemsg = require('uni-subscribemsg');
// 初始化实例
let uniSubscribemsg = new UniSubscribemsg({
dcloudAppid: "你项目的dcloudAppid",
provider: "weixin-mp", // 注意,这里是weixin-mp
});
// 发送模板消息
let res = await uniSubscribemsg.sendTemplateMessage({
touser: "用户openid",
template_id: "消息模板id",
appid: "公众号appid",
miniprogram: {
appid: "小程序appid",
pagepath: "pages/index/index", // 小程序页面
},
data: {
first: {
value: "您购买的套餐已到期!",
color: "#666666"
},
keyword1: {
value: "[email protected]",
color: "#666666"
},
keyword2: {
value: "阿里云空间",
color: "#666666"
},
keyword3: {
value: "2023-12-21 15:30:20",
color: "#666666"
},
remark: {
value: "请及时续费",
color: "#666666"
}
}
});
请求参数
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
touser | String | 是 | 接收者openid(用户在该小程序下对应的openid) |
appid | String | 否 | 微信公众号appid(不传会自动从uni-id配置中获取) |
miniprogram | Object | 否 | 跳小程序所需数据,不需跳小程序可不用传该数据 |
appid | String | 是 | 所需跳转到的小程序appid(该小程序 appid 必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏) |
pagepath | String | 否 | 所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),要求该小程序已发布,暂不支持小游戏 |
data | Object | 是 | 模板数据 |
color | String | 否 | 模板内容字体颜色,不填默认为黑色 |
返回参数:
参数 | 说明 |
---|---|
errCode | 为0代表发送成功,其他均为失败,与微信公众号官方返回码一致 微信公众号全局返回码 |
errMsg | 失败后的提示 ,与微信公众号官方错误提示一致 |
注意:公众号和小程序无需绑定在同一个开放平台下,但需要同时满足下面的3个要求。
uni-subscribemsg 版本需 ≥ 1.0.1
// 引入uni-subscribemsg公共模块
const UniSubscribemsg = require('uni-subscribemsg');
// 初始化实例
let uniSubscribemsg = new UniSubscribemsg({
dcloudAppid: "你项目的dcloudAppid",
provider: "weixin-h5",
});
// 检测用户是否关注了公众号
let res = await uniSubscribemsg.getSubscribeUserInfo({
openid
});
请求参数:
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
openid | String | 是 | 用户openid |
返回参数:
参数 | 说明 |
---|---|
errCode | 为0代表发送成功,其他均为失败,与微信公众号官方返回码一致 微信公众号全局返回码 |
errMsg | 失败后的提示,与微信公众号官方错误提示一致 |
subscribe | true 已关注公众号 false 未关注公众号 |
result | 用户基本信息返回值 |