WeChat Mini Program - Cloud Development Polling Realizes Timing Push Subscription Messages

foreword

Audience: Have experience in small programs and cloud development (if not, it should be possible to follow the process and official documents)

Regarding the message push of the applet, I know the following implementation methods
1. The template message has been offline on January 10, 2020
2. Sending and pushing through the unified service message on the server side, 因为模板消息现已下线,现只支持公众号. Unified service news official document
2. Realize long-term news push through the official account by following the official account
3. Subscription news, including one-time subscription news and long-term subscription news
subscription news official document

Choices about technical implementation

Regarding the several implementations of message push for applets, let’s briefly talk about their respective advantages and disadvantages:

1. Unified service message

Advantages: Can be sent multiple times for a long time
Disadvantages: Because the template message is now offline, only official accounts are supported now

2. Realized through official account

Advantages: Can be sent multiple times for a long time
Disadvantages: You need to guide and follow the official account, if you don’t have an official account, you have to register one, and there are some precautions below

1. The Official Account and the Mini Program need to be on the same WeChat open platform to ensure that they have the same UnionID.
2. If you need to add the Mini Program entry to the message template, you need to associate the WeChat Official Account with the Mini Program.
3. The Mini Program Both the official account and the official account must be certified.
4. The applet needs to know the appid and appsecret of the official account
in advance. 5. Before sending a message, it is necessary to obtain the user’s openid corresponding to the official account.

3. Realization of subscription message

Subscription messages, including one-time subscription messages and long-term subscription messages, unfortunately长期订阅消息只对指定类目开放

One-time subscription message
Advantages: Both server and cloud development can implement push
Disadvantages: Authorization is required each time, and each authorization agrees to push only once

Hey, nothing to choose, 最终选择的是订阅消息的一次性订阅消息, the following is the official WeChat introduction

Applet subscription message

Features

The message capability is an important part of the applet capability. We provide developers with the ability to subscribe to messages in order to achieve a closed-loop service and a better experience.

  • Subscription message push location: service notification
  • Conditions for sending subscription messages: user self-subscription
  • Subscription message card jump ability: click to view details to jump to the page of the applet
    insert image description here

message type

1. One-time subscription to news

The one-time subscription message is used to solve the notification problem of the follow-up service link after the user uses the Mini Program. After the user subscribes independently, the developer can send a corresponding service message for an unlimited time; each message can be subscribed or unsubscribed separately.

2. Long-term subscription news

One-time subscription to messages can meet the needs of most service scenarios of Mini Programs, but there are scenarios in the field of offline public services that cannot be satisfied by one-time subscription, such as flight delays, and multiple notifications need to be sent according to the real-time status of the flight. To facilitate the service, we provide long-term subscription messages. After the user subscribes once, the developer can send multiple messages for a long time.

目前长期性订阅消息仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下公共服务业务。

3. Device subscription message

Device subscription message is a special type of subscription message, which belongs to the long-term subscription message type and needs to complete "device access" before it can be used.
The device subscription message is used to send a message notification to the user when the device triggers certain events that require manual intervention (such as a device failure, insufficient equipment supplies, etc.). See Device Subscription Message Documentation for details .

Instructions for use

Step 1: Obtain the template ID

Manually configure and obtain the template ID on the WeChat public platform:
log in to https://mp.weixin.qq.com to obtain the template. If there is no suitable template, you can apply to add a new template, which can be used after approval.
intro

Step 2: Obtain the distribution permission

One-time subscription message, long-term subscription message, see interface wx.requestSubscribeMessage for details

Device subscription message, see interface wx.requestSubscribeDeviceMessage for details

Step 3: Call the interface to send the subscription message

One-time subscription message, long-term subscription message, see server interface subscribeMessage.send for details

Device subscription message, see server interface hardwareDevice.send for details

Precautions

  • After the user checks "Always keep the above selection, don't ask again", the next subscription call wx.requestSubscribeMessage will not pop up, and the previous selection will be kept. To modify the selection, you need to open the applet settings to modify it.

accomplish

Design ideas

