首頁  >  文章  >  後端開發  >  實作微信小程式範本訊息不受限制、無限主動推送

實作微信小程式範本訊息不受限制、無限主動推送

韦小宝
韦小宝原創
2018-03-01 14:55:599509瀏覽

需求背景

基於微信的通知管道,微信小程式為開發者提供了可以高效觸達用戶的模板訊息能力,在用戶本人與小程式頁面有交互行為後觸發,透過微信聊天清單中的服務通知可快速進入檢視訊息,點選查看詳情還能跳到下方訊息的小程式的指定頁面。

微信小程式允許下發範本訊息的條件分為兩類:付款或提交表單。透過提交表單來下發範本訊息的限制為「允許開發者向使用者在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);
}

推送範本訊息

#下面實作了群發的功能,針對特定使用者類似。

/**
* 推送消息
*
* @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天內,對使用者發送多個範本訊息喚回使用者。

這就是實作微信小程式範本訊息不受限制、無限主動推送的方法詳細的所有內容。

相關文章:

微信小程式訊息推送php伺服器驗證

以上是實作微信小程式範本訊息不受限制、無限主動推送的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn