微信小程序之订阅消息推送(基于微信云开发)

2,360 阅读4分钟

最近自己开发了一款微信小程序,其中包含了一项比较重要关键的功能就是订阅消息的推送。

推送这一块挺绕的,想将我自己的开发过程写下来。给大家作个参考,少踩一些踩坑。

微信小程序的订阅消息使用规范需要仔细阅读,相关文档:developers.weixin.qq.com/miniprogram…

准备条件

  1. 审核通过的微信小程序账号 * 1
  2. 已选好的模板 * 1
  3. 可用的微信云开发环境 * 1
  4. 已对接云开发的微信小程序 * 1

开发前的考虑

由于博主的小程序是商品比价类小程序,不属于公共服务类的小程序,所以只能选择一次性订阅消息。所以博主将订阅交互设计成了:用户来点击订阅按钮,积累发送消息次数,随后程序根据所记录的次数进行消息发送。发送成功后对次数进行修改。

开始开发

(一)创建云数据库

用来存储用户的openid与发送次数

openid决定了将订阅消息发送给哪一位用户,所以我们有必要在数据库中存入需要接收订阅消息的用户信息

image.png

创建相关数据的增改查接口

云数据库操作相关文档:developers.weixin.qq.com/miniprogram…

*添加次数
export const addTimes = ({ openid, days }) => {
  return new Promise((resolve, reject) => {
    const db = wx.cloud.database()
    db.collection('order_users').add({
      data: {
        openid,
        days
      },
      ...
    })
  })
}

*修改次数
export const updateTimes = ({ openid, days }) => {
  return new Promise((resolve, reject) => {
    const db = wx.cloud.database()
    db.collection('order_users').where({
      _openid: openid 
    }).update({
      data: {
        days
      }
      ...
    })
  })
}

定义完成数据库操作函数,我们通过程序往数据库里添加数据

image.png

保证数据库里的数据正确无误,我们下一步在云函数中编写模板消息发送功能相关的代码

(二)创建云函数

用来发送模板消息

// 云函数入口文件
const cloud = require('wx-server-sdk')

// 我们在这里初始化数据库
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV,
})
const db = cloud.database()

const MAX_LIMIT = 100
// 用于发送用户的openid获取
let USER_INDEX = 0
// 模板消息id,在小程序后台中的订阅消息获取
const TEMPLATE_ID = '8DQSjUQL...'

// 获取已经订阅的用户数据
const getUserData = () => {
  // 由于一次性获取数据库数量有限,所以我们要分多次promise,最终一次请求,获取全部数据
  return new Promise(async (resolve, reject) => {
    const countResult = await db.collection('order_users').count()
    const total = countResult.total

    const batchTimes = Math.ceil(total / 100)

    const tasks = []
    for (let i = 0; i < batchTimes; i++) {
      const promise = db.collection('order_users').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()
      tasks.push(promise)
    }

    // 等待所有
    let returnData = (await Promise.all(tasks)).reduce((acc, cur) => {
      return {
        data: acc.data.concat(cur.data),
        errMsg: acc.errMsg,
      }
    })

    resolve(returnData)
  })
}

// 云函数入口函数
exports.main = async (event, context) => {
  let users = []
  
      // 定义发送订阅消息函数
  const handleSend = () => {
    cloud.openapi.subscribeMessage.send({
      "touser": users[USER_INDEX]._openid,
      "page": '/pages/home/home', // 点击订阅消息时,打开的页面路径
      "lang": 'zh_CN',
      "data": {
        "thing1": {
          "value": '优惠通知'
        },
        "thing3": {
          "value": '点击查看详情'
        },
      },
      "templateId": TEMPLATE_ID,
      "miniprogramState": 'trial'
    }).then(() => {
        // 获取用户订阅剩余次数
      let afterDays = users[USER_INDEX].days -= 1

        // 如果是最后一次发送了,就删除该记录
      if (afterDays === 0) { 
        return db.collection('order_users').where({
          _openid: users[USER_INDEX]._openid
        }).remove()
      } else {
          // 如果不是,则次数-1,更新数据
        return db.collection('order_users').where({
          _openid: users[USER_INDEX]._openid
        }).update({
          data: {
            days: afterDays
          }
        })
      }
    }).then(() => {
        // 发送成功!则对下一个用户发送
      USER_INDEX += 1
        
        // 如果index值,小于用户数组,说明没有发送完,仍需要继续发送
      if (USER_INDEX < users.length) {
        handleSend()
      }
    }).catch((err) => {
        // 发送失败,跳过此用户,对下一个用户发送
      USER_INDEX += 1

      if (USER_INDEX < users.length) {
        handleSend()
      }
    })
  }

  getUserData().then(res => {
      // 获取用户数据成功,先设置用户数据,随后执行发送消息函数: handleSend()
    users = res.data
    handleSend()
  })

}

定义完成后,我们上传云函数

image.png

等等,我们忘了一件事情

我们该如何进行程序编写,才能够让这个消息指定时间执行呢?

这里面我们用到了触发器,触发器可以定义云函数的执行时间,到点自动执行

触发器:developers.weixin.qq.com/miniprogram…

打开云函数文件夹下的config.json,我们定义触发器

{
  "permissions": {
    "openapi": [
      
    ]
  },
  "triggers": [
    {
      "name": "myTrigger",
      "type": "timer",
      "config": "0 0 19 * * * *" // 每天19:00执行
    }
  ]
}

最后还差一件事

定义openapi,否则功亏一篑

{
  "permissions": {
    "openapi": [
      "templateMessage.send" // 我们使用了开放能力:模板消息发送。在这里定义值
    ]
  },
  "triggers": [
    {
      "name": "myTrigger",
      "type": "timer",
      "config": "0 0 19 * * * *"
    }
  ]
}

相关文档:developers.weixin.qq.com/miniprogram…

最后上传触发器即可

写在最后

以上内容是博主开发的一款微信小程序后总结下来的经验。

小程序在这里,欢迎大家扫码体验这款小程序!

gh_c67a1654313d_430 (1).jpg