My requirement here is to push the anniversary. On the anniversary or a few days before the anniversary set by the user, a message needs to be pushed to the user to remind the user that the anniversary has arrived. Because it is a one-time authorization, the timing of the authorization must first be considered. Therefore, it is considered to set a switch where the user adds or edits the anniversary information. When it is turned on, the notification permission is judged. If there is no permission, it will remind you to turn on the notification on the settings page. If you have permission, you can request authorization. , the authorization success switch is turned on, the notification permission switch is turned off if it fails or is not turned on, and finally the information is submitted to the database, and the push interface will be polled once a day. According to this status and whether it is the reminder time of the anniversary day, it is judged whether to push or not, and the push is successful to reset the status . After the push, the user turns on the push switch again to realize the next push, forming a closed loop.

Please add a picture description

Implementation process

  • First go to the background of the applet to select a template
  • Then implement the logic of the design on the new edit page (including the judgment of notification permissions, requesting a one-time subscription, closing the switch status on failure, and saving data to the database)
  • Cloud development polls push messages (first find out the data that needs to be pushed, and then send the push corresponding to the data format of the template)

Implementation

1. Select a template

Log in to the applet development background - Subscribe to news - Search in the public template library to select a suitable template, and then you can view the template details in My Templates, and what needs to be 模板idused 详情里的字段in cloud development

insert image description here
insert image description here
insert image description here

2. Edit page code implementation

First of all, implement the page and logic related to the switch first, so I won’t go into details here.
Then judge the notification permission and request a one-time subscription

2.1. Judging notification authority

Judging the notification permission uses wx.getSetting

wx.getSetting({
    
    
  withSubscriptions: true,
  success (res) {
    
    
    console.log(res.authSetting)
    // res.authSetting = {
    
    
    //   "scope.userInfo": true,
    //   "scope.userLocation": true
    // }
    console.log(res.subscriptionsSetting)
    // res.subscriptionsSetting = {
    
    
    //   mainSwitch: true, // 订阅消息总开关
    //   itemSettings: {   // 每一项开关
    //     SYS_MSG_TYPE_INTERACTIVE: 'accept', // 小游戏系统订阅消息
    //     SYS_MSG_TYPE_RANK: 'accept'
    //     zun-LzcQyW-edafCVvzPkK4de2Rllr1fFpw2A_x0oXE: 'reject', // 普通一次性订阅消息
    //     ke_OZC_66gZxALLcsuI7ilCJSP2OJ2vWo2ooUPpkWrw: 'ban',
    //   }
    // }
  }
})

2.2. Request a one-time subscription

Request a one-time subscription using wx.requestSubscribeMessage

wx.requestSubscribeMessage({
    
    
  tmplIds: [''], // 模板id
  success (res) {
    
     }
})

2.3. Store data in cloud database

The data structure of each project is different, so I won’t expand on it here

core code

  // 是否提醒
  onSwitchChange: function (event) {
    
    
    this.setData({
    
    
      ["dict.isPush"]: event.detail.value
    })
    if (!event.detail.value) {
    
    
      this.setData({
    
    
        ["dict.pushTime"]: ''
      })
    }
    if (event.detail.value) {
    
    
      this.checkAndRequestSubscribeMessage()
    }
  },
  // 检查订阅消息权限,未开启提示前往开启,已开启请求订阅消息
  checkAndRequestSubscribeMessage() {
    
    
    let that = this
    wx.getSetting({
    
    
      withSubscriptions: true,
      success(res) {
    
    
        console.log(res.subscriptionsSetting)
        // 订阅消息总开关是否开启
        if (!res.subscriptionsSetting.mainSwitch) {
    
    
          that.subscriptionFailed()
          wx.showModal({
    
    
            title: '提示',
            content: '当前暂未开启接消息提醒,是否前往设置页开启?',
            success(res) {
    
    
              if (res.confirm) {
    
    
                wx.openSetting()
              }
            }
          })
        } else {
    
    
          let templateId = 'c64Gp5-89xyD55rnDr0oBWQNphWlNm_l4MX-Sduuj2c' // 模板ID
          wx.requestSubscribeMessage({
    
    
            tmplIds: [templateId],
            success(res) {
    
    
              console.log(res)
              // 申请订阅成功,将订阅信息调用云函数存入云开发数据
              if (res.errMsg === 'requestSubscribeMessage:ok') {
    
    
                // res[templateId]: 'accept'、'reject'、'ban'、'filter'
                if (res[templateId] == 'accept') {
    
    } else {
    
    
                  that.subscriptionFailed()
                }
              }
            },
            fail(err) {
    
    
              console.log(err)
              that.subscriptionFailed()
              wx.showToast({
    
    
                title: '订阅失败',
                icon: 'none'
              })
            }
          })
        }
      }
    })
  },
  // 订阅失败
  subscriptionFailed() {
    
    
    this.setData({
    
    
      ["dict.isPush"]: false
    })
  },

