微信小程序模板消息群发、无限制推送相关讲解

2023-10-27

模版消息推送是微信小程序采用的通知形式,用户本人在小程序页面有交互行为后,可触发下发通知,通过微信聊天列表中的服务通知可快捷进入查看消息。此外,点击查看详情还能跳转到下发消息的小程序的指定页面。但是为了避免这种通知被滥用,带来不好的用户体验,小程序也对模板消息推送做了相应的限制。为了更好的优化小打卡小程序的打卡通知功能,我在开发的过程中自行摸索了一套突破推送限制的解决方案。可以实现7天内向用户推送多条模板消息,甚至向用户群发消息的功能。

注意:请务必在严格遵守小程序运营规范的前提下使用本方案。

消息通知有什么作用?

消息通知是一个很重要的功能,如QQ空间的回复状态通知,QQ邮箱的邮件通知,微信支付成功提通知等。这种常规的服务跟踪类消息,便于用户掌握产品对自身服务的进度,方便客户获取必要的信息,提高效率;保证用户的知情权,让用户有安全感。同时,对于产品本身来说,可以引导用户进行下一步行为,增加了产品的曝光率,便于用户留存,增强用户粘性。

模板消息长什么样子?

服务通知及模板消息


如上图,呈现在微信聊天列表的服务通知,收纳了各个小程序向用户推送模板消息,这个服务通知是用户查看模板消息的入口,用户点击服务通知后可以查看到通知列表页面,每条通知以卡片的形式呈现,包括小程序的logo、名称、通知时间、通知内容等信息。

模板消息是什么?

所谓『模板消息』,就如上面的通知卡片,首先通知卡片形式样子是固定的,其实卡片中的通知内容部分,可以看到每天通知的内容都具备日程描述、日程主题、日程时间等要素,通知之间不同的地方在于这些要素后面的文案,将这些通知要素制作成模板,每次针对不同的通知内容只需要填充每条要素对应的具体的文本即可推送给用户。上面图中两条模板消息的日程主题和时间不一样,其他的信息要素保持一致,这就是模板消息。

使用模板消息有哪些好处?

提到模板消息的好处,第一印象是"多、快、好、省"的特点。

"快"即快捷,体现在微信用户侧的通知体验,由于在微信客户端服务通知在聊天列表中,保留了用户以往处理聊天通知的习惯,所以用户可以很便捷地触及服务通知,查看小程序推送的模板消息。

"好"即效果好,小程序的模板消息具备跳转直达小程序特定页面的能力,这样用户接收消息后,查看消息的通知就能便捷地回到小程序进行相应的业务处理、信息查看等后续操作,一定程度上提升了用户的活跃度,小打卡小程序的近30天访问来源数据显示,有20%左右的用户通过模板消息这个入口进入小打卡,在各种来源中排名第三位,可以见模板消息是用户使用你的小程序的重要入口。

"省"即省钱呗,有了模板推送,自然降低了消息通知的成本,节省费用。消息通知优先通过模板消息这种方式来推送给指定用户,只有才无法触及用户的情况下,才使用传统的付费短信推送等形式。

"多"呢?上面提到"无法触及用户的情况",其实是因为小程序不具备"多"的特点。物以稀为贵,模板消息虽好,但是微信小程序官方为了保证用户体验,平衡通知和骚扰行为,对模板推送做了相应限制。接下来就聊聊这个限制。

微信对模板消息有什么样的限制?

微信小程序允许下发模板消息的条件分为两类,支付或者提交表单

目前支付的限制有所放开,即1次支付可以下发3条模板消息。通过提交表单来下发模板消息的方式限制为一次的触发行为,7天内可以向用户推送一条模板消息。这种消息的控制放的太宽的话,很容易对用户的体验造成很大冲击,给用户带来一定的骚扰。

但是,用户1次触发、7天内推送1条通知明显是不够用的,比如小打卡小程序利用模板消息的推送来提醒用户每天打卡,只能在用户前一天打卡的情况下,获取一次推送模板消息的机会,然后用于第二天向用户发送打卡通知。但是很多情况下,用户如果某一天忘记打卡,小打卡便失去了提醒用户的权限,和用户断开了联系

在小打卡中还有一个迫切需要多条模板消息推送的场景,比如打卡活动每次有新的成员进入,需要通知管理员进行审核,这种情况也需要及时地通知管理员,以便管理员快速响应,处理成员的审核请求并通知成员审核结果。

注意到下发条件中,每次触发的到的推送码可以在未来7天内使用,多次提交触发下发的消息条数独立,相互不影响,那能不能突破模板消息的发送限制,更好地优化打卡提醒功能呢?

