小程序 · 云开发实战:搭建小程序订阅消息系统

1,554 阅读6分钟

消息能力是小程序能力中的重要组成部分,微信官方提供了订阅消息能力,以便实现开发者实现服务的闭环和更优的体验。可以支持在用户自主订阅后,推送消息到用户端(服务通知),用户点击查看详情可跳转至小程序的页面,实现服务的闭环,提高活跃度和用户粘性

本次课程会演示如何使用云开发快速为小程序加入订阅消息能力,在实战环节会带领大家搭建一个具备用户订阅、消息去重、定时发送、用户退订等订阅消息管理能力的开课提醒小程序,学习完成后同学们将掌握:

  • 云调用调用微信开放能力相比传统模式有哪些优点
  • 如何基于云开发快速接入小程序订阅消息
  • 如何结合云开发的云函数、定时触发器、数据库和云调用开发完整的功能

基础知识点

小程序·云开发介绍

“小程序·云开发”由微信团队和腾讯云联合打造的“应用服务中台”,秉承高效、易用、安全、低成本的服务理念,整合了微信公众平台和腾讯云的核心技术,提供云数据库、云存储、云函数、日志和监控等开发运维能力。通过“小程序·云开发”,开发者可无缝安全调用小程序的开放服务,提升开发效率,快速试错和落地产品。

订阅消息介绍

微信官方提供了订阅消息能力,以便实现开发者实现服务的闭环和更优的体验。可以支持在用户自主订阅后,推送消息到用户端(服务通知),用户点击查看详情可跳转至小程序的页面,实现服务的闭环,提高活跃度和用户粘性

准备工作

准备小程序账号和开发工具

温馨提示:本次的实战的案例里用到了**“订阅课程开课提醒”** 这个订阅消息模板,需要小程序服务类目里包含 “教育 > 在线教育”,可以在服务类目中加入此类目。后续生产环境中可根据自己的场景选择合适的服务类目和订阅消息模板。

  1. 已经申请微信小程序(在服务类目中加入**“教育 > 在线教育”**),获取小程序 AppID

  2. 下载 开发版 微信开发者工具( Nightly Build (Windows 64Windows 32macOS))

  3. 在微信公共平台的 "订阅消息"中申请一个开课提醒订阅消息模板,获得消息模板ID,字段的内容和顺序需要按下图所示:

    在这里插入图片描述

下载并导入初始项目的源代码

此次活动的项目源代码压缩包可关注公众号 [微信极客WeGeek] 回复"订阅消息"获得。解压源代码压缩包后,可以看到 “第六期课程资料”⽂件夹下有两个⽂件夹,分别为 init(此次活动的实战初始代码)和 intact(完成后的完整代码)。

点击开发者工具工具栏项目-导入项目,项目名称可以任意填写比如“小程序订阅消息系统”,项目路径为之前解压出来的 “第六期课程资料”文件夹里面的 init 文件夹,AppID 使用之前准备好的小程序 AppID

配置项目

  1. 打开云开发控制台,在数据库管理页新建⼀个 messages 集合。
  2. 修改 pages/index/index 里面的 lessonTmplId 变量的值为准备好的消息模板ID
    在这里插入图片描述

了解本次实战的整体流程图

在这里插入图片描述

搭建步骤

小程序前端实现订阅和退订交互