3. Cloud development polling push

Here is the point! ! ! First, right-click on the cloud function directory in the project to create a new cloud function, and then you need to implement the code for polling and pushing in this cloud function. The cloud function I built here ispush

insert image description here

3.1. Push

The push uses the subscribeMessage.send method of the server.
Here is the cloud call for push, so that you can use the cloud development and use to configure the API permission
subscribeMessage.sendin the cloud function code config.jsonfile . DetailssubscribeMessage.send

The configuration is as follows

  "permissions": {
    
    
    "openapi": ["subscribeMessage.send"]
  },

insert image description here

request parameters

Attributes type Defaults required illustrate
touser string yes The openid of the recipient (user)
templateId string yes The id of the subscription template to be delivered
page string no The jump page after clicking the template card is limited to the pages in this applet. Support parameters, (example index?foo=bar). If this field is not filled, the template will not jump.
data Object yes Template content, the format is like { "key1": { "value": any }, "key2": { "value": any } }
miniprogramState string no Jump applet type: developer is the development version; trial is the trial version; formal is the official version; the default is the official version
lang string no Enter the language type of the applet to view ", support zh_CN (Simplified Chinese), en_US (English), zh_HK (Traditional Chinese), zh_TW (Traditional Chinese), the default is zh_CN

Example of an official request

const cloud = require('wx-server-sdk')
cloud.init({
    
    
  env: cloud.DYNAMIC_CURRENT_ENV,
})
exports.main = async (event, context) => {
    
    
  try {
    
    
    const result = await cloud.openapi.subscribeMessage.send({
    
    
        "touser": 'OPENID',
        "page": 'index',
        "lang": 'zh_CN',
        "data": {
    
    
          "number01": {
    
    
            "value": '339208499'
          },
          "date01": {
    
    
            "value": '2015年01月05日'
          },
          "site01": {
    
    
            "value": 'TIT创意园'
          },
          "site02": {
    
    
            "value": '广州市新港中路397号'
          }
        },
        "templateId": 'TEMPLATE_ID',
        "miniprogramState": 'developer'
      })
    return result
  } catch (err) {
    
    
    return err
  }
}

miniprogramStateIn the formal environment, replace formalor comment out this line

3.2, Polling

Timed triggers for cloud development used by polling

insert image description here

Timed Trigger Official Introduction

This function requires developer tools version 1.02.1811270 and above to be used. Starting from developer tools 1.02.1910182, the newly uploaded timing trigger supports the use of cloud calls

  • If the cloud function needs to be executed regularly/regularly, that is, timing trigger, we can use the cloud function timing trigger. A cloud function configured with a timing trigger will be automatically triggered at the corresponding time point, and the return result of the function will not be returned to the caller.

  • Create a new file under the cloud function directory where the trigger needs to be added config.json. The format is as follows:

{
    
    
  // triggers 字段是触发器数组,目前仅支持一个触发器,即数组只能填写一个,不可添加多个
  "triggers": [
    {
    
    
      // name: 触发器的名字,规则见下方说明
      "name": "myTrigger",
      // type: 触发器类型,目前仅支持 timer (即 定时触发器)
      "type": "timer",
      // config: 触发器配置,在定时触发器下,config 格式为 cron 表达式,规则见下方说明
      "config": "0 0 2 1 * * *"
    }
  ]
}
official example

Some examples of Cron expressions and their associated meanings are shown below:

  • */5 * * * * * * means trigger every 5 seconds
  • 0 0 2 1 * * * means trigger at 2 am on the 1st day of each month
  • 0 15 10 * * MON-FRI * means trigger at 10:15 am every day from Monday to Friday
  • 0 0 10,14,16 * * * * means trigger at 10 am, 2 pm and 4 pm every day
  • 0 */30 9-17 * * * * means trigger every half hour from 9 am to 5 pm every day
  • 0 0 12 * * WED * means trigger every Wednesday at 12 noon