如何突破模板消息的推送限制?

微信小程序官方最近已经透露出可能对模板消息进一步放宽限制的信号,不过在这之前,我们可以在遵守官方相关运营规范、保证用户体验的情况下,倒腾一个"让用户一次触发、多次推送,甚至群发模板消息"的解决方案。

其实仔细分析消息下发条件"1次提交表单可下发1条,多次提交下发条数独立,相互不影响",突破口就明显了,只需收集到足够推送码,即每次提交表单时获取到的formId就是我们所需的“推送权限”。它是一次性的,代表着开发者有向当前用户推送模板消息的权限。

为了打造这样一个突破限制的模版消息推送功能,做到7天内任性推送,我们将小程序前后端的工作明确一下,小程序前端,即运行在用户微信上的小程序负责收集推送码,小程序后端,即运行在服务器上的应用程序负责将推送码存储到数据库中,并在需要推送的模版消息的时候从中取出推送码formId判断有效性并加以运用。整个方案的前后端业务流程如下:

方案前后端流程

接下来我们设计一个能够突破当前模板消息推送限制的方案。结合小程序前端界面、小程序逻辑层、服务器程序、数据库、异步任务系统各自分工,来实现将小程序模板消息推送所需的推送码收集、上报、存储、调用。最终做到7日内更好地推送模板消息、触及用户。

一.前端页面如何尽可能多地收集推送码?

每次表单提交可以触发一次下发模版消息的机会,表单组件

如下:

Page({
  formSubmit: function(e) {
    let formId = event.detail.formId;
    console.log('form发生了submit事件,推送码为:', formId)
  }
})

组件中属性report-submit为true时,代表需要请求发模板消息的推送码,此时点击按钮提交表单可以获取formId,用于发送模板消息。接下来只需要对原来的页面进行改造,将用户原来绑定了点击事件的界面用表单组件中的button按钮组件来代替,也就是把用户的交互点击的bindtap事件通过表单bindsubmit来取代,从而捕获用户的点击事件来产生更多的推送码formId,这里还需要对按钮组件的样式进行稍微的修改,以便更好地包裹原来界面的代码。

/*wxss*/
/*修改按钮样式,使其能够包裹其他组件*/
.btn {
  border:none;
  text-align:left;
  padding:0;
  margin:0;
  line-height:1.5;
}
//js
Page({
  formSubmit: function(e) {
    let formId = e.detail.formId;
    this.dealFormIds(formId); //处理保存推送码
    let type = e.detail.target.dataset.type;
    //根据type的值来执行相应的点击事件
    //...
  },
  dealFormIds: function(formId) {
    let formIds = app.globalData.gloabalFomIds;//获取全局数据中的推送码gloabalFomIds数组
    if (!formIds) formIds = [];
    let data = {
      formId: formId,
      expire: parseInt(new Date().getTime() / 1000)+604800 //计算7天后的过期时间时间戳
    }
    formIds.push(data);//将data添加到数组的末尾
    app.globalData.gloabalFomIds = formIds; //保存推送码并赋值给全局变量
  },
})

上面的代码主要实现了模拟表单提交事件来取代原来的点击事件,用户在点击界面进行交互的同时,能够获得多个推送码保存app.js的全局变量globalData中,等待用户下一次发起网络请求时,即可将gloabalFomIds数组数据发送给服务器。

小打卡上的点击区域


上图以小打卡的打卡详情页为例,用户在这个页面的点击操作可以很快收集到多个formId,所以将界面上用户高频点击的事件用表单的形式重新封装后,可以静默、快速收集到所需的"模板消息推送权限"。

二.小程序逻辑层如何传递推送码给服务器?

Page({
   onLoad:function(){
    this. saveFormIds();
  },
  saveFormIds: function(){
    var formIds = app.globalData.gloabalFomIds; // 获取gloabalFomIds
    if (formIds.length) {//gloabalFomIds存在的情况下 将数组转换为JSON字符串
      formIds = JSON.stringify(formIds);
      app.globalData.gloabalFomIds = '';
    }
    wx.request({//通过网络请求发送openId和formIds到服务器
      url: 'https://www.x.com', 
      method: 'GET',
      data: {
        openId: 'openId',
        formIds: formIds
      },
      success: function(res) {
      }
    });
  },
})

在小程序的逻辑层中,通过全局变量gloabalFomIds收集到多个formId后,可以在新页面载入时,在onLoad生命周期函数中发送网络请求获取数据,gloabalFomIds不为空时,把gloabalFomIds数组格式化为字符串发送到服务器,并清空当前的gloabalFomIds,以便继续获取新的formId。

