Skip to content

10订阅消息:提高小程序用户留存

你好,我是俊鹏,今天这一讲,我来带你学习怎么使用微信小程序的订阅消息功能。

你能发现,我在标题里强调了订阅消息能提高小程序的留存率,为什么强调这一点呢? 站在小程序的角度上,订阅消息最普遍的应用场景有两种,一种是被动的,一种是主动的。

被动的订阅消息指: 消息的发送需要用户的某些行为作为触发,然后小程序再针对性地向用户发送消息反馈。以电商类小程序为例,当用户支付成功之后,小程序会向用户推送一条消息,用户可以通过这条消息跟踪订单进度。

主动的订阅消息是指: 小程序可以定期或不定期地向用户发送消息通知,不需要用户的某些行为作为触发点。比如学习类小程序在每天的固定时间向用户发送消息,通知用户打卡。

在被动场景下,小程序会对用户的行为及时反馈,从而提升用户的产品体验,以及对小程序的认可度、依赖度。在主动场景下,小程序可以通过定期或不定期地发送通知,把离开的用户拉回来继续使用小程序。所以,这两种场景下的订阅消息都能帮小程序提高用户的留存率,这就是我们学习订阅消息的目的。

我希望学完今天的内容,你能把订阅消息应用到工作中,让自己的小程序获得更多稳定的用户。

现在,我们已经明确了学习的目的,接下来就一起学习怎么使用小程序的订阅消息功能。订阅消息属于微信提供的开放接口之一,所以跟 09 讲调用微信开放接口一样,我会介绍两种方法:

  • 传统的调用方式,掌握这种方式后,你会明白订阅消息完整链路的基本原理;

  • 云调用方式,教你用免鉴权的方式快速实现订阅消息的调用,提高研发效率。

这两种方式有一些内容是相同的,包括消息模板配置和获取用户授权,所以我先带你学习这些内容,然后再掌握它们的差异点,也就是发送消息的逻辑。

订阅消息完整的流程可以简单概况成下面这张图:

  1. 在发送消息之前必须获得用户授权,这是第一步也最基本的一步。

  2. 用户授权之后,你需要把授权信息记录下来,因为小程序的订阅消息能定义多种类型,每种都需要得到用户的授权后才可以发送。

  3. 消息的发送需要一个触发点,根据订阅消息的两种应用场景,触发点可以是用户的某个行为比如支付订单,也可以是小程序主动触发,比如定时发送。

这三个步骤是小程序订阅消息的基本流程,我讲这个流程是希望你能先对整体的轮廓有所了解,然后再深入完整架构和实现细节。在这个流程中,有一个没有覆盖的必要步骤:先配置订阅消息的模板。

配置消息模板

登录微信公众平台之后,消息模板的配置入口在小程序管理后台中的"功能"-"订阅消息"里,你会看到下面这张图展示的内容:

点击"添加"就可以配置消息模板了,微信官方提供了一些常用的模板类型,你可以自行选择:

你可以看到,上图中有一个"一次性订阅"的提醒,说明这些模板库提供的都是一次性订阅消息。而小程序的订阅消息分为:一次性订阅消息和长期订阅消息。

  • 一次性你可以简单理解成得到用户的授权之后只能发送一条消息,如果再有发送需求还要再次申请用户的授权。

  • 长期订阅消息可以得到用户授权后发送多条消息。不过目前长期订阅消息只向政务民生、医疗、交通、金融、教育等线下公共服务开放(后面也许会开放出更多领域)。

所以,我们今天的学习是围绕一次性订阅消息展开的。

按照上述流程配置完消息模板后,你会拿到一个模板 ID,请记住这个名词,后续所有步骤都会用到它,而第一步就是用模板 ID 获取用户的授权。

获取用户授权

小程序SDK提供了一个用来获取用户授权的API:wx.requestSubscribeMessage。你要用这个 API 为每一个模板 ID 授权,调用方式如下:

javascript
wx.requestSubscribeMessage({
  tmplIds: ['tmplId_1','tmplId_2','tmplId_3'],
  success (res) {
    console.log(res)
    / **
    {
      errMsg: 'requestSubscribeMessage:ok'
      tmplId_1: 'accept',
      tmplId_2: 'reject',
      tmplId_3: 'ban' 
    }
    */
  }
})

其中参数 tmplIds 是一个数组,数组中的每个元素就是前面配置的消息模板 ID ,如果你需要一次性获取多个模板的用户授权就在 tmplIds 数组里写入多个元素。调用wx.requestSubscribeMessage 之后,用户会在小程序端收到一个弹窗:

用户可以对列表中的每个消息模板分别授权,也可以全部勾选(也就是全部授权)。用户点击"允许"按钮之后,将会触发 wx.requestSubscribeMessage 的 success 回调函数,返回的数据结构可以参考上面的示例代码,每个模板 ID 都有一个状态标识,accept 代表得到授权、reject 代表未获得授权、ban 代表被后台封禁。当然,正常情况下是不会出现 ban 状态的,除非你的订阅消息涉嫌骚扰用户或内容违禁。

既然学习的是一次性订阅消息,那么你要在每次得到用户授权后都要把信息记录下来。但不能把这些信息保存在前端,而是同步到服务端保存(因为发送消息是在服务端执行的),那怎么把这些信息与用户一一对应起来呢?