triggersThe fields in configcan control the frequency of triggering. When developing and testing, I used to call once every 50 seconds.

 "config": "*/50 * * * * * *"

这里有个坑,如果代码实现上传并部署云函数之后,左等右等在日志中看不到日志,因为少了一个步骤,在上传并部署云函数之后,需要右键云函数上传触发器,这样才生效,想关闭可以删除触发器

Polling to push the complete code

config.json

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

index.js

// 云函数入口文件
const cloud = require('wx-server-sdk')

// 初始化 cloud
cloud.init({
    
    
  // API 调用都保持和云函数当前所在环境一致
  env: cloud.DYNAMIC_CURRENT_ENV
})

const db = cloud.database()
const _ = db.command
const $ = db.command.aggregate
const kTableName = '换成自己的表名'

// 云函数入口函数
exports.main = async (event, context) => {
    
    
  try {
    
    
    // 从云开发数据库中查询等待发送的消息列表
    const msgArr = await db
      .collection(kTableName)
      // 查询条件,已开启推送,并且提醒时间为今天
      .where({
    
    
        A_IsPush: true,
        A_PushTime: timeStampToTime(new Date().getTime(), '{y}/{m}/{d}')
      })
      .get()

    // 循环消息列表
    const sendPromises = msgArr.data.map(async msgData => {
    
    
      try {
    
    
        // 发送订阅消息
        await cloud.openapi.subscribeMessage.send({
    
    
          touser: msgData._openid, // 要发送用户的openid
          page: 'pages/home/home', // 用户通过消息通知点击进入小程序的页面
          lang: 'zh_CN',
          templateId: 'c64Gp5-89xyD55rnDr0oBWQNphWlNm_l4MX-Sduuj2c', // 订阅消息模板ID
          // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
          // miniprogramState: 'developer',
          // 要发送的数据,要和模板一致
          data: {
    
    
            // 纪念日名称
            thing5: {
    
    
              value: msgData.A_Title
            },
            // 纪念日时间
            time2: {
    
    
              value: msgData.A_Time
            },
            // 备注
            thing4: {
    
    
              value: msgData.A_Remarks ? msgData.A_Remarks : '无'
            },
          }
        })
        // 发送成功后将数据状态重置
        return db
          .collection(kTableName)
          .doc(msgData._id)
          .update({
    
    
            data: {
    
    
              A_IsPush: false,
              A_PushTime: '',
              A_NextTime: '',
            },
          })
      } catch (e) {
    
    
        return e
      }
    })

    return Promise.all(sendPromises)
  } catch (err) {
    
    
    console.log(err)
    return err
  }
}

function timeStampToTime(time, cFormat) {
    
    
  if (arguments.length === 0) {
    
    
    return null
  }
  const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    
    } else {
    
    
    if (('' + time).length === 10) time = parseInt(time) * 1000
    date = new Date(time)
  }
  const formatObj = {
    
    
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    w: date.getDay()
  }
  const time_str = format.replace(/{(y|m|d|h|i|s|w)+}/g, (result, key) => {
    
    
    let value = formatObj[key]
    if (key === 'w') {
    
    
      return ['日', '一', '二', '三', '四', '五', '六'][value]
    }
    if (result.length > 0 && value < 10) {
    
    
      value = '0' + value
    }
    return value || 0
  })
  return time_str
}

// 定时触发器 
// https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/functions/triggers.html

// 50秒一次
// "config": "*/50 * * * * * *"

// 每天上午8点一次
// "config": "0 0 8 * * * *"

package.json

{
    
    
  "name": "push",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    
    
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    
    
    "wx-server-sdk": "~2.6.1"
  }
}

3.3. Upload and deploy cloud functions

After all the codes are implemented, you can first set the project environment as the development environment, then right-click to upload and deploy the cloud function, and then upload the trigger

insert image description here

Then open the cloud function console, select cloud function-log, and check the status. If it succeeds and there is data that needs to be pushed, the mobile phone will receive a push message. If it fails, modify it according to the log.

insert image description here
end here

Finally, I recommend my small program,我的纪念日小助手

Please add a picture description

Guess you like

Origin blog.csdn.net/iotjin/article/details/124149696