微信小程序开发:云函数定时推送消息

402 views, 2022/07/14 updated   Go to Comments

通过上两章的开发,我们已经得到一个基于云、功能完整的待办清单小程序了。

然而微信小程序版本的待办清单是有不足的。你想想,会用待办清单的用户大多记性不大好,那万一用户记性差到连小程序都忘了打开看看呢...此时就需要推送消息的辅助了:直接推送一条服务信息到微信中,让你的微信图标带个小红点,这样你总能看到了吧?

本章就来添加这个小却重要的消息推送功能。

配置

首先你要知道,小程序代码存储于你的手机本地,如果不打开它,里面的代码是不会运行的。那实现消息推送的重任,自然只能落到云函数身上了。云函数运行在云端,并且你可以给它设置一个自动运行的触发器!那么定时推送就成为了可能。

要开启订阅消息功能,首先需要做一点配置。

打开微信小程序后台 - 功能 - 订阅消息,点击开通按钮后,出现下面这个界面:

点击选用按钮,进入公共模板库

选择待办事项提醒模板,进入下面的模板配置页面:

模板可以自定义很多条目,为了简单起见,这里仅勾选事项主题事项描述

点击提交后,模板就生成了,像下图这样:

模板ID是你创建的模板的身份证,记住它后面要用。

然后点击详情按钮:

注意看上图红框部分,事项主题和事项描述的分别为 thing1thing4 ,后面也要用。

ok,这就配置完毕了。接下来开始正式搞代码。

核心代码

由于推送的核心代码必须运行在云上,因此新建云函数 pushNotify (方法参见前面章节),在入口文件中写入下面的代码:

// cloudfunctions/pushNotify/index.js

const cloud = require('wx-server-sdk')
// 初始化 cloud
cloud.init({
  // API 调用都保持和云函数当前所在环境一致
  // 不加此参数就默认为第一个创建的云环境
  env: cloud.DYNAMIC_CURRENT_ENV
})

const db = cloud.database()
const kTableName = 'todo'

// 云函数入口函数
exports.main = async (event, context) => {
  try {
    // --- 步骤1 ---
    // 从云开发数据库中查询等待发送的消息列表
    const msgArr = await db
      .collection(kTableName)
      // 查询条件
      .where({
        checked: false,
        pushed: false,
      })
      .get()

    // --- 步骤2 ---
    for (const msgData of msgArr.data) {
      // 发送订阅消息
      await cloud.openapi.subscribeMessage.send({
        touser: msgData._openid, // 要发送用户的openid
        page: 'pages/index/index', // 用户通过消息通知点击进入小程序的页面
        lang: 'zh_CN',
        // 订阅消息模板ID
        // 替换为你的模板id!
        templateId: 'FHKU0kt...xxx...zgH_VEerY',
        // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
        // 正式版删除此行
        miniprogramState: 'developer',
        // 要发送的数据,要和模板一致
        data: {
          // 待办的主题
          thing1: {
            value: msgData.content === '' ? '无' : sliceBodyStr(msgData.content, 16)
          },
          // 待办的详情
          thing4: {
            value: '别忘了待办事项哟'
          },
        }
      })

      // --- 步骤3 ---
      // 发送成功后将pushed数据状态重置
      db
        .collection(kTableName)
        .doc(msgData._id)
        .update({
          data: {
            pushed: true
          },
        })
    }

    // --- 步骤4 ---
    return msgArr
  } catch (e) {
    return e
  }
}

// 将太长的文本截短
function sliceBodyStr(str, length) {
  if (str.length <= length) {
    return str
  } else {
    return str.slice(0, length) + '...'
  }
}

代码有点长。核心步骤分解如下:

  • 步骤1:从云数据库中,将“暂未完成”(checked: false)并且“未被推送过”(pushed: false)的消息筛选出来。
  • 步骤2:调用微信提供的开放接口,将消息逐条推送给对应的用户。注意这里的 templateId 就是前面的模板ID,data 里的数据对应模板条目的
  • 步骤3:发送完毕后,将 pushed 置为 true ,后续将不再推送。
  • 步骤4:将数据返回(不影响功能)。

整段代码实现的功能就是:在某个确定的时间,将对应的待办消息推送给正确的用户,并且同一条待办仅允许推送一次。推送的云函数这样就可以了。

记得上传云函数!

接下来修改本地端的代码。

本地代码

小程序本地的代码需要修改两点:

  • 首先你要知道,为了防止开发者骚扰用户,推送消息不是你想发就能发的。要想发送成功,首先你需要征得用户的同意。用户同意一次你就能发一条推送,同意两次才能发两条,管控非常严格。
  • 其次,前面在云端用到了 pushed 字段,需要增加到待办数据中。

