微信小程序模板消息限制實(shí)現(xiàn)無限制主動(dòng)推送的示例代碼
需求背景
基于微信的通知渠道,微信小程序?yàn)殚_發(fā)者提供了可以高效觸達(dá)用戶的模板消息能力,在用戶本人與小程序頁面有交互行為后觸發(fā),通過微信聊天列表中的服務(wù)通知可快捷進(jìn)入查看消息,點(diǎn)擊查看詳情還能跳轉(zhuǎn)到下發(fā)消息的小程序的指定頁面。
微信小程序允許下發(fā)模板消息的條件分為兩類:支付或者提交表單。通過提交表單來下發(fā)模板消息的限制為“允許開發(fā)者向用戶在7天內(nèi)推送有限條數(shù)的模板消息(1次提交表單可下發(fā)1條,多次提交下條數(shù)獨(dú)立,相互不影響)”。
然而,用戶1次觸發(fā)7天內(nèi)推送1條通知是明顯不夠用的。比如,簽到功能利用模板消息的推送來提醒用戶每天簽到,只能在用戶前一天簽到的情況下,獲取一次推送模板消息的機(jī)會(huì),然后用于第二天向該用戶發(fā)送簽到提醒。但是很多情況下,用戶在某一天忘記簽到,系統(tǒng)便失去了提醒用戶的權(quán)限,導(dǎo)致和用戶斷開了聯(lián)系;再比如,系統(tǒng)想主動(dòng)告知用戶即將做某活動(dòng),然而由于微信小程序被動(dòng)觸發(fā)通知的限制,系統(tǒng)將無法主動(dòng)推送消息。
如何突破模板消息的推送限制?
突破口:“1次提交表單可下發(fā)1條,多次提交下發(fā)條數(shù)獨(dú)立,相互不影響”
為了突破模板消息的推送限制,實(shí)現(xiàn)7天內(nèi)任性推送,只需收集到足夠的推送碼,即每次提交表單時(shí)獲取到的formId。一個(gè)formId代表著開發(fā)者有向當(dāng)前用戶推送模板消息的一次權(quán)限。
客戶端
收集推送碼
當(dāng)表單組件中的屬性report-submit=true時(shí)表示發(fā)送模板消息,提交表單便可以獲取formId。接下來只要對(duì)原先的頁面進(jìn)行改造,將用戶原先綁定了點(diǎn)擊事件的界面用表單組件中的button按鈕組件來代替,即把用戶的交互點(diǎn)擊的bindtap事件由表單bindsubmit來代替,從而捕獲用戶的點(diǎn)擊事件來生成更多的推送碼。
// 收集推送碼 Page({ formSubmit: funcition(e) { let formId = e.detail.formId; this.collectFormIds(formId); //保存推送碼 let type = e.detail.target.dataset.type; // 根據(jù)type執(zhí)行點(diǎn)擊事件 }, collectFormIds: function(formId) { let formIds = app.globalData.globalFormIds; // 獲取全局推送碼數(shù)組 if (!formIds) formIds = []; let data = { formId: formId, expire: new Data().getTime() + 60480000 // 7天后的過期時(shí)間戳 } formIds.push(data); app.globalData.globalFormIds = formIds; }, })
上報(bào)推送碼
等待用戶下一次發(fā)起網(wǎng)絡(luò)請(qǐng)求時(shí),將globalFormIds發(fā)送給服務(wù)器。
// 上報(bào)推送碼 Page({ onLoad: funcition(e) { this.uploadFormIds(); //上傳推送碼 }, collectFormIds: function(formId) { var formIds = app.globalData.globalFormIds; // 獲取全局推送碼 if (formIds.length) { formIds = JSON.stringify(formIds); // 轉(zhuǎn)換成JSON字符串 app.globalData.gloabalFomIds = ''; // 清空當(dāng)前全局推送碼 } wx.request({ // 發(fā)送到服務(wù)器 url: 'http://xxx', method: 'POST', data: { openId: 'openId', formIds: formIds }, success: function(res) { } }); }, })
服務(wù)端
存儲(chǔ)推送碼
高頻IO,采用Redis來存儲(chǔ)推送碼。
/** * 收集用戶推送碼 * * @param openId 用戶的openid * @param formTemplates 用戶的表單模板 */ public void collect(String openId, List<FormTemplateVO> formTemplates) { redisTemplate.opsForList().rightPushAll("mina:openid:" + openId, formTemplates); }
推送模板消息
下面實(shí)現(xiàn)了群發(fā)的功能,針對(duì)特定用戶類似。
/** * 推送消息 * * @param templateId 模板消息id * @param page 跳轉(zhuǎn)頁面 * @param keyWords 模板內(nèi)容 */ public void push(String templateId, String page, String keyWords) { String logPrefix = "推送消息"; // 獲取access token String accessToken = this.getAccessToken(); // 創(chuàng)建消息通用模板 MsgTemplateVO msgTemplateVO = MsgTemplateVO.builder().template_id(templateId).build(); // 跳轉(zhuǎn)頁面 msgTemplateVO.setPage(StringUtils.isNotBlank(page) ? page : ""); // 模板內(nèi)容 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); // 發(fā)送消息 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); } } /** * 根據(jù)用戶獲取有效的推送碼 * * @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; }
以上方案可以實(shí)現(xiàn)在用戶最后一次使用小程序后的7天內(nèi),對(duì)用戶發(fā)送多條模板消息喚回用戶。
- 微信小程序?qū)W習(xí)總結(jié)(三)條件、模板、文件引用實(shí)例分析
- 微信小程序?qū)W習(xí)總結(jié)(二)樣式、屬性、模板操作分析
- 微信小程序自定義導(dǎo)航欄(模板化)
- 微信小程序模板消息推送的兩種實(shí)現(xiàn)方式
- 微信小程序template模板與component組件的區(qū)別和使用詳解
- 微信小程序?qū)崿F(xiàn)發(fā)送模板消息功能示例【通過openid推送消息給用戶】
- 微信公眾平臺(tái) 發(fā)送模板消息(Java接口開發(fā))
- 微信小程序模板template簡單用法示例
- 微信小程序模板與設(shè)置WXML實(shí)例講解
相關(guān)文章
從URL中提取參數(shù)與將對(duì)象轉(zhuǎn)換為URL查詢參數(shù)的實(shí)現(xiàn)代碼
這兩種主要是對(duì)《Prototype淺析》先前略過的Sring部分中toQueryParams和Object部分的toQueryString方法的補(bǔ)充2012-01-01更優(yōu)雅的微信小程序骨架屏實(shí)現(xiàn)詳解
這篇文章主要介紹了更優(yōu)雅的微信小程序骨架屏實(shí)現(xiàn)詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08JavaScript使用Promise封裝Axios進(jìn)行高效開發(fā)
這篇文章主要介紹了JavaScript使用Promise封裝Axios進(jìn)行高效開發(fā),Axios是一個(gè)基于Promise的HTTP庫,它可以幫助我們更方便地發(fā)起HTTP請(qǐng)求,并且提供了許多高級(jí)功能,感興趣的同學(xué)可以參考下文2023-05-05JavaScript 幾種循環(huán)方式以及模塊化的總結(jié)
這篇文章主要介紹了JavaScript 幾種循環(huán)方式以及模塊化的的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)JavaScript,感興趣的朋友可以了解下2020-09-09JavaScript canvas實(shí)現(xiàn)流星特效
這篇文章主要為大家詳細(xì)介紹了JavaScript canvas實(shí)現(xiàn)流星特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05小程序雙頭slider選擇器的實(shí)現(xiàn)示例
這篇文章主要介紹了小程序雙頭slider選擇器的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03