實戰分享: 小程式雲開發玩轉訂閱消息
- 2019 年 10 月 22 日
- 筆記
微信官方為提升小程式模板消息能力的使用體驗,對模板消息的下發條件進行了調整。原有的小程式模板消息介面於 2020 年 1 月 10 日下線,屆時將無法使用舊的小程式模板消息介面發送模板消息,取而代之的是新的一次性訂閱消息和長期訂閱消息。 訂閱消息給小程式開發者帶來了更好的觸達用戶的能力,在具體實施過程中,開發者如何把模板消息換成新的訂閱消息,是否需要購買伺服器來實現伺服器鑒權,怎樣才能在用戶訂閱之後一段時間後,給用戶發送長期或一次性訂閱消息呢? 小程式·雲開發最近支援了通過雲調用免 access_token 發送訂閱消息,還新增支援了在定時觸發器中實現雲調用,這些能力可以幫助開發者輕鬆玩轉小程式訂閱消息。 我們今天會利用小程式·雲開發進行一個小程式中實現訂閱開課提醒的實戰,幫助大家了解如何基於小程式·雲開發快速接入小程式訂閱消息。  ## 整體時序圖  ## 環境準備 – [註冊小程式帳號](https://tencentcloudbase.github.io/2019-09-03-wx-dev-guide-register/) – [開通雲開發服務](https://tencentcloudbase.github.io/2019-09-03-wx-dev-guide-service/) ## 獲取訂閱消息模板 ID 在微信小程式管理後台中,新增一個訂閱消息的模板,這裡我們新增了一個開課提醒的模板。  ## 引導用戶訂閱 微信小程式提供了`wx.requestSubscribeMessage` 介面來發起申請訂閱許可權介面。  在 “訂閱開課提醒” 的按鈕上綁定 tap 事件,事件處理器我們這裡用的 `onSubscribe` **index.wxml** “`javascript “` 在 `onSubscribe` 函數內,我們會調用微信 API `wx.requestSubscribeMessage` 申請發送訂閱消息許可權,當用戶在彈窗同意訂閱之後,我們會收到 `success` 回調,將訂閱的課程資訊調用雲函數 `subscribe` 存入雲開發資料庫,雲函數 `subscribe` 的實現在下文會講。 **index.js** “`js onSubscribe: function(e) { // 獲取課程資訊 const item = e.currentTarget.dataset.item; // 調用微信 API 申請發送訂閱消息 wx.requestSubscribeMessage({ // 傳入訂閱消息的模板id,模板 id 可在小程式管理後台申請 tmplIds: [lessonTmplId], success(res) { // 申請訂閱成功 if (res.errMsg === ‘requestSubscribeMessage:ok’) { // 這裡將訂閱的課程資訊調用雲函數存入雲開發數據 wx.cloud .callFunction({ name: ‘subscribe’, data: { data: item, templateId: lessonTmplId, }, }) .then(() => { wx.showToast({ title: ‘訂閱成功’, icon: ‘success’, duration: 2000, }); }) .catch(() => { wx.showToast({ title: ‘訂閱失敗’, icon: ‘success’, duration: 2000, }); }); } }, }); }, “` ## 將訂閱消息存入雲開發資料庫 接下來我們創建一個雲函數 `subscribe` ,這個雲函數的作用是將用戶的訂閱資訊存入雲開發資料庫的集合 `messages` 中,等待將來需要通知用戶時進行調用。 在微信開發者工具的雲開發面板中創建資料庫集合 `messages`  創建一個 `subscribe` 雲函數,在雲函數中我們將小程式端發送過來的課程訂閱資訊,存儲在雲開發資料庫集合中,開發完成後,在微信開發者工具中右鍵上傳並部署雲函數。 **cloudfunctions/subscribe/index.js** “`js const cloud = require(‘wx-server-sdk’); cloud.init(); const db = cloud.database(); exports.main = async (event, context) => { try { const {OPENID} = cloud.getWXContext(); // 在雲開發資料庫中存儲用戶訂閱的課程 const result = await db.collection(‘messages’).add({ data: { touser: OPENID, // 訂閱者的openid page: ‘index’, // 訂閱消息卡片點擊後會打開小程式的哪個頁面 data: event.data, // 訂閱消息的數據 templateId: event.templateId, // 訂閱消息模板ID done: false, // 消息發送狀態設置為 false }, }); return result; } catch (err) { console.log(err); return err; } }; “` ## 利用定時觸發器來定期發送訂閱消息 接下來我們需要實現一個定時執行的雲函數`send`,來檢查資料庫中是否有需要發送給用戶的訂閱消息。如果有需要發送的訂閱消息,會通過雲調用 `cloud.openapi.subscribeMessage.send` 將訂閱消息發送給用戶。 創建一個名叫 `send` 的雲函數,首先要配置雲函數,在 `config.json` 的 `permissions` 中新增 `subscribeMessage.send`的雲調用許可權,然後新增一個 `sendMessagerTimer` 的定時觸發器,定時觸發器的語法和 `linux` 的 `crontab` 類似,比如,我們配置的 `”0 * * * * * *”` 代表每分鐘執行一次雲函數。 **cloudfunctions/send/config.json** “`json { “permissions”: { “openapi”: [“subscribeMessage.send”] }, “triggers”: [ { “name”: “sendMessagerTimer”, “type”: “timer”, “config”: “0 * * * * * *” } ] } “` 接下來是實現發送訂閱消息的雲函數,這個雲函數會從雲開發資料庫集合`messages`中查詢等待發送的消息列表,檢查資料庫中是否有需要發送給用戶的訂閱消息,發送條件可以根據自己的業務實現,比如開課提醒可以根據課程開課日期來檢查是否需要發送訂閱消息,在我們下面的程式碼示例里做了簡化,篩選條件只檢查了狀態為未發送。 查詢到待發送的消息列表之後,我們會循環消息列表,依次發送每條訂閱消息,發送成功後將資料庫中消息的狀態改為已發送。 **cloudfunctions/send/index.js** “`js const cloud = require(‘wx-server-sdk’); exports.main = async (event, context) => { cloud.init(); const db = cloud.database(); try { // 從雲開發資料庫中查詢等待發送的消息列表 const messages = await db .collection(‘messages’) // 查詢條件這裡做了簡化,只查找了狀態為未發送的消息 // 在真正的生產環境,可以根據開課日期等條件篩選應該發送哪些消息 .where({ done: false, }) .get(); // 循環消息列表 const sendPromises = messages.data.map(async message => { try { // 發送訂閱消息 await cloud.openapi.subscribeMessage.send({ touser: message.touser, page: message.page, data: message.data, templateId: message.templateId, }); // 發送成功後將消息的狀態改為已發送 return db .collection(‘messages’) .doc(message._id) .update({ data: { done: true, }, }); } catch (e) { return e; } }); return Promise.all(sendPromises); } catch (err) { console.log(err); return err; } }; “` ## 最終效果  ## 源程式碼 [https://github.com/binggg/tcb-subscribe-demo](https://github.com/binggg/tcb-subscribe-demo) — ## 關於我 binggg(Booker Zhao) @騰訊 – 先後就職於迅雷、騰訊等,個人開源項目有 mrn.js 等 – 創辦了迅雷內部組件倉庫 XNPM ,參與幾個迅雷前端開源項目的開發 – 熱衷於優化和提效,是一個奉行「懶惰使人進步」的懶人工程師 ### 社交資料 – ? GitHub: [https://github.com/binggg](https://github.com/binggg) – ? 簡書: [https://www.jianshu.com/u/60f22559b79f](https://www.jianshu.com/u/60f22559b79f) – ? 掘金: [https://juejin.im/user/58d31f130ce4630057edb3ba](https://juejin.im/user/58d31f130ce4630057edb3ba) – ?️?️ 微博: [https://weibo.com/being99](https://weibo.com/being99) – ? 思否: [https://segmentfault.com/u/binggg](https://segmentfault.com/u/binggg) – ? 部落格園: [https://www.cnblogs.com/binggg/](https://www.cnblogs.com/binggg/) – ? 開源中國: [https://my.oschina.net/u/4217267](https://my.oschina.net/u/4217267) – ? 極術社區: [https://aijishu.com/u/binggg](https://aijishu.com/u/binggg) – ? 今日頭條: [https://www.toutiao.com/c/user/102306299647](https://www.toutiao.com/c/user/102306299647) – ?CSDN: [https://blog.csdn.net/weixin_42541867](https://blog.csdn.net/weixin_42541867) 微信公眾號 `binggg_net`, 歡迎關注