在这里插入图片描述
打开 miniprogram/pages/index/index.js,在“@todo 实现订阅逻辑” 下方粘贴如下代码:

    // 获取课程信息
    const item = e.currentTarget.dataset.item;

    // 调用微信 API 申请发送订阅消息
    wx.requestSubscribeMessage({
      // 传入订阅消息的模板id,模板 id 可在小程序管理后台申请
      tmplIds: [lessonTmplId],
      success(res) {
        // 申请订阅成功
        if (res.errMsg === 'requestSubscribeMessage:ok') {
          // 这里将订阅的课程信息调用云函数存入db
          wx.cloud
            .callFunction({
              name: 'subscribe',
              data: {
                ...item,
                data: {
                  thing2: {value: item.title},
                  date5: {value: item.startTimeString},
                  phrase4: {value: item.teacher},
                  thing3: {value: item.description},
                },
                templateId: lessonTmplId,
              },
            })
            .then(() => {
              wx.showToast({
                title: '订阅成功',
                icon: 'success',
                duration: 2000,
              });
            })
            .catch(() => {
              wx.showToast({
                title: '订阅失败',
                icon: 'success',
                duration: 2000,
              });
            });
        }

在这里插入图片描述
在 “@todo 实现取消订阅逻辑” 下方粘贴如下代码:

    // 获取课程信息
    const item = e.currentTarget.dataset.item;

    // 这里将订阅的课程信息调用云函数存入db
    wx.cloud
      .callFunction({
        name: 'unsubscribe',
        data: {
          id: item.id,
          templateId: lessonTmplId,
        },
      })
      .then(() => {
        wx.showToast({
          title: '取消订阅成功',
          icon: 'success',
          duration: 2000,
        });
      })
      .catch(() => {
        wx.showToast({
          title: '取消订阅失败',
          icon: 'success',
          duration: 2000,
        });
      });

实现完这两个方法之后,在真机上面点击订阅的时候,会首先发起订阅消息的授权,成功之后会请求我们的 subscribe 云函数,在退订时会请求我们的 unsubscribe 云函数,

实现订阅消息存储

在这里插入图片描述
打开 cloudfunctions/subscribe/index.js, 在 “@todo 将消息内容存储在 messages 集合,并做去重” 下方粘贴如下代码:

    // 防止重复存储
    let message = await db
      .collection('messages')
      .where({
        id: event.id,
        touser: OPENID,
        templateId: event.templateId,
      })
      .get();

    if (message.data.length) {
      return message;
    }

    // 在云开发数据库中存储用户订阅的信息
    const result = await db.collection('messages').add({
      data: {
        ...event,
        touser: OPENID,
        page: 'index',
        done: false, // 消息发送状态设置为 false
      },
    });
    return result;

在这里我们实现了用户订阅信息存储在 messages 集合,并且做到了防止同一门课程重复订阅的问题。

实现订阅消息的定时发送

在这里插入图片描述
打开 cloudfunctions/send/index.js, 在“@todo 实现定时发送订阅消息逻辑”下方粘贴以下代码

  try {
    // 从云开数据库中查询等待发送的消息列表
    const messages = await db
      .collection('messages')
      .where({
        done: false,
        // 课程开始时间前半小时之内
        startTime: _.lte(new Date().getTime() + 30 * 60 * 1000),
      })
      .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;
  }

在这里插入图片描述
打开 cloudfunctions/send/config.json,在其中加入如下配置:

  "triggers": [
    {
      "name": "sendMessagerTimer",
      "type": "timer",
      "config": "0 * * * * * *"
		}
  ]

加入这个配置之后,需要使用前面下载的开发版的开发者工具,部署一下函数,将定时触发器发布出去。根据我们的配置,每分钟都运行一次 send 函数,在 send 函数中,我们会将消息集合中满足发送条件的订阅消息通过云调用推送出去。

实现订阅消息的退订

在这里插入图片描述
打开 cloudfunctions/unsubscribe/index.js, 在 "@todo 删除订阅的消息" 下方粘贴以下代码

    // 删除订阅的消息
    const result = await db
      .collection('messages')
      .where({
        touser: OPENID,
        templateId: event.templateId,
        id: event.id,
      })
      .remove();
    return result;

实现了对指定用户对某个课程的订阅,定时触发时不会再给该用户发送消息,实现了退订的功能

互动福利

扫码关注公众号,回复关键词『订阅消息』,就能获取本次实战的源码包。

在这里插入图片描述