C#開發(fā)微信門戶及應(yīng)用(29)--微信個性化菜單的實(shí)現(xiàn)
有一段時間沒有接著微信的主題繼續(xù)介紹里面的功能模塊了,這段時間來,微信也做了不少的變化改動,針對這些特性我全面核對了一下相關(guān)的微信公眾號和企業(yè)號的接口,對原有的微信API和系統(tǒng)管理做了全面的更新,本隨筆以及后面的隨筆就是基于這個工作上的總結(jié),以期把微信涉及的功能模塊,都使用C#實(shí)現(xiàn)的方式來介紹。本隨筆主要介紹微信公眾號的個性化菜單的實(shí)現(xiàn),雖然目前微信公眾號和企業(yè)號已經(jīng)在功能上接近一致,不過在企業(yè)號上還沒有個性化菜單的相關(guān)接口。
1、個性化菜單介紹
我們先了解一下個性化菜單的介紹,根據(jù)官方的資料,如下介紹。
為了幫助公眾號實(shí)現(xiàn)靈活的業(yè)務(wù)運(yùn)營,微信公眾平臺新增了個性化菜單接口,開發(fā)者可以通過該接口,讓公眾號的不同用戶群體看到不一樣的自定義菜單。該接口開放給已認(rèn)證訂閱號和已認(rèn)證服務(wù)號。
開發(fā)者可以通過以下條件來設(shè)置用戶看到的菜單:
1、用戶分組(開發(fā)者的業(yè)務(wù)需求可以借助用戶分組來完成) 2、性別 3、手機(jī)操作系統(tǒng) 4、地區(qū)(用戶在微信客戶端設(shè)置的地區(qū)) 5、語言(用戶在微信客戶端設(shè)置的語言)
個性化菜單接口說明:
1、個性化菜單要求用戶的微信客戶端版本在iPhone6.2.2,Android 6.2.4以上。 2、菜單的刷新策略是,在用戶進(jìn)入公眾號會話頁或公眾號profile頁時,如果發(fā)現(xiàn)上一次拉取菜單的請求在5分鐘以前,就會拉取一下菜單,如果菜單有更新,就會刷新客戶端的菜單。測試時可以嘗試取消關(guān)注公眾賬號后再次關(guān)注,則可以看到創(chuàng)建后的效果。 3、普通公眾號的個性化菜單的新增接口每日限制次數(shù)為2000次,刪除接口也是2000次,測試個性化菜單匹配結(jié)果接口為20000次 4、出于安全考慮,一個公眾號的所有個性化菜單,最多只能設(shè)置為跳轉(zhuǎn)到3個域名下的鏈接 5、創(chuàng)建個性化菜單之前必須先創(chuàng)建默認(rèn)菜單(默認(rèn)菜單是指使用普通自定義菜單創(chuàng)建接口創(chuàng)建的菜單)。如果刪除默認(rèn)菜單,個性化菜單也會全部刪除
個性化菜單匹配規(guī)則說明:
當(dāng)公眾號創(chuàng)建多個個性化菜單時,將按照發(fā)布順序,由新到舊逐一匹配,直到用戶信息與matchrule相符合。如果全部個性化菜單都沒有匹配成功,則返回默認(rèn)菜單。 例如公眾號先后發(fā)布了默認(rèn)菜單,個性化菜單1,個性化菜單2,個性化菜單3。那么當(dāng)用戶進(jìn)入公眾號頁面時,將從個性化菜單3開始匹配,如果個性化菜單3匹配成功,則直接返回個性化菜單3,否則繼續(xù)嘗試匹配個性化菜單2,直到成功匹配到一個菜單。 根據(jù)上述匹配規(guī)則,為了避免菜單生效時間的混淆,決定不予提供個性化菜單編輯API,開發(fā)者需要更新菜單時,需將完整配置重新發(fā)布一輪。
除正常的默認(rèn)菜單外,個性化菜單提供了下面幾個處理操作。
1 創(chuàng)建個性化菜單
2 刪除個性化菜單
3 測試個性化菜單匹配結(jié)果
4 查詢個性化菜單
5 刪除所有菜單
個性化自定義菜單功能,是指商家可以根據(jù)粉絲的分組、性別、手機(jī)操作系統(tǒng),甚至地區(qū),來分別展示公眾號的菜單。
比如,一家健身會所的公眾號,將自定義菜單根據(jù)粉絲性別進(jìn)行了分開設(shè)置。男性粉絲進(jìn)入公眾號會展示男生們比較感興趣菜單內(nèi)容,跆拳道、搏擊等;若是女性粉絲,則會展示瑜伽、舞蹈、防身術(shù)等女性粉絲感興趣的菜單課程等。
?
2、個性化菜單的C#設(shè)計(jì)處理
微信的菜單是微信處理中很重要的一環(huán),因?yàn)樗俏⑿沤o用戶入口體驗(yàn)重要的一環(huán),也是很直觀的界面呈現(xiàn)之一,菜單的展示就是需要我們絞盡腦汁來精簡的界面元素了,由于菜單的重要性以及功能的豐富性,我在之前好幾篇隨筆專門介紹了菜單的各種處理。
在《C#開發(fā)微信門戶及應(yīng)用(6)--微信門戶菜單的管理操作》、《C#開發(fā)微信門戶及應(yīng)用(9)-微信門戶菜單管理及提交到微信服務(wù)器》、《C#開發(fā)微信門戶及應(yīng)用(11)--微信菜單的多種表現(xiàn)方式介紹》、《C#開發(fā)微信門戶及應(yīng)用(20)-微信企業(yè)號的菜單管理》分別對相關(guān)的菜單有過介紹,有需要可以參考了解一下。
菜單模塊,在微信公眾號和企業(yè)號,它們都可以共用一個模型,因此我們把這些內(nèi)容都放在微信共用模塊里面,包括它的實(shí)體類信息(如菜單模塊),雖然有些地方,部分字段內(nèi)容沒有,但是我們可以通過實(shí)體類的JSON標(biāo)識來進(jìn)行處理,從而實(shí)現(xiàn)比較彈性化的實(shí)體類信息承載。
如下標(biāo)識代碼所示。
/// <summary> /// 菜單基本信息(公眾號、企業(yè)號公用,其他部分一樣) /// </summary> public class MenuJson : BaseJsonResult { /// <summary> /// 按鈕描述,既按鈕名字,不超過16個字節(jié),子菜單不超過40個字節(jié) /// </summary> public string name { get; set; } /// <summary> /// 按鈕類型(click或view) /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string type { get; set; } /// <summary> /// 按鈕KEY值,用于消息接口(event類型)推送,不超過128字節(jié) /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string key { get; set; } /// <summary> /// 網(wǎng)頁鏈接,用戶點(diǎn)擊按鈕可打開鏈接,不超過256字節(jié) /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string url { get; set; } /// <summary> /// media_id類型和view_limited類型必須,調(diào)用新增永久素材接口返回的合法media_id /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public string media_id { get; set; } /// <summary> /// 子按鈕數(shù)組,按鈕個數(shù)應(yīng)為2~5個 /// </summary> [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public List<MenuJson> sub_button { get; set; }
上面這個實(shí)體類是菜單信息的基礎(chǔ)信息,我們需要從這個基礎(chǔ)上擴(kuò)展出來幾個實(shí)體類,方便在構(gòu)建,獲取菜單信息的時候進(jìn)行信息轉(zhuǎn)換,如下幾個類圖的設(shè)計(jì)所示。
通過這幾個類的關(guān)系,我們就可以適應(yīng)所有的默認(rèn)菜單和個性化菜單,以及企業(yè)號的菜單信息轉(zhuǎn)換處理了,通過JSON轉(zhuǎn)換為對應(yīng)的實(shí)體類,實(shí)現(xiàn)信息的強(qiáng)類型處理。
其中我們菜單處理的API實(shí)現(xiàn)類代碼如下所示。
/// <summary> /// 菜單的相關(guān)操作 /// </summary> public class MenuApi : IMenuApi
這樣我們在IMenuApi的基礎(chǔ)上增加幾個個性化的接口。
/// <summary> /// 創(chuàng)建個性化菜單 /// </summary> /// <param name="accessToken">調(diào)用接口憑證</param> /// <param name="menuJson">菜單對象</param> /// <returns></returns> string CreateConditionalMenu(string accessToken, MenuListJson menuJson); /// <summary> /// 根據(jù)菜單ID刪除個性化菜單 /// </summary> /// <param name="accessToken">調(diào)用接口憑證</param> /// <param name="menuid">菜單ID</param> /// <returns></returns> CommonResult DeleteConditionalMenu(string accessToken, string menuid); /// <summary> /// 測試個性化菜單匹配結(jié)果 /// </summary> /// <param name="accessToken">調(diào)用接口憑證</param> /// <returns></returns> MenuListJson TryMatchConditionalMenu(string accessToken, string user_id);
然后在MenuApi實(shí)現(xiàn)類里面實(shí)現(xiàn)相關(guān)的邏輯處理即可。
下面是創(chuàng)建個性化菜單的接口說明。
創(chuàng)建個性化菜單
http請求方式:POST(請使用https協(xié)議)
https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN
請求示例
{ "button":[ { "type":"click", "name":"今日歌曲", "key":"V1001_TODAY_MUSIC" }, { "name":"菜單", "sub_button":[ { "type":"view", "name":"搜索", "url":"http://www.soso.com/" }, { "type":"view", "name":"視頻", "url":"http://v.qq.com/" }, { "type":"click", "name":"贊一下我們", "key":"V1001_GOOD" }] }], "matchrule":{ "group_id":"2", "sex":"1", "country":"中國", "province":"廣東", "city":"廣州", "client_platform_type":"2" "language":"zh_CN" } }
其中上面的信息,轉(zhuǎn)換為我們的實(shí)體類對象信息就是如下所示。
MenuListJson menuJson
它API返回結(jié)果如下所示。
{ "menuid":"208379533" }
為了承載這個信息,我們需要定義一個實(shí)體類來承載這個信息。
/// <summary> /// 返回MenuId的結(jié)果 /// </summary> public class MenuIdResult { /// <summary> /// 菜單的ID /// </summary> public string menuid { get; set; } }
最后我們的API接口只需要獲取里面的菜單ID值,字符串類型的就可以了,API具體實(shí)現(xiàn)代碼如下所示。
/// <summary> /// 創(chuàng)建個性化菜單 /// </summary> /// <param name="accessToken">調(diào)用接口憑證</param> /// <param name="menuJson">菜單對象</param> /// <returns></returns> public string CreateConditionalMenu(string accessToken, MenuListJson menuJson) { string result = ""; var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token={0}", accessToken); //matchrule不能為空 ArgumentValidation.CheckForNullReference(menuJson.matchrule, "matchrule"); string postData = menuJson.ToJson(); MenuIdResult list = JsonHelper<MenuIdResult>.ConvertJson(url, postData); if (list != null) { result = list.menuid; } return result; }
而刪除個性化菜單的接口也是類似的處理,如下所示。
/// <summary> /// 根據(jù)菜單ID刪除個性化菜單 /// </summary> /// <param name="accessToken">調(diào)用接口憑證</param> /// <param name="menuid">菜單ID</param> /// <returns></returns> public CommonResult DeleteConditionalMenu(string accessToken, string menuid) { var url = string.Format("https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token={0}", accessToken); var data = new { menuid = menuid }; string postData = data.ToJson(); return Helper.GetExecuteResult(url, postData); }
另外,對于個性化菜單來說,查詢、刪除所有的菜單操作接口和普通默認(rèn)菜單是一樣的,因此可以重用這兩個接口,不過由于我們擴(kuò)展了查詢返回的信息類,所以如果是個性化菜單,那么它返回的JSON字符串里面,包含了conditionalmenu的屬性,這個是一個集合 ,也就是說個性化菜單是多個規(guī)則的個性化菜單的集合。
菜單的JSON數(shù)據(jù)結(jié)構(gòu)如下所示。
?
3、個性化菜單封裝接口的使用
有了上面接口的封裝,我們可以在創(chuàng)建個性化菜單的時候很方便了,構(gòu)建個性化菜單的時候,我們需要把全部需要出現(xiàn)的菜單都需要放在一個conditionalmenu的單元里面,雖然這樣的單元在集合里面出現(xiàn)多個。
如下面是構(gòu)建一個個性化的菜單項(xiàng)目,和普通的默認(rèn)菜單不同,它需要指定一個matchrule的對象,如下代碼所示。
MenuJson conditional = new MenuJson("相關(guān)鏈接", new MenuJson[] { new MenuJson("個性化菜單", ButtonType.click, "event_company") }); MatchRule rule = new MatchRule() { sex = "1" }; MenuListJson menuJson = new MenuListJson(); menuJson.button.AddRange(new MenuJson[] { conditional }); menuJson.matchrule = rule;
通過上面的代碼了解,我們?nèi)绻枰黾佣鄠€個性化菜單,那么就是通過這個方法,每次創(chuàng)建一個個性化菜單的方式進(jìn)行構(gòu)建,當(dāng)然如果我們使用查詢個性化菜單的結(jié)果可以看到,如果創(chuàng)建多個,那么conditionalmenu集合里面是多個對象的。
調(diào)用代碼每次添加一個個性化菜單的操作如下所示。
string menuid = menuBLL.CreateConditionalMenu(token, menuJson); Console.WriteLine("創(chuàng)建菜單:" + (!string.IsNullOrEmpty(menuid) ? "成功:" + menuid : "失敗"));
我們創(chuàng)建多個規(guī)則后,可以通過TryMatch的方式來檢查匹配的結(jié)果,也就是對應(yīng)不同用戶(openid)會出現(xiàn)不同的個性化菜單列表了。
var myResult = menuBLL.TryMatchConditionalMenu(token, openId); if (myResult != null) { Console.WriteLine(myResult.ToJson()); } var userid_female = "oSiLnt2J4mYkhVG3aLTdMIF1hv-s";//女性的ID myResult = menuBLL.TryMatchConditionalMenu(token, userid_female); if (myResult != null) { Console.WriteLine(myResult.ToJson()); }
?
專注于Winform開發(fā)框架/混合式開發(fā)框架、Web開發(fā)框架、Bootstrap開發(fā)框架、微信門戶開發(fā)框架的研究及應(yīng)用。
??轉(zhuǎn)載請注明出處:
撰寫人:伍華聰? ?
本文摘自 :https://blog.51cto.com/w