还记得我们在 02 讲学习的小程序登录功能吗?登录成功后服务端会拿到用户的 openId,然后用openId 创建自定义登录态返回给小程序的前端,后续小程序的每次请求都需要携带这个自定义登录态,服务端在接收到请求后可以从自定义登录态反解析出用户的 openId,这样就可以将请求的数据与用户一一对应起来了。整个过程如图所示:

这样我们就获取到了用户的授权,接下来就是向用户发送一条订阅消息,我们先学习传统的调用方式(这里会用到 09 讲中提到的使用缓存管理 access_token 的知识)。

发送消息的传统调用方式

学完 09 讲后我们知道了,调用微信开放接口需要临时凭证 access_token,发送订阅消息的接口作为微信开放接口的一员同样要遵循这条规则。

服务端需要调用微信提供的subscribeMessage.send接口向用户发送订阅消息,这个接口有几个请求参数需要你特别关注:

其中 template_id 是上一步得到用户授权的几个模板 ID 中的一个,请注意,你每次调用 subscribeMessage.send 接口只能发送一条消息给用户,而不能同时发送多条,这是微信的限制。touser 参数的值是接收消息的用户 openId,access_token 是临时凭证。

而且我刚刚提到了,发送消息需要一个触发点(可以是用户的某个行为触发,也可以是服务端的定时任务,具体采用哪种方式需要根据业务场景来决定),我会以定时任务这种场景为例,对照下图讲解一下完整的发送消息流程:

  1. 首先,服务器需要设定一个定时任务,比如每天 9 点触发一次,发送消息。

  2. 触发之后,第一步先检查本地缓存中是否存在有效期之内的 access_token ,如果不存在就需要重新请求微信的服务获取一个新的。

  3. 拿到有效的 access_token 之后,第二步是通过 subscribeMessage.send 接口向微信服务器发送一个请求。

  4. 微信服务器收到请求之后,发送一条订阅消息给指定的 openId 对应的用户,便完成了整个发送消息的流程。

以上就是发送订阅消息的传统调用方式。你也看到了,在这套流程中,需要比较繁重的服务端开发工作,比如设定定时任务、缓存管理等,如果你具备这些知识和能力的话当然是件很容易完成的事,但对于大多数小程序前端开发者来说,相对欠缺这部分知识,所以接下来我们就来学习效率更高的云调用方式。

发送消息的云调用方式

09 讲中我已经讲了云调用是什么,就不再重复了,如果你忘了记得复习一下。微信小程序的订阅消息功能提供了云调用的支持,你可以不用关注鉴权,也就是不需要关注 access_token,直接在云函数里调用微信 SDK 提供的openapi.subscribeMessage.sendAPI 就行,参数跟 subscribeMessage.send 接口一样,只是不再需要 access_token 了。

javascript
const cloud = require('wx-server-sdk')
cloud.init()
exports.main = async (event, context) => {
  try {
    const result = await cloud.openapi.subscribeMessage.send({
        touser: 'OPENID',
        templateId: 'TEMPLATE_ID',
        // ...其他参数
      })
    return result
  } catch (err) {
    return err
  }
}

除了避免管理 access_token 的麻烦以外,在前面传统调用方式中还用到了一项能力:定时任务。这项需求云函数同样可以满足,你可以给云函数配置一个定时触发器,使用简单的 JSON 配置文件就可以设定一个定时任务。比如我刚刚说的每天 9 点触发一次就可以写成下面这种格式的云函数定时触发器:

javascript
{
  // triggers 字段是触发器数组,目前仅支持一个触发器,即数组只能填写一个,不可添加多个
  "triggers": [
    {
      // name: 触发器的名字,规则见下方说明
      "name": "myTrigger",
      // type: 触发器类型,目前仅支持 timer (即 定时触发器)
      "type": "timer",
      // config: 触发器配置,在定时触发器下,config 格式为 cron 表达式,规则见下方说明
      "config": "0 0 9/23 1/1 * * *"
    }
  ]
}

通过上面两个步骤就完成了跟传统调用方式一样的功能,而整个发送消息的流程也得到了简化:

对比这两种调用方式,你应该能够明显感受到不同。当然,这并不是说我们只学会用云调用而不用学习传统方式了。云调用的底层也是类似传统的调用方式,只不过帮你完成了定时任务、缓存管理这些服务端的开发工作,而且我们通过学习传统的调用方式能够明白底层的工作原理,也许有一天你能够成为一名架构师,那时候你就需要这些底层知识作为搭建复杂架构的基础了。

总结

今天这节课,我之所以带你了解小程序的订阅消息,是因为它能帮助小程序提高用户的留存率。通过这节课,我希望你能够将以下知识融会贯通:

  1. 小程序订阅消息的基本流程,包括模板配置、用户授权和发送消息;

  2. 知晓发送消息的传统调用方式,并且能够充分理解每一个步骤的作用;

  3. 学会并能够使用通过云调用实现订阅消息的发送,并且能够体会到云调用带来的效率提升。

如果你能够完成上面三点要求,那么今天就交给你一个需要动动手的课后作业:使用云调用完成小程序的订阅消息功能。我相信在成功完成这个作业之后,你能够对今天这节课的知识有更深的理解和记忆。