實戰分享: 小程序雲開發玩轉訂閱消息

微信官方爲提升小程序模板消息能力的使用體驗,對模板消息的下發條件進行了調整。原有的小程序模板消息接口於 2020 年 1 月 10 日下線,屆時將無法使用舊的小程序模板消息接口發送模板消息,取而代之的是新的一次性訂閱消息和長期訂閱消息。

訂閱消息給小程序開發者帶來了更好的觸達用戶的能力,在具體實施過程中,開發者如何把模板消息換成新的訂閱消息,是否需要購買服務器來實現服務器鑑權,怎樣才能在用戶訂閱之後一段時間後,給用戶發送長期或一次性訂閱消息呢?

小程序·雲開發最近支持了通過雲調用免 access_token 發送訂閱消息,還新增支持了在定時觸發器中實現雲調用,這些能力可以幫助開發者輕鬆玩轉小程序訂閱消息。

我們今天會利用小程序·雲開發進行一個小程序中實現訂閱開課提醒的實戰,幫助大家瞭解如何基於小程序·雲開發快速接入小程序訂閱消息。

開課提醒小程序界面

整體時序圖

開課提醒訂閱消息時序圖

環境準備

獲取訂閱消息模板 ID

在微信小程序管理後臺中,新增一個訂閱消息的模板,這裏我們新增了一個開課提醒的模板。

新增模板

引導用戶訂閱

微信小程序提供了wx.requestSubscribeMessage 接口來發起申請訂閱權限界面。

微信申請訂閱權限界面

在 "訂閱開課提醒" 的按鈕上綁定 tap 事件,事件處理器我們這裏用的 onSubscribe

index.wxml

<button
  class="btn"
  data-item="{{ item }}"
  bindtap="onSubscribe"
  hover-class="btn-hover"
>
  訂閱開課提醒
</button>

onSubscribe 函數內,我們會調用微信 API wx.requestSubscribeMessage 申請發送訂閱消息權限,當用戶在彈窗同意訂閱之後,我們會收到 success 回調,將訂閱的課程信息調用雲函數 subscribe 存入雲開發數據庫,雲函數 subscribe 的實現在下文會講。

index.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

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.jsonpermissions 中新增 subscribeMessage.send的雲調用權限,然後新增一個 sendMessagerTimer 的定時觸發器,定時觸發器的語法和 linuxcrontab 類似,比如,我們配置的 "0 * * * * * *" 代表每分鐘執行一次雲函數。

cloudfunctions/send/config.json

{
  "permissions": {
    "openapi": ["subscribeMessage.send"]
  },
  "triggers": [
    {
      "name": "sendMessagerTimer",
      "type": "timer",
      "config": "0 * * * * * *"
    }
  ]
}

接下來是實現發送訂閱消息的雲函數,這個雲函數會從雲開發數據庫集合messages中查詢等待發送的消息列表,檢查數據庫中是否有需要發送給用戶的訂閱消息,發送條件可以根據自己的業務實現,比如開課提醒可以根據課程開課日期來檢查是否需要發送訂閱消息,在我們下面的代碼示例裏做了簡化,篩選條件只檢查了狀態爲未發送。

查詢到待發送的消息列表之後,我們會循環消息列表,依次發送每條訂閱消息,發送成功後將數據庫中消息的狀態改爲已發送。

cloudfunctions/send/index.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


關於我

binggg(Booker Zhao) @騰訊

- 先後就職於迅雷、騰訊等,個人開源項目有 mrn.js 等
- 創辦了迅雷內部組件倉庫 XNPM ,參與幾個迅雷前端開源項目的開發
- 熱衷於優化和提效,是一個奉行“懶惰使人進步”的懶人工程師

社交資料

微信公衆號 binggg_net, 歡迎關注

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章