前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >『教程』如何突破微信小程序模板消息限制实现无限制主动推送

『教程』如何突破微信小程序模板消息限制实现无限制主动推送

作者头像
极乐君
发布2018-07-31 14:38:30
2.1K0
发布2018-07-31 14:38:30
举报
文章被收录于专栏:极乐技术社区极乐技术社区

背景需求

基于微信的通知渠道,微信小程序为开发者提供了可以高效触达用户的模板消息能力,在用户本人与小程序页面有交互行为后触发,通过微信聊天列表中的服务通知可快捷进入查看消息,点击查看详情还能跳转到下发消息的小程序的指定页面。

微信小程序允许下发模板消息的条件分为两类:支付或者提交表单。通过提交表单来下发模板消息的限制为“允许开发者向用户在7天内推送有限条数的模板消息(1次提交表单可下发1条,多次提交下条数独立,相互不影响)”。

然而,用户1次触发7天内推送1条通知是明显不够用的。比如,签到功能利用模板消息的推送来提醒用户每天签到,只能在用户前一天签到的情况下,获取一次推送模板消息的机会,然后用于第二天向该用户发送签到提醒。

但是很多情况下,用户在某一天忘记签到,系统便失去了提醒用户的权限,导致和用户断开了联系;再比如,系统想主动告知用户即将做某活动,然而由于微信小程序被动触发通知的限制,系统将无法主动推送消息。

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

突破口:“1次提交表单可下发1条,多次提交下发条数独立,相互不影响”

为了突破模板消息的推送限制,实现7天内任性推送,只需收集到足够的推送码,即每次提交表单时获取到的formId。一个formId代表着开发者有向当前用户推送模板消息的一次权限。

客户端 收集推送码

当表单组件中的属性report-submit=true时表示发送模板消息,提交表单便可以获取formId。接下来只要对原先的页面进行改造,将用户原先绑定了点击事件的界面用表单组件中的button按钮组件来代替,即把用户的交互点击的bindtap事件由表单bindsubmit来代替,从而捕获用户的点击事件来生成更多的推送码。

// 收集推送码Page({ formSubmit: funcition(e) { let formId = e.detail.formId; this.collectFormIds(formId); //保存推送码 let type = e.detail.target.dataset.type; // 根据type执行点击事件 }, collectFormIds: function(formId) { let formIds = app.globalData.globalFormIds; // 获取全局推送码数组 if (!formIds) formIds = []; let data = { formId: formId, expire: new Data().getTime() + 60480000 // 7天后的过期时间戳 } formIds.push(data); app.globalData.globalFormIds = formIds; },})

上报推送码

等待用户下一次发起网络请求时,将globalFormIds发送给服务器。

// 上报推送码Page({ onLoad: funcition(e) { this.uploadFormIds(); //上传推送码 }, collectFormIds: function(formId) { var formIds = app.globalData.globalFormIds; // 获取全局推送码 if (formIds.length) { formIds = JSON.stringify(formIds); // 转换成JSON字符串 app.globalData.gloabalFomIds = ''; // 清空当前全局推送码 } wx.request({ // 发送到服务器 url: 'http://xxx', method: 'POST', data: { openId: 'openId', formIds: formIds }, success: function(res) { } }); },})

服存储推送码

高频IO,采用Redis来存储推送码。

/** * 收集用户推送码 * * @param openId 用户的openid * @param formTemplates 用户的表单模板 */public void collect(String openId, List<FormTemplateVO> formTemplates) { redisTemplate.opsForList().rightPushAll("mina:openid:" + openId, formTemplates);}

推送模板消息

下面实现了群发的功能,针对特定用户类似。

代码语言:javascript
复制
/** * 推送消息 * * @param templateId 模板消息id * @param page   
    跳转页面 * @param keyWords 
  模板内容 */public void push(String templateId, String page, String keyWords) 
{    String logPrefix = "推送消息";    // 获取access token    String accessToken = this.getAccessToken();    // 创建消息通用模板
    MsgTemplateVO msgTemplateVO = MsgTemplateVO.builder().template_id(templateId).build();    // 跳转页面 
    msgTemplateVO.setPage(StringUtils.isNotBlank(page) ? page : "");    // 模板内容  
   if (StringUtils.isNotBlank(keyWords)) {        String[] keyWordArr = keyWords.split(BaseConsts.COMMA_STR);        Map<String, MsgTemplateVO.KeyWord> keyWordMap = new HashMap<>(8);        for (int i = 0; i < keyWordArr.length; i++) {            MsgTemplateVO.KeyWord keyWord = msgTemplateVO.new KeyWord(keyWordArr[i]);         
     keyWordMap.put(MsgTemplateVO.KEYWORD + (i + 1), keyWord);        }  
        msgTemplateVO.setData(keyWordMap);    } else {        msgTemplateVO.setData(Collections.emptyMap());    }    // 获取所有用户 
      List<String> openIdList = minaRedisDao.getAllOpenIds();    for (String openId : openIdList) {        // 获取有效推送码     
      String formId = minaRedisDao.getValidFormId(openId);    
       if (StringUtils.isBlank(formId)) {            LOGGER.error("{}>>>openId={}>>>已无有效推送码[失败]", logPrefix, openId);            continue;        }        // 指派消息   
         MsgTemplateVO assignMsgTemplateVO = msgTemplateVO.assign(openId, formId);        // 发送消息      
      Map<String, Object> resultMap;        try {            String jsonBody = JsonUtils.getObjectMapper().writeValueAsString(assignMsgTemplateVO);     
            String resultBody = OkHttpUtils.getInstance().postAsString(messageUrl + accessToken, jsonBody);       
          resultMap = JsonUtils.getObjectMapper().readValue(resultBody, Map.class);        } catch (IOException e) {            LOGGER.error("{}>>>openId={}>>>{}[失败]", logPrefix, openId, e.getMessage(), e);            continue;        }   
          if ((int) resultMap.get(ResponseConsts.Mina.CODE) != 0) {            LOGGER.error("{}>>>openId={}>>>{}[失败]", logPrefix, openId, resultMap.get(ResponseConsts.Mina.MSG));            continue;        }    
         LOGGER.info("{}>>>openId={}>>>[成功]", logPrefix, openId);    }}/** * 根据用户获取有效的推送码 * * @param openId 用户的openid * @return 推送码 */public String getValidFormId(String openId) {    List<FormTemplateVO> formTemplates = redisTemplate.opsForList().range("mina:openid:" + openId, 0, -1);    String validFormId = "";    int trimStart = 0;    int size;  
        for (int i = 0; i < (size = formTemplates.size()); i++) {        if (formTemplates.get(i).getExpire() > System.currentTimeMillis()) {            validFormId = formTemplates.get(i).getFormId();            trimStart = i + 1;            break;        }    }    // 移除本次使用的和已过期的    redisTemplate.opsForList().trim(KEY_MINA_PUSH + openId, trimStart == 0 ? size : trimStart, -1);    
       return validFormId;}

以上方案可以实现在用户最后一次使用小程序后的7天内,对用户发送多条模板消息唤回用户。

鸣谢本文作者:Joker_Coding

原文地址:https://www.jianshu.com/p/3b02d75ef0dc

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-03-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 极乐技术社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云开发 CloudBase
云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档