三.后端程序如何保存推送码formId?

因为这个保存是一个高频IO的操作,我们后端以PHP结合高性能的key-value数据库Redis来实现推送码的存储。相关关键代码如下,简单表达了思路,针对不同的后端环境和开发语言,你可能需要做相应的调整。

//关键代码
public function saveFormIds(){
    $openId = $_GET['openId'];
    $formIds = $_GET['formIds'];;//获取formIds数组
    if($formIds){
        $formIds = json_decode($formIds,TRUE);//JSON解码为数组
        $this -> _saveFormIdsArray($openId,$formIds);//保存
    }
}
private function _get($openId){
    $cacheKey = md5('user_formId'.$openId);
    $data = $this->cache->redis->get($cacheKey);//修改为你自己的Redis调用方式
    if($data)return json_decode($data,TRUE);
    else return FALSE;
}
private function _save($openId,$data){
    $cacheKey = md5('user_formId'.$openId);
    return $this->cache->redis->save($cacheKey,json_encode($data),60*60*24*7);//修改为你自己的Redis调用方式
}
private function _saveFormIdsArray($openId,$arr){
    $res = $this->_get($openId);
    if($res){
        $new = array_merge($res, $arr);//合并数组
        return $this->_save($openId,$new);
    }else{
        $result = $arr;
        return $this->_save($openId,$result);
    }
}

这一步主要是构建服务器程序高效存储用户的推送码formId,这下推送机会有了,接下来我们考虑如何利用后端程序来想特定用户发送模板消息,考虑怎样去合理运用推送机会。

四.如何实现高性能的模板消息推送?

构建高性能的服务器端异步任务推送,可以满足模板消息的群发、以及定时发送的需求,如小打卡就采用了高性能分布式内存队列系统 BEANSTALKD,来实现模板消息的异步定时推送。实现发送模板消息的群发、定时发送分为2个步骤:

设置任务执行时间并将该发送任务推送到异步任务队列。

通过任务发送服务轮询执行任务,获取access_token、指定你需要推送消息的用户的openId,根据openId获取用户的推送码formId,并结合模板id拼装模板上的通知内容,调用模板消息发送接口来异步发送。

普通的模板消息的发送就不赘述了,可参考官方文档中的模板消息功能一步步进行操作,我们重点来看高性能异步任务推送的实现方法。涉及到的关键代码如下:

//设置异步任务
public function put_task($data,$priority=2,$delay=3,$ttr=60){//任务数据、优先级、时间定时、任务处理时间
    $pheanstalk = new Pheanstalk('127.0.0.1:11300');
    return $pheanstalk ->useTube('test') ->put($data,$priority,$delay,$ttr);
}
//执行异步任务
public function run() {
    while(1) {
        $job = $this->pheanstalk->watch('test')->ignore('default')->reserve();//监听任务
        $this->send_notice_by_key($job->getData());//执行模板消息的发送
        $this->pheanstalk->delete($job);//删除任务
        $memory = memory_get_usage();
        usleep(10);
    }
}
//1.取出一个可用的用户openId对应的推送码
public function getFormId($openId){
    $res = $this->_get($openId);
    if($res){
        if(!count($res)){
            return FALSE;
        }
        $newData = array();
        $result = FALSE;
        for($i = 0;$i < count($res);$i++){
            if($res[$i]['expire'] > time()){
                $result = $res[$i]['formId'];//得到一个可用的formId
                for($j = $i+1;$j < count($res);$j++){//移除本次使用的formId
                    array_push($newData,$res[$j]);//重新获取可用formId组成的新数组
                }
                break;
            }
        }
           $this->_save($openId,$newData);
        return $result;
    }else{
        return FALSE;
    }
}
//2.拼装模板,创建通知内容
private function create_template($openId,$formId,$content){
    $templateData['keyword1']['value'] = '打卡即将开始';
    $templateData['keyword1']['color'] = '#d81e06';
    $templateData['keyword2']['value'] = '打卡名称';
    $templateData['keyword2']['color'] = '#1aaba8';
    $templateData['keyword3']['value'] = '05:00';
    $templateData['keyword4']['value'] = '备注说明';
    $data['touser'] = $openId;
    $data['template_id'] = '模板id';
    $data['page'] = 'pages/detail/detail?id=1000';//用户点击模板消息后的跳转页面
    $data['form_id'] = $formId;
    $data['data'] = $templateData;
    return json_encode($data);
}

