⼩程序模板消息限制实现⽆限制主动推送的⽰例代码需求背景
基于的通知渠道,⼩程序为开发者提供了可以⾼效触达⽤户的模板消息能⼒,在⽤户本⼈与⼩程序页⾯有交互⾏为后触发,通过聊天列表中的服务通知可快捷进⼊查看消息,点击查看详情还能跳转到下发消息的⼩程序的指定页⾯。
⼩程序允许下发模板消息的条件分为两类:⽀付或者提交表单。通过提交表单来下发模板消息的限制为“允许开发者向⽤户在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;
let type = e.detail.pe; // 根据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 = ''; // 清空当前全局推送码
}
url: '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);
}
推送模板消息
下⾯实现了发的功能,针对特定⽤户类似。
/**
* 推送消息
*
* @param templateId 模板消息id
* @param page    跳转页⾯
* @param keyWords  模板内容
*/
public void push(String templateId, String page, String keyWords) {
String logPrefix = "推送消息";
// 获取access token
String accessToken = AccessToken();
// 创建消息通⽤模板
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 = w KeyWord(keyWordArr[i]);
keyWordMap.put(MsgTemplateVO.KEYWORD + (i + 1), keyWord);
}
msgTemplateVO.setData(keyWordMap);
} else {
msgTemplateVO.ptyMap());
}
// 获取所有⽤户
List<String> openIdList = AllOpenIds();
for (String openId : openIdList) {
// 获取有效推送码
String formId = ValidFormId(openId);
if (StringUtils.isBlank(formId)) {
<("{}>>>openId={}>>>已⽆有效推送码[失败]", logPrefix, openId); continue;
}
// 指派消息
MsgTemplateVO assignMsgTemplateVO = msgTemplateVO.assign(openId, formId);
// 发送消息
Map<String, Object> resultMap;
try {
String jsonBody = ObjectMapper().writeValueAsString(assignMsgTemplateVO);
String resultBody = Instance().postAsString(messageUrl + accessToken, jsonBody);
resultMap = ObjectMapper().readValue(resultBody, Map.class);
} catch (IOException e) {
<("{}>>>openId={}>>>{}[失败]", logPrefix, openId, e.getMessage(), e);
continue;
}
if ((int) (ResponseConsts.Mina.CODE) != 0) {
<("{}>>>openId={}>>>{}[失败]", logPrefix, openId, (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 ((i).getExpire() > System.currentTimeMillis()) {
validFormId = (i).getFormId();
trimStart = i + 1;
break;
}
}
// 移除本次使⽤的和已过期的
redisTemplate.opsForList().trim(KEY_MINA_PUSH + openId, trimStart == 0 ? size : trimStart, -1);
return validFormId;
}
以上⽅案可以实现在⽤户最后⼀次使⽤⼩程序后的7天内,对⽤户发送多条模板消息唤回⽤户。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。