uni-app結合.NET 7實現微信小程序訂閱消息推送
目錄
- 功能介紹
- 消息類型
- 基本流程
- 注意事項
- 獲取模板ID
- uni-app代碼
- 服務端代碼
- 生成訂單
- 發送模板消息
- 總結
微信小程序的訂閱消息是小程序的重要能力之一,為實現服務的閉環提供更優的體驗。訂閱消息我們應該經常見到,比如下單成功之后的服務通知
,支付成功后的支付成功通知
,都屬于小程序的訂閱消息。
本文只實現一次性訂閱
的功能,至于長期訂閱
與設備訂閱
,有機會碰到再進行研究。
在開始之前,我們先看看微信小程序訂閱消息的介紹:
功能介紹
消息能力是小程序能力中的重要組成,我們為開發者提供了訂閱消息能力,以便實現服務的閉環和更優的體驗。
- 訂閱消息推送位置:服務通知
- 訂閱消息下發條件:用戶自主訂閱
- 訂閱消息卡片跳轉能力:點擊查看詳情可跳轉至該小程序的頁面
消息類型
1. 一次性訂閱消息
一次性訂閱消息用于解決用戶使用小程序后,后續服務環節的通知問題。用戶自主訂閱后,開發者可不限時間地下發一條對應的服務消息;每條消息可單獨訂閱或退訂。
2. 長期訂閱消息
一次性訂閱消息可滿足小程序的大部分服務場景需求,但線下公共服務領域存在一次性訂閱無法滿足的場景,如航班延誤,需根據航班實時動態來多次發送消息提醒。為便于服務,我們提供了長期性訂閱消息,用戶訂閱一次后,開發者可長期下發多條消息。
目前長期性訂閱消息僅向政務民生、醫療、交通、金融、教育等線下公共服務開放,后期將逐步支持到其他線下公共服務業務。
所以我們普通小程序,在注冊成功后,訂閱消息的模板選擇,只有一次性訂閱的選項,沒有長期訂閱的選項。
3. 設備訂閱消息
設備訂閱消息是一種特殊類型的訂閱消息,它屬于長期訂閱消息類型,且需要完成「設備接入」才能使用。
了解了小程序訂閱消息之后,我們開始進入正題!
基本流程
注意事項
由于后面的文章還很長,注意事項優先發出來,可能看到這里已經解決了你的問題。
- 一次性模板 id 和永久模板 id 不可同時使用。
- 低版本基礎庫2.4.4~2.8.3 已支持訂閱消息接口調用,僅支持傳入一個一次性 tmplId / 永久 tmplId。
- 2.8.2 版本開始,用戶發生點擊行為或者發起支付回調后,才可以調起訂閱消息界面
- 2.10.0 版本開始,開發版和體驗版小程序將禁止使用模板消息 formId。
- 一次授權調用里,每個 tmplId 對應的模板標題不能存在相同的,若出現相同的,只保留一個。
- 2.10.0 版本開始,支持訂閱語音消息提醒
特別注意第三條,版本庫是2.8.2及以上的時候,訂閱消息必須發生點擊行為或是發起支付回調后,才可以調起訂閱消息的界面。這個點擊行為沒有特別要求。比如一個表單,點擊提交按鈕后,也是可以調起訂閱消息界面的。支付后的回調不需要點擊行為,也可以調起訂閱消息界面。
獲取模板ID
在微信公眾平臺登錄小程序,在訂閱消息功能下,進入到我的模板,找到模板,并將模板id復制出來,如果沒有模板,需要先添加模板,再獲取模板id
要添加新模板,點擊選用
按鈕,在公共模板庫中選擇需要的模板,添加就可以了。
有很多文章說,如果沒有合適的模板,可以創建自定義模板。但如果你真想去創建自定義模板,會發現根本找不到地方。
如果想創建自定義模板,可通過以下方式進行。
1、點擊選用
按鈕,來到公共模板庫。(公共模板庫中的模板,與你小程序的服務類目相關)
2、在搜索框中,輸入比較長的關鍵詞。
3、點擊搜素,如果還是能匹配出模板來,則重新調整關鍵詞,直到沒有任何搜索結果為止。
4、點擊頁面中的幫忙我們完善模板庫
,進行自定義模板設置。
創建自定義模板的時候,一定要仔細閱讀申請模板的流程,尤其是第1條。我單拉出來重點標注一下,因為沒仔細看第1條,第一次申請的幾個模板白白等了好幾天。
模板標題需體現具體的服務場景,要求以“通知”或“提醒”結尾
,如:物流到貨通知、交易提醒。
看到這里,會發現以上大部分跟網上的文章沒啥區別,別急,正文來了!
uni-app代碼
前端實現的是點擊提交按鈕,保存表單,保存成功后發送訂閱消息,在pages/index/index.vue
下編寫如下代碼:
<template> <view> <view> <publishStep :list="setpList" :current="0" mode="number" active-color="#eb3572"></publishStep> </view> <view> <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></view> <view> <view> <u-button type="error" @click="submitForm" :loading="submit_loading">確認提交</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>
這里的流程分為3步:
1、提交表單,服務端返回訂單號(orderId)
2、使用uni.requestSubscribeMessage
,調起授權框,當點擊同意后,進入第三步。調起授權后,如果用戶同意,回調函數的參數subscribeMessageRes
有兩個對象:errMsg
和XXXXXXXXXXX
,errMsg不必多說。主要是這個XXXXXXXXXXX是什么。XXXXXXXXXXX是授權生成的,目測來看就是模板Id。
3、使用uni.login
,獲取code
。
4、將code
與orderId
發送到服務器,服務器通過code
獲取到openId
,再根據orderId
獲取到具體訂單數據。
5、發送模板消息。
如果不出意外的話,提交成功后,彈出如下授權框
服務端代碼
服務端ORM使用SqlSugar
,微信小程序接口使用SKIT.FlurlHttpClient.Wechat
庫。
生成訂單
提交訂單,這里只做演示,具體的代碼自己實現下就可以了!
[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; }}
發送模板消息
發送一次性訂閱的模板消息,傳的參數為前端獲取的code
與orderId
。根據訂單編號獲取訂單信息,以便在訂閱消息中,設置小程序信息以及打開路徑。code
用于獲取用戶的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;}
構造模板消息的時候,使用IDictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem> messageData = new Dictionary<string, CgibinMessageSubscribeSendRequest.Types.DataItem>
來進行構造,
假設一個模板消息的詳細內容是這樣的:
- 那么上面代碼中的params1 就是character_string22,同理params2就是thing7。也就是說。IDictionary的key就是模板中
.DATA
前面的內容。 messageRequest.TemplateId
,要與前端的模板Id一致。messageRequest.MiniProgramState
表示跳轉微信小程序的類型。默認為正式版- developer為開發版;
- trial為體驗版;
- formal為正式版;
如果不出意外的話,你的微信會收到服務通知。點擊卡片后,進入小程序的訂單詳情頁面!
總結
1、其實微信小程序的訂閱消息和公眾號的訂閱消息模板還是比較好申請的。如果在類目模板與歷史模板中無法找到合適自己的模板,那么自己申請一個模板。審核的話,2-3天就可以收到通知了。需要注意的是,申請模板的時候,最好把各項在本地保留一份。因為一旦提交申請,在公眾號或小程序后臺,你就找不到了。玩意審核沒通過,再申請的時候,前面寫的啥內容,已經忘的差不多了!
2、感謝SqlSugar
,為.Net開發者提供這么強大的ORM。真的是太方便了。
3、感謝SKIT.FlurlHttpClient.Wechat
,為.Net開發者提供這么便捷的工具。
4、為了能快速表達清楚意思,以上前端與服務端代碼,都是精簡過的,萬萬不可直接使用!
到此這篇關于uni-app結合.NET 7實現微信小程序訂閱消息推送的文章就介紹到這了,更多相關uni-app .NET 7小程序消息推送內容請搜索以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持!