//3.执行模板消息发布
public function send_notice($key){
    $openId = '用户openId';
    $formId = $this -> getFormId($openId);//获取formId
    $access_token = '获取access_token';
    $content='通知内容';//可通过$key作为键来获取对应的通知数据
    if($access_token){
        $templateData = $this->create_template($openId,$formId,$content);//拼接模板数据
        $res = json_decode($this->http_post('https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token='.$access_token,$templateData));
        if($res->errcode == 0){
            return $res;
        }else{
            return false;
        }
    }
}

Beanstalkd是一个高性能、轻量级的分布式内存队列系统,我们通过Beanstalkd将模板消息推送任务的创建以及任务的执行分开进行。

在创建推送任务时,设置任务的执行时间以及定义推送消息的类型和通知内容等数据。

在任务执行时,通过Beanstalkd的任务监听函数来捕获任务。通过预先在创建任务时标记的数据来确定模板消息的具体推送内容,比如用户openId,通过用户openId获取一个可用的推送码formId,获取推送内容等,最后在调用微信小程序模板消息下发接口完成推送。

getFormId函数主要实现每次取出一个未过期可用的推送码formId,并且删除不可用的邀请码和当前已选中的邀请码,以保证一定数额的推送码formId在未来一周内可用。

关于Beanstalkd的使用介绍,可用参考一下文章,深入研究。

高性能分布式内存队列系统beanstalkd(转)

beanstalkd消息队列使用

最后总结一下,整个方案涉及到的关键词有表单、按钮、formId、模板消息、Redis、Beanstalkd等,涉及了多项技术的组合,包括前端开发、后端开发、数据库技术等,且前后端分工明确,共同支撑整个方案地实现。

模板消息推送方案

正如我之前文章里所说的,微信小程序开发的难点不在于小程序本身,小程序开发技术是前后端一系列的技术的组合,开发者需要持续学习,掌握、提升更多的相关开发技术,来更好地支撑产品的功能实现。最后,这个方案可以在用户最后一次使用小程序后的7天内,对用户发送多条模板消息唤回用户,但是请一定要在遵循微信官方的运营规范的前提下,合理使用这样的模板消息推送功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微信小程序模板消息群发、无限制推送相关讲解 的相关文章

  • Ubuntu20安装clickhouse最新版本详细教程

    文章目录 环境说明 安装步骤 第1步 检查是否支持SSE4 2 第2步 为apt添加clickhouse仓库 第3步 添加依赖并更新apt数据库 第4步 安装clickhouse服务端及客户端 第5步 启动clickhouse 第6步 客户
  • unity中事件委托的用法和重新加载场景的关系

    委托是一种容器 容器里面放的是函数方法 可以同时运行多个函数 事件 event 一般就是用来阉割委托 只能增加函数 提高安全性 就比如我设置小鸟碰撞到水管 就运行订阅委托所有函数 using System Collections using

