The subscription message of WeChat Mini Program is one of the important capabilities of the Mini Program, which provides a better experience for realizing the closed-loop service. We should often see subscription messages. For example, after the order is successfully placed and 服务通知
the payment is successful 支付成功通知
, they all belong to the subscription message of the applet.
This article only implements 一次性订阅
the functions, as for 长期订阅
and 设备订阅
, if you have the opportunity to meet and then conduct research.
Table of contents
Before we start, let's take a look at the introduction of the WeChat 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
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.
目前长期性订阅消息仅向政务民生、医疗、交通、金融、教育等线下公共服务开放,后期将逐步支持到其他线下公共服务业务。
Therefore, for our ordinary applets, after successful registration, the template selection of subscription news only has the option of one-time subscription, and there is no option of long-term subscription.
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.
After learning about subscribing to news from the applet, let's get down to business!
basic process
Precautions
Since the following article is still very long, the precautions are issued first, and you may see that your problem has been solved here.
- One-time template id and permanent template id cannot be used at the same time.
- The lower version basic library 2.4.4~2.8.3 already supports the subscription message interface call, and only supports passing in a one-time tmplId/permanent tmplId.
- Starting from version 2.8.2, the subscription message interface can only be invoked after the user clicks or initiates a payment callback
- Starting from version 2.10.0, the development version and trial version of the applet will prohibit the use of the template message formId.
- In an authorization call, the template titles corresponding to each tmplId cannot exist the same, if there are the same, only one will be kept.
- Starting from version 2.10.0, it supports subscribing to voice message reminders
Pay special attention to the third item. When the version library is 2.8.2 or above, the subscription message interface must be invoked after a click action or a payment callback is initiated. There are no special requirements for this click behavior. For example, for a form, after clicking the submit button, the subscription message interface can also be invoked. The callback after payment does not need to be clicked, and the subscription message interface can also be invoked.
Get template ID
Log in to the mini program on the WeChat public platform, under the subscription message function, enter My template, find the template, and copy the template id. If there is no template, you need to add the template first, and then get the template id
To add a new template, click 选用
the button, select the desired template in the public template library, and add it.
There are many articles that say that if there is no suitable template, you can create a custom template . But if you really want to create a custom template, you will find that there is nowhere to be found.
If you want to create a custom template, you can do it in the following ways.
1. Click 选用
the button to come to the public template library. (The templates in the public template library are related to the service category of your Mini Program)
2. In the search box, enter a relatively long keyword.
3. Click Search, if the template can still be matched, then re-adjust the keywords until there is no search result.
4. Click on the page 帮忙我们完善模板库
to set the custom template.
When creating a custom template, be sure to carefully read the process of applying for a template, especially Article 1. I just pulled it out and highlighted it, because I didn't read Article 1 carefully, and I waited for several days for the first few templates for the first application.
The title of the template needs to reflect specific service scenarios, 要求以“通知”或“提醒”结尾
such as: logistics arrival notification, transaction reminder.
Seeing this, you will find that most of the above are no different from the articles on the Internet. Don't worry, the main text is here!
uni-app code
The front-end implementation is to click the submit button, save the form, and send a subscription message after the save is successful. Write the following code pages/index/index.vue
below :
<template>
<view>
<view class="setp">
<publishStep :list="setpList" :current="0" mode="number" active-color="#eb3572"></publishStep>
</view>
<view class="container">
<u-form :model="form" ref="uForm" :rules="rules" :error-type="errorType">
<u-form-item label="姓名" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}" prop="realName">
<u-input v-model="form.realName" placeholder="" input-align="right" />
</u-form-item>
<u-form-item label="服务时间" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}"
right-icon="arrow-right" prop="serviceTime">
<u-input v-model="form.serviceTime" placeholder="请选择服务时间" :disabled="true" input-align="right" @click="timeShow=true" />
</u-form-item>
<u-form-item label="服务地址" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}" prop="serviceAddress">
<u-input v-model="form.serviceAddress" placeholder="" input-align="right" @click="selectAddress" />
</u-form-item>
<u-form-item label="联系电话" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}"
prop="lxtel">
<u-input v-model="form.lxtel" type="number" placeholder="请输入联系电话" input-align="right" :clearable="false" />
</u-form-item>
<u-form-item label="需求描述" label-width="160rpx" :border-bottom="true" :label-style="{'font-size':'28rpx'}"
prop="remarks">
<u-input v-model="form.remarks" type="text" placeholder="请输入您的需求" input-align="right" :clearable="false" />
</u-form-item>
</u-form>
</view>
<view style="height: 160rpx;"></view>
<view class="bottom_nav">
<view class="buttom_box padding-horizontal-20 padding-vertical-10">
<u-button type="error" @click="submitForm" :loading="submit_loading" style="height: 100rpx; font-weight: bold; font-size: 36rpx;">确认提交</u-button>
</view>
</view>
<u-picker mode="time" v-model="timeShow" :params="timeParams" @confirm="timeConfirm"></u-picker>
</view>
</template>
<script>
export default {
data() {
return {
form:{
realName:"",
serviceTime:'',
serviceAddress:"",
lxtel:"",
remarks:""
},
rules:{
realName: [{
required: true,
message: "请填写您的姓名",
trigger: 'change'
}],
serviceTime: [{
required: true,
message: "请选择服务时间",
trigger: 'change'
}],
lxtel: [{
required: true,
message: "请输入联系电话",
trigger: 'change'
}],
},
errorType: ['toast'],
timeShow:false,
timeParams:{
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
},
submit_loading:false,
}
},
onReady() {
this.$refs.uForm.setRules(this.rules);
},
onLoad(params) {
let that = this;
},
methods: {
timeConfirm(e){
let that = this;
that.form.serviceTime = e.year +"-"+e.month+"-"+e.day
},
gotoOrder(){
uni.redirectTo({
url:"/pages/order/order"
})
},
submitForm(){
let that = this;
this.$refs.uForm.validate(valid=>{
if (valid){
that.$u.api.submit_order(that.form).then(res => {
if (res.success) {
let data = res.data;
uni.showToast({
title: '提交成功',
icon: 'success'
})
// #ifdef MP-WEIXIN
uni.requestSubscribeMessage({
tmplIds:['XXXXXXXXXXX'], //这里填写tempid
success:function(subscribeMessageRes){
if(subscribeMessageRes.errMsg=="requestSubscribeMessage:ok"){
if(subscribeMessageRes.XXXXXXXXXXX=="accept"){
uni.login({
provider: 'weixin',
success:function(loginRes){
if(loginRes.errMsg=="login:ok"){
const code = loginRes.code;
that.$u.api.sendSubscribeMessage({
"code":code,
"orderId":data.orderId
}).then(res=>{
that.gotoOrder()
})
}else{
that.gotoOrder()
}
},
fail() {
that.gotoOrder()
}
})
}else{
that.gotoOrder()
}
}else{
that.gotoOrder()
}
},
fail:function(){
that.gotoOrder()
}
})
// #endif
} else {
uni.$u.toast(res.message);
}
});
}
})
}
}
}
</script>
<style>
.setp{
padding: 40rpx 0;}
.bottom_nav {
position: fixed;
width: 100%;
height: 100rpx;
left: 0;
bottom: 0;
z-index: 9999;
background: #FFFFFF;
border-top: 1rpx #f3f3f3 solid;
}
</style>
The process here is divided into 3 steps:
1. Submit the form, and the server will return the order number (orderId)
2. Use uni.requestSubscribeMessage
, call up the authorization box, and enter the third step after clicking Agree. After invoking the authorization, if the user agrees, the parameters of the callback function subscribeMessageRes
have two objects: errMsg
and XXXXXXXXXXX
, errMsg Needless to say. Mainly what this XXXXXXXXXX is. XXXXXXXXXXXX is generated by authorization, which is the template ID by visual inspection.
3. Use uni.login
, obtain code
.
4. Send code
and orderId
send to the server, the server code
obtains it openId
, and then orderId
obtains the specific order data according to the acquisition.
5. Send template message.
If nothing unexpected happens, after the submission is successful, the following authorization box will pop up
server code
The server-side ORM is used SqlSugar
, and the WeChat applet interface uses SKIT.FlurlHttpClient.Wechat
the library.
Generate orders
Submit the order , here is only a demonstration, the specific code can be realized by yourself!
[HttpPost]
public async Task<AjaxResult> SubmitOrder(order model)
{
//生成订单号
model.order_no = DateTime.Now.ToString("yyyyMMddHHssfffff");
model.addtime = DateTime.Now;
//ExecuteReturnIdentity方法会返回自增id
var id = await db.Insertable(model).ExecuteReturnIdentity();
return new AjaxResult(){
success=true,
data = id
};
}
AjaxResult.cs
public class AjaxResult
{
/// <summary>
/// 是否成功
/// </summary>
public bool success {
get; set; } = true;
/// <summary>
/// 错误代码
/// </summary>
public int code {
get; set; } = 0;
/// <summary>
/// 返回消息
/// </summary>
public string message {
get; set; }
/// <summary>
/// 返回数据
/// </summary>
public object data{
get; set;}
}
order.cs
[SugarTable("order")]
public class order
{
/// <summary>
/// 主键,自增Id
/// </summary>
[SugarColumn(IsPrimaryKey = true)]
public int id {
get; set; }
/// <summary>
/// 订单编号
/// </summary>
public string order_no {
get; set; }
/// <summary>
/// 姓名
/// </summary>
public string realName {
get; set; }
/// <summary>
/// 时间
/// </summary>
public DateTime serviceTime {
get; set; }
/// <summary>
/// 地址
/// </summary>
public string serviceAddress {
get; set; }
/// <summary>
/// 联系电话
/// </summary>
public string lxtel {
get; set; }
/// <summary>
/// 备注
/// </summary>
public string remarks {
get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime addtime {
get; set; }
}
send template message
Send a template message for one-time subscription, and the passed parameters are obtained by the front code
end orderId
. Obtain the order information according to the order number, so as to set the applet information and open path in the subscription message. code
Used to get users openId
.
[HttpPost]
public async Task<AjaxResult> SendSubscribeMessage(string code,string orderId)
{
AjaxResult result = new AjaxResult();
if (string.IsNullOrEmpty(code) || string.IsNullOrEmpty(orderId))
{
result.success = false;
result.message = "参数错误";
return result;
}
var order_model = await db.Queryable<order>().InSingleAsync(orderId);
if(order_model is null)
{
result.success = false;
result.message = "参数错误";
return result;
}
//初始化WechatApiClient
var options = new WechatApiClientOptions()
{
AppId = "appId",
AppSecret = "appSecret "
};
var client = new WechatApiClient(options);
//获取openId
var request = new SnsJsCode2SessionRequest();
request.JsCode = code;
var response = await client.ExecuteSnsJsCode2SessionAsync(request);
string openId = response.OpenId;
//获取token
var tokenRequest = new CgibinTokenRequest();
var tokenResponse = await client.ExecuteCgibinTokenAsync(tokenRequest);
var token = tokenResponse.AccessToken;
//发送模板消息
var messageRequest = new CgibinMessageSubscribeSendRequest();
IDictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> messageData = new Dictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem>
{
{
"params1",
new CgibinMessageSubscribeSendRequest.Types.DataItem() {
Value=order_model.order_no}
},
{
"params1",
new CgibinMessageSubscribeSendRequest.Types.DataItem(){
Value=order_model.userNmae}
},
{
"params3",
new CgibinMessageSubscribeSendRequest.Types.DataItem(){
Value=order_model.serviceTime}
},
{
"params4",
new CgibinMessageSubscribeSendRequest.Types.DataItem(){
Value=order_model.serviceAddress}
},
{
"params5",
new CgibinMessageSubscribeSendRequest.Types.DataItem(){
Value=order_model.addtime.ToString("yyyy-MM-dd HH:ss")}
}
};
messageRequest.AccessToken = token;
messageRequest.ToUserOpenId = openId;
messageRequest.TemplateId = "XXXXXXXXXXX";
messageRequest.MiniProgramState = "developer";
//微信小程序要跳转的地址。可以加参数
messageRequest.MiniProgramPagePath = "/pages/order/order_details?id=" + order_model.id;
messageRequest.Data = messageData;
var messageResponse = await client.ExecuteCgibinMessageSubscribeSendAsync(messageRequest);
if(messageResponse.ErrorCode==0)
{
result.success=true;
result.message = "ok";
return result;
}
result.success = false;
result.message = "error";
return result;
}
When constructing a template message, use IDictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> messageData = new Dictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem>
to construct,
assuming that the detailed content of a template message is as follows:
- Then params1 in the above code is character_string22, and params2 is thing7 in the same way. That is. The key of IDictionary is
.DATA
the previous content in the template. messageRequest.TemplateId
, which must be consistent with the template Id of the front end.messageRequest.MiniProgramState
Indicates the type of redirected WeChat applet. The default is the official version- developer is the development version;
- trial is the trial version;
- formal is the official version;
If nothing else, your WeChat will receive a service notification. After clicking the card, enter the order details page of the mini program!
Summarize
1. In fact, it is relatively easy to apply for the subscription message of the WeChat applet and the subscription message template of the official account. If you cannot find a template suitable for you in the category templates and history templates, then apply for a template yourself. If it is reviewed, you can receive a notification within 2-3 days.
需要注意的是,申请模板的时候,最好把各项在本地保留一份。因为一旦提交申请,在公众号或小程序后台,你就找不到了。玩意审核没通过,再申请的时候,前面写的啥内容,已经忘的差不多了!
2. Thank you SqlSugar
for providing such a powerful ORM for .Net developers. It's really convenient.
3. Thanks SKIT.FlurlHttpClient.Wechat
for providing such a convenient tool for .Net developers.
4. In order to quickly express the meaning clearly, the above front-end and server-side codes are all simplified and must not be used directly! ,
Click on the official account card below to follow me! Learn together and progress together!