因此,修改 pages/index/index.js 如下:

// pages/index/index.js

Component({
  // ...

  methods: {
    // 修改已有的inputSubmit()方法
    // 点击提交按钮
    inputSubmit() {
      // ...
      const newItem = {
        // ...
        // 新增代码
        pushed: false
      }
      // ...
      // 新增代码
      // 订阅服务
      this.subscribe()
    },

    // 新增方法
    // 向用户申请推送服务
    subscribe() {
      // 填写你自己的模板id
      const templateId = 'FHKU..xxx..H_VEerY'
      // 仅展示了主流程
      // 正式环境中,需考虑到用户可能会点击‘拒绝’、‘永久拒绝’等情况
      // 并弹出对应的反馈,如弹窗等
      wx.requestSubscribeMessage({
        tmplIds: [templateId],
        success (res) {
          console.log('订阅成功 ', res)
        },
        fail (err) {
          console.log('订阅失败 ', err)
        }
      })
    },
  },

  // ...
})

代码非常直白,你肯定看得懂。

唯一需要注意的是,wx.requestSubscribeMessage() 用于向用户申请推送权限,在正式环境中一定要考虑到万一用户点击了拒绝甚至永久拒绝该怎么办?你可能需要结合 wx.getSetting() 等接口,向用户提供弹窗等反馈信息。

触发器

主要代码都写好了,但是现在还不能自动推送,直到触发器被设置好。

触发器的设置方法很简单,修改云函数文件 /cloudfunctions/pushNotify/config.json 的代码如下:

{
  "permissions": {
    "openapi": ["subscribeMessage.send"]
  },
  "triggers": [{
    "name": "myTimer",
    "type": "timer",
    "config": "*/50 * * * * * *"
  }]
}

代码中 permissions 字段声明了云函数需要推送消息的能力,triggers 定义了每50秒运行一次的触发器。也就是说,这个云函数将每50秒就自动执行一次,从而达到了定时推送的目的。

然后右键云函数目录,点击上传触发器(保险起见,顺便把云函数也重新部署一下):

过一小会儿,触发器就部署完成了。

你可以在云函数控制台属性里查看触发器。

让我们在真机上试试效果。

点击预览,用你的微信扫描二维码:

在手机微信上进入开发版小程序,随便新建一条待办。

下方将弹出面板申请推送权限,点击确定

ok了!50秒内,你的微信就会收到推送消息了。

像下面这样:

进入服务通知,还可以看到推送的详情:

心情激动不激动?

最后一点小工作:云函数运行是要消耗资源的。如果你想做一个白嫖党,那么50秒周期的触发器可能会很快耗尽你的免费资源额度。比较理想的频率是每天早上8点运行一次,对于简单的待办来说足够了。

每早8点的触发器像下面这样设置:

// 50秒一次
// "config": "*/50 * * * * * *"

// 每天上午8点一次
// "config": "0 0 8 * * * *"

设置完记得重新上传触发器。

任务完成。

更多触发器的设置规则,请看定时触发器

限制条件

正如上面所说,对推送通知的限制主要有两点:

  • 云资源是有限的。
  • 推送权限有严格限制。

你需要在以上两条的规则下,设计合理的推送逻辑:

  • 触发器角度:如果运行太频繁,你的资源额度会很快消耗完;但如果太缓慢,又影响用户体验。
  • 推送权限角度:用户同意一次仅推送一次的机制,决定了你不能够周期性的重复推送同一条内容。每一条待办的机会只有一次,要好好利用。

比较平衡的策略是用户可以自行选择推送日期,且每天集中推送一次(或者两次)。再一次,教程开头章节的那个 Demo 用的就是这个方案,你可以参考其大致的交互流程:

总结

很多人对资源额度有限制感到非常反感。但要我说的话,其实你没必要太过操心:

  • 如果你的小程序不受欢迎,仅你自己和朋友使用,那正常情况下你可以快乐白嫖。
  • 如果非常受欢迎,那么将流量通过广告变现是非常容易的,覆盖你的支出应该绰绰有余。

腾讯还是你熟悉的那个腾讯,资本家怎么可能把服务器免费给你用。但是对于学习者来说,考虑太多就什么也做不成了。你我共勉。

点赞 or 吐槽?来评论区!




本文作者: 杜赛
发布时间: 2022年07月14日 - 10:45
最后更新: 2022年07月14日 - 10:45
转载请保留原文链接及作者
本站使用 Github 评论后端。鉴于国内复杂的网络环境,如遇评论无法加载、发表等问题,请尝试刷新页面,或更换上网姿势。