随机推荐

  • vmware

    一 虚拟机设置 1 选择待处理虚拟机 右键 设置 或者在点开虚拟机时 选择 编辑虚拟机设置 2 在虚拟机设置 窗口 选择 选项 点击 共享文件夹 文件夹共享 选择总是启用 3 在文件夹 添加共享目录 弹出窗口 点击下一步 设置共享文件夹目录
  • DNS协议及其工作原理

    DNS是域名系统 Domain Name System 的缩写 它是一种用于将域名转换为IP地址的分布式数据库系统 它是因特网的基石 能够使人们通过域名方便地访问互联网 而无需记住复杂的IP地址 DNS的历史可以追溯到1983年 当时因特网
  • 浅谈公钥和私钥的概念

    关于公钥和私钥 简单来理解你可以将它们视做你的用户名和密码 用户名就是公钥 密码就是私钥 区块链数字钱包由公钥和私钥组成 熟悉密码学的人都会了解公钥和私钥 要是作为开发人员 则能够使用公钥和私钥在两个不同的通信之间建立安全连接 但要是可以扩
  • sqli-labs (less-18)

    sqli labs less 18 进入18关 输入用户名和密码以后 我们发现屏幕上回显了我们的IP地址和我们的User Agent 用hackbar抓取POST包 在用户名和密码的位置判断注入点 这里我试了很久 发现用户名和密码的位置都是
  • Java 基础 字符输入流读取字符数据

    package demo5 import java io FileInputStream import java io FileOutputStream import java io FileReader import java io IO
  • 华为OD机试 - 宜居星球改造计划(Java)

    题目描述 2XXX年 人类通过对火星的大气进行宜居改造分析 使得火星已在理论上具备人类宜居的条件 由于技术原因 无法一次性将火星大气全部改造 只能通过局部处理形式 假设将火星待改造的区域为row column的网格 每个网格有3个值 宜居区
  • 安卓搭建文件共享服务器,安卓文件共享云服务器搭建

    安卓文件共享云服务器搭建 内容精选 换一换 如果您的业务数据同时保存在数据盘和系统盘中 要想实现业务数据跨帐号迁移 需要用到镜像服务的创建整机镜像 共享镜像等功能 本节操作以Windows操作系统为例 为您详细介绍在同一区域内 跨帐号迁移业
  • IP地址块222.125.80.128/26怎么理解?

    IP地址块222 125 80 128 26包含的可用主机数是多少 最小的地址是多少 最大的地址是多少 IP 26 是CIDR的格式 全称是classless inter domain route 叫做无类域间路由 就是说32位IP的前26
  • 简单理解虚拟机的三种网络适配模式

    仅主机 虚拟机与主机能互ping 但虚拟机不能上网 NAT模式 虚拟机与主机能互ping 虚拟机能上网 但非主机不能访问 桥接模式 虚拟机与主机能互ping 虚拟机能上网 而且非主机可能访问
  • Python Django: urlpatterns 变量的语法

    urlpatterns 变量的语法 1 包含其它的URLconfs 1 1 项目目录结构如下 注 记得在settings py中配置新添加的应用 1 2 不同目录下的urls py配置 2 url别名反向解析 3 url 命名空间 3 1
  • left join on多表关联_MySQL-关联查询

    MySQL 关联查询SQL数据分析 1周前MySQL关联查询前面 我们介绍的都是单表查询 就是只从一张表中获取数据 而实际应用的时候 我们都会同时查询多张表 这里 我们就介绍下 多表关联查询的使用 SQL join 用于根据两个或多个表中的
  • 使用umi快速搭建项目

    1 首先安装umi npm install umi g 2 创建一个文件夹 注意不能是中文 在vscode 中进入文件夹 执行命令生成package json文件 npm init 3 修改配置项 scripts start umi dev
  • 浏览器插件不能自动运行问题的设置方案

    目录 1 环境 2 问题描述 3 解决方案 1 环境 浏览器 Microsoft Edge 版本 117 0 2045 31 正式版本 64 位 设置插件 AdGuard 广告拦截器 2 问题描述 每次打开一个新的网页时 插件都不能自动运行
  • 7.1 参数的点估计

    小结 点估计是一种统计推断方法 它用于通过样本数据估计总体参数的值 在统计学中 总体是指一个包含所有个体的集合 而样本是从总体中选出的一部分个体 总体参数是总体的某种特征 如平均值 标准差 比例等 点估计是指使用样本数据来估计总体参数的一个
  • AtCoder Beginner Contest 219 D - Strange Lunchbox

    D 问当A至少x个 B至少y个的最小方案数 定义dp i j 位A有i个 B有j个的最小方案数 然后枚举 因为问的是至少 所以要遍历A从x B从y开始到300的所有答案 因为可能没有刚好到达x y 如样例1 include
  • 局域网的组成及主要设备的作用

    局域网通常是分布在一个有限地理范内的网络系统 一般所涉及的地理范围只有几公里 通常由一个单位或组织建设拥有的计算机网 局域网由网络硬件 包括网络服务器 网络工作站 网卡 网络互联设备等 和网络传输介质 以及网络软件所组成 网络设备 即网络通
  • 知识推理学习笔记

    知识推理 一 OWL本体语言 1 语法 2 逻辑基础 3 描述逻辑系统 1 最基本的元素 概念 关系 个体 1 概念 解释为一个领域的子集 2 关系 解释为一个领域的二元关系 笛卡尔乘积 3 个体 一个领域内的实例 2 TBox术语集 泛化
  • spring boot整合JMS(ActiveMQ实现)

    一 安装ActiveMQ 具体的安装步骤 请参考我的另一篇博文 http blog csdn net liuchuanhong1 article details 52057711 二 新建spring boot工程 并加入JMS Activ
  • 阿里三面 失败

    update 2015 04 16 在tomcat下一个 使用classloader加载类信息之后将被放置在一类方法区 永久代 当这个类创建一个线程 例如 显示当前的时间段 这会导致此类信息已经在该地区长期存在 作已经完毕了 可是没有把这个
  • 微信小程序模板消息群发、无限制推送相关讲解

    模版消息推送是微信小程序采用的通知形式 用户本人在小程序页面有交互行为后 可触发下发通知 通过微信聊天列表中的服务通知可快捷进入查看消息 此外 点击查看详情还能跳转到下发消息的小程序的指定页面 但是为了避免这种通知被滥用 带来不好的用户体验