通过上两章的开发,我们已经得到一个基于云、功能完整的待办清单小程序了。
然而微信小程序版本的待办清单是有不足的。你想想,会用待办清单的用户大多记性不大好,那万一用户记性差到连小程序都忘了打开看看呢...此时就需要推送消息的辅助了:直接推送一条服务信息到微信中,让你的微信图标带个小红点,这样你总能看到了吧?
本章就来添加这个小却重要的消息推送功能。
首先你要知道,小程序代码存储于你的手机本地,如果不打开它,里面的代码是不会运行的。那实现消息推送的重任,自然只能落到云函数身上了。云函数运行在云端,并且你可以给它设置一个自动运行的触发器!那么定时推送就成为了可能。
要开启订阅消息功能,首先需要做一点配置。
打开微信小程序后台 - 功能 - 订阅消息,点击开通按钮后,出现下面这个界面:
点击选用按钮,进入公共模板库:
选择待办事项提醒模板,进入下面的模板配置页面:
模板可以自定义很多条目,为了简单起见,这里仅勾选事项主题和事项描述。
点击提交后,模板就生成了,像下图这样:
模板ID是你创建的模板的身份证,记住它后面要用。
然后点击详情按钮:
注意看上图红框部分,事项主题和事项描述的键分别为 thing1
和 thing4
,后面也要用。
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) + '...'
}
}
代码有点长。核心步骤分解如下:
checked: false
)并且“未被推送过”(pushed: false
)的消息筛选出来。templateId
就是前面的模板ID,data
里的数据对应模板条目的键。pushed
置为 true
,后续将不再推送。整段代码实现的功能就是:在某个确定的时间,将对应的待办消息推送给正确的用户,并且同一条待办仅允许推送一次。推送的云函数这样就可以了。
记得上传云函数!
接下来修改本地端的代码。
小程序本地的代码需要修改两点:
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 * * * *"
设置完记得重新上传触发器。
任务完成。
更多触发器的设置规则,请看 定时触发器。
*/5 * * * * * * 表示每5秒触发一次
0 0 2 1 * * * 表示在每月的1日的凌晨2点触发
0 15 10 * * MON-FRI * 表示在周一到周五每天上午10:15触发
0 0 10,14,16 * * * * 表示在每天上午10点,下午2点,4点触发
0 */30 9-17 * * * * 表示在每天上午9点到下午5点内每半小时触发
0 0 12 * * WED * 表示在每个星期三中午12点触发
正如上面所说,对推送通知的限制主要有两点:
你需要在以上两条的规则下,设计合理的推送逻辑:
比较平衡的策略是用户可以自行选择推送日期,且每天集中推送一次(或者两次)。再一次,教程开头章节的那个 Demo 用的就是这个方案,你可以参考其大致的交互流程:
很多人对资源额度有限制感到非常反感。但要我说的话,其实你没必要太过操心:
腾讯还是你熟悉的那个腾讯,资本家怎么可能把服务器免费给你用。但是对于学习者来说,考虑太多就什么也做不成了。你我共勉。