1、概述
自定義菜單能夠幫助公眾號豐富界面,讓用戶更好更快地理解公眾號的功能。菜單分為默認菜單與個性化菜單。個性化菜單接口是為了幫助公眾號實現靈活的業務運營,開發者可以通過該接口,讓公眾號的不同用戶群體看到不一樣的自定義菜單。該接口開放給已認證訂閱號和已認證服務號。本文主要介紹微信自定義菜單的創建、查詢、刪除、各菜單類型事件的響應方法,以及菜單應用的界面整合參考。由於篇幅有限不可能面面俱到,只能拋磚迎玉,大家就可以據此擴展做深入的應用。
2、自定義菜單的規則
- 自定義菜單分為一級菜單和二級菜單。
- 一級菜單數量為1-3個,即打開公眾賬號直接可以看到排列在最下方的最多3個按鈕。一級菜單的文字最多不能4個漢字,多出來的部分將會以“...”代替。
- 二級菜單從屬於一級菜單,數量為1-5個。二級菜單的文字不最多不能超過8個漢字,多出來的部分將會以“...”代替。
- 無論一級菜單還是二級菜單,都有兩個觸發事件可以選擇,分別是:點擊(click,值不能超過128字節)和打開網址(view,url不能超過256個字節)。
- 當一個一級菜單下有二級菜單存在的時候,這個一級菜單按鈕被點擊不會有任何事件發生。
- 創建自定義菜單后,菜單的刷新策略是,在用戶進入公眾號會話頁或公眾號profile頁時,如果發現上一次拉取菜單的請求在5分鍾以前,就會拉取一下菜單,如果菜單有更新,就會刷新客戶端的菜單。測試時可以嘗試取消關注公眾賬號后再次關注,則可以看到創建后的效果。
3、自定義菜單接口可實現按鈕類型的種類
自定義菜單接口可實現多種類型按鈕,如下:
1、click:點擊推事件用戶點擊click類型按鈕后,微信服務器會通過消息接口推送消息類型為event的結構給開發者(參考消息接口指南),並且帶上按鈕中開發者填寫的key值,開發者可以通過自定義的key值與用戶進行交互;
2、view:跳轉URL用戶點擊view類型按鈕后,微信客戶端將會打開開發者在按鈕中填寫的網頁URL,可與網頁授權獲取用戶基本信息接口結合,獲得用戶基本信息。
3、scancode_push:掃碼推事件用戶點擊按鈕后,微信客戶端將調起掃一掃工具,完成掃碼操作后顯示掃描結果(如果是URL,將進入URL),且會將掃碼的結果傳給開發者,開發者可以下發消息。
4、scancode_waitmsg:掃碼推事件且彈出“消息接收中”提示框用戶點擊按鈕后,微信客戶端將調起掃一掃工具,完成掃碼操作后,將掃碼的結果傳給開發者,同時收起掃一掃工具,然后彈出“消息接收中”提示框,隨后可能會收到開發者下發的消息。
5、pic_sysphoto:彈出系統拍照發圖用戶點擊按鈕后,微信客戶端將調起系統相機,完成拍照操作后,會將拍攝的相片發送給開發者,並推送事件給開發者,同時收起系統相機,隨后可能會收到開發者下發的消息。
6、pic_photo_or_album:彈出拍照或者相冊發圖用戶點擊按鈕后,微信客戶端將彈出選擇器供用戶選擇“拍照”或者“從手機相冊選擇”。用戶選擇后即走其他兩種流程。
7、pic_weixin:彈出微信相冊發圖器用戶點擊按鈕后,微信客戶端將調起微信相冊,完成選擇操作后,將選擇的相片發送給開發者的服務器,並推送事件給開發者,同時收起相冊,隨后可能會收到開發者下發的消息。
8、location_select:彈出地理位置選擇器用戶點擊按鈕后,微信客戶端將調起地理位置選擇工具,完成選擇操作后,將選擇的地理位置發送給開發者的服務器,同時收起位置選擇工具,隨后可能會收到開發者下發的消息。
9、media_id:下發消息(除文本消息)用戶點擊media_id類型按鈕后,微信服務器會將開發者填寫的永久素材id對應的素材下發給用戶,永久素材類型可以是圖片、音頻、視頻、圖文消息。請注意:永久素材id必須是在“素材管理/新增永久素材”接口上傳后獲得的合法id。
10、view_limited:跳轉圖文消息URL用戶點擊view_limited類型按鈕后,微信客戶端將打開開發者在按鈕中填寫的永久素材id對應的圖文消息URL,永久素材類型只支持圖文消息。請注意:永久素材id必須是在“素材管理/新增永久素材”接口上傳后獲得的合法id。
請注意,3到8的所有事件,僅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用戶,舊版本微信用戶點擊后將沒有回應,開發者也不能正常接收到事件推送。9和10,是專門給第三方平台旗下未微信認證(具體而言,是資質認證未通過)的訂閱號准備的事件類型,它們是沒有事件推送的,能力相對受限,其他類型的公眾號不必使用。
4、創建菜單
4.1、創建菜單的接口
微信提供了接口API可以創建自定義菜單,接口相關說明如下。
http請求方式:POST(請使用https協議)
https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
click和view的請求示例
{
"button":[
{
"type":"click",
"name":"今日歌曲",
"key":"V1001_TODAY_MUSIC"
},
{
"name":"菜單",
"sub_button":[
{
"type":"view",
"name":"搜索",
"url":"http://www.soso.com/"
},
{
"type":"miniprogram",
"name":"wxa",
"url":"http://mp.weixin.qq.com",
"appid":"wx286b93c14bbf93aa",
"pagepath":"pages/lunar/index"
},
{
"type":"click",
"name":"贊一下我們",
"key":"V1001_GOOD"
}]
}]
}
其他新增按鈕類型的請求示例
{
"button": [
{
"name": "掃碼",
"sub_button": [
{
"type": "scancode_waitmsg",
"name": "掃碼帶提示",
"key": "rselfmenu_0_0",
"sub_button": [ ]
},
{
"type": "scancode_push",
"name": "掃碼推事件",
"key": "rselfmenu_0_1",
"sub_button": [ ]
}
]
},
{
"name": "發圖",
"sub_button": [
{
"type": "pic_sysphoto",
"name": "系統拍照發圖",
"key": "rselfmenu_1_0",
"sub_button": [ ]
},
{
"type": "pic_photo_or_album",
"name": "拍照或者相冊發圖",
"key": "rselfmenu_1_1",
"sub_button": [ ]
},
{
"type": "pic_weixin",
"name": "微信相冊發圖",
"key": "rselfmenu_1_2",
"sub_button": [ ]
}
]
},
{
"name": "發送位置",
"type": "location_select",
"key": "rselfmenu_2_0"
},
{
"type": "media_id",
"name": "圖片",
"media_id": "MEDIA_ID1"
},
{
"type": "view_limited",
"name": "圖文消息",
"media_id": "MEDIA_ID2"
}
]
}
參數說明
參數 是否必須 說明
button 是 一級菜單數組,個數應為1~3個
sub_button 否 二級菜單數組,個數應為1~5個
type 是 菜單的響應動作類型,view表示網頁類型,click表示點擊類型,miniprogram表示小程序類型
name 是 菜單標題, 不超過16個字節,子菜單不超過60個字節
key click等點擊類型必須 菜單KEY值,用於消息接口推送,不超過128字節
url view、miniprogram類型必須 網頁 鏈接,用戶點擊菜單可打開鏈接,不超過1024字節。 type為miniprogram時,不支持小程序的老版本客戶端將打開本url。
media_id media_id類型和view_limited類型必須 調用新增永久素材接口返回的合法media_id
appid miniprogram類型必須 小程序的appid(僅認證公眾號可配置)
pagepath miniprogram類型必須 小程序的頁面路徑
4.2、使用Senparc.Weixin.MP SDK創建自定義菜單
使用微信提供的接口創建菜單編碼量還是非常大,在此我們借助Senparc.Weixin.MP SDK來快速的創建自定義菜單。非常簡單,只需三步:
第一步:獲取AccessToken
var accessToken = AccessTokenContainer.TryGetToken(appId, appSecret).access_token;
PS:如果第三步中使用AppId取代AccessToken,則這一步可以省略。
第二步:組織菜單內容
ButtonGroup bg = new ButtonGroup();
//菜單1
var subButton = new SubButton()
{
name = "菜單1"
};
bg.button.Add(subButton);
subButton.sub_button.Add(new SingleClickButton()
{
key = "SubClickRoot_Text",
name = "返回文本"
});
subButton.sub_button.Add(new SingleClickButton()
{
key = "SubClickRoot_News",
name = "返回圖文"
});
subButton.sub_button.Add(new SingleClickButton()
{
key = "SubClickRoot_Music",
name = "返回音樂"
});
subButton.sub_button.Add(new SingleViewButton()
{
url = "http://www.rdiframework.net/",
name = "Url跳轉"
});
//菜單2
var subButton2 = new SubButton()
{
name = "菜單2"
};
bg.button.Add(subButton2);
subButton2.sub_button.Add(new SingleClickButton()
{
key = "SubClickRoot_Text",
name = "返回文本"
});
subButton2.sub_button.Add(new SingleClickButton()
{
key = "SubClickRoot_News",
name = "返回圖文"
});
第三步:提交到微信服務器
var result = CommonApi.CreateMenu(accessToken, bg);
上面SingleClickButton和SingleViewButton分別對應了微信API中的click和view兩種菜單響應方式。
通過執行上述代碼我們可以看到創建的菜單如下所示,可以看到上面我們通過代碼創建的自定義菜單。
4.3、查詢已創建的菜單
使用接口創建自定義菜單后,開發者還可使用接口查詢自定義菜單的結構。另外請注意,在設置了個性化菜單后,使用本自定義菜單查詢接口可以獲取默認菜單和全部個性化菜單信息。
請求說明
http請求方式:GET
https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
需要注意的時返回的Json數據分兩種類型,默認菜單與個性化的菜單。
menu為默認菜單,conditionalmenu為個性化菜單列表。字段說明請見個性化菜單接口頁的說明。
使用Senparc.Weixin.MP SDK查詢已創建的菜單接口只需一行代碼,如下:
var result = CommonApi.GetMenu(accessToken);
4.4、刪除已創建的菜單
使用接口創建自定義菜單后,開發者還可使用接口刪除當前使用的自定義菜單。另請注意,在個性化菜單時,調用此接口會刪除默認菜單及全部個性化菜單。
請求說明
http請求方式:GET
https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
使用Senparc.Weixin.MP SDK刪除已創建的菜單接口只需一行代碼,如下:
var result = CommonApi.DeleteMenu(accessToken);
5、菜單響應事件的處理
無論是click還是view,服務器都會收到不同的事件響應。不同的是,click之后客戶端可以得到返回信息,而view在收到請求后,無論返回什么信息,客戶端都無法收到(直接打開URL了)。用戶點擊自定義菜單后,微信會把點擊事件推送給開發者,請注意,點擊菜單彈出子菜單,不會產生上報。另外第3個到第8個類型的所有事件,僅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用戶,舊版本微信用戶點擊后將沒有回應,開發者也不能正常接收到事件推送。
要對菜單響應事件的處理,我們只需要重寫Senparc.Weixin.MP SDK中的對應事件,具體詳情如下。下面給出了各類型事件處理的參考代碼,具體業務應用可以就此擴展開來做深入的應用即可。
5.1、點擊菜單拉取消息時的事件推送
public override IResponseMessageBase OnTextOrEventRequest(RequestMessageText requestMessage)
{
// 預處理文字或事件類型請求。
// 這個請求是一個比較特殊的請求,通常用於統一處理來自文字或菜單按鈕的同一個執行邏輯,
// 會在執行OnTextRequest或OnEventRequest之前觸發,具有以下一些特征:
// 1、如果返回null,則繼續執行OnTextRequest或OnEventRequest
// 2、如果返回不為null,則終止執行OnTextRequest或OnEventRequest,返回最終ResponseMessage
// 3、如果是事件,則會將RequestMessageEvent自動轉為RequestMessageText類型,其中RequestMessageText.Content就是RequestMessageEvent.EventKey
if (requestMessage.Content == "OneClick")
{
var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
strongResponseMessage.Content = "您點擊了底部按鈕。\r\n為了測試微信軟件換行bug的應對措施,這里做了一個——\r\n換行";
return strongResponseMessage;
}
return null;//返回null,則繼續執行OnTextRequest或OnEventRequest
}
public override IResponseMessageBase OnEvent_ClickRequest(RequestMessageEvent_Click requestMessage)
{
//獲得當前公眾號
WeixinOfficialAccountEntity account = RDIFrameworkService.Instance.WeixinBasicService.GetOfficialAccountEntity(Id);
IResponseMessageBase reponseMessage = null;
//菜單點擊,需要跟創建菜單時的Key匹配
switch (requestMessage.EventKey)
{
case "OneClick":
{
//這個過程實際已經在OnTextOrEventRequest中完成,這里不會執行到。
var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
reponseMessage = strongResponseMessage;
strongResponseMessage.Content = "您點擊了底部按鈕。\r\n為了測試微信軟件換行bug的應對措施,這里做了一個——\r\n換行";
}
break;
case "SubClickRoot_Text":
{
var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
reponseMessage = strongResponseMessage;
strongResponseMessage.Content = "您點擊了子菜單按鈕。";
}
break;
case "SubClickRoot_News":
{
var strongResponseMessage = CreateResponseMessage<ResponseMessageNews>();
reponseMessage = strongResponseMessage;
strongResponseMessage.Articles.Add(new Article()
{
Title = "您點擊了子菜單圖文按鈕",
Description = "您點擊了子菜單圖文按鈕,這是一條圖文信息。",
PicUrl = "http://www.rdiframework.net/img/weixing-ma.png",
Url = "http://www.rdiframework.net/"
});
}
break;
case "SubClickRoot_Music":
{
//上傳縮略圖
var uploadResult = MediaApi.UploadTemporaryMedia(account.AccessToken, UploadMediaFileType.image,Server.GetMapPath("~/Content/Images/weixing-ma.png"));
//設置音樂信息
var strongResponseMessage = CreateResponseMessage<ResponseMessageMusic>();
reponseMessage = strongResponseMessage;
strongResponseMessage.Music.Title = "天籟之音";
strongResponseMessage.Music.Description = "真的是天籟之音";
strongResponseMessage.Music.MusicUrl = "http://www.rdiframework.net/resource/music/music1.mp3";
strongResponseMessage.Music.HQMusicUrl = "http://www.rdiframework.net/resource/music/music1.mp3";
strongResponseMessage.Music.ThumbMediaId = uploadResult.media_id;
}
break;
case "SubClickRoot_Image":
{
//上傳圖片
var uploadResult = MediaApi.UploadTemporaryMedia(account.AccessToken, UploadMediaFileType.image, Server.GetMapPath("~/Content/Images/weixing-ma.png"));
//設置圖片信息
var strongResponseMessage = CreateResponseMessage<ResponseMessageImage>();
reponseMessage = strongResponseMessage;
strongResponseMessage.Image.MediaId = uploadResult.media_id;
}
break;
default:
{
var strongResponseMessage = CreateResponseMessage<ResponseMessageText>();
strongResponseMessage.Content = "您點擊了按鈕,EventKey:" + requestMessage.EventKey;
reponseMessage = strongResponseMessage;
}
break;
}
return reponseMessage;
}
在4.2小節我們創建的菜單中,我們單擊“返回圖文”二級菜單項,由於我們為這個菜單項定義的KEY為“SubClickRoot_News”,如下圖的調試狀態所示。
我們返回到微信查看一下運行效果,可以看到我們自己的服務器根據定義已經正確的返回了圖文信息給我們,其他的菜單事件操作類似。
![返回圖文事件運行效果]](https://img2018.cnblogs.com/blog/157572/201904/157572-20190413130528327-1661526058.png)
又如我們返回一首音樂,還可以直接播放返回的音樂,如下圖所示。
5.2、擊菜單跳轉鏈接時的事件推送
public override IResponseMessageBase OnEvent_ViewRequest(RequestMessageEvent_View requestMessage)
{
//說明:這條消息只作為接收,下面的responseMessage到達不了客戶端,類似OnEvent_UnsubscribeRequest
var responseMessage = CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "您點擊了view按鈕,將打開網頁:" + requestMessage.EventKey;
return responseMessage;
}
5.3、掃碼推事件的事件推送
/// <summary>
/// 事件之掃碼推事件(scancode_push)
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnEvent_ScancodePushRequest(RequestMessageEvent_Scancode_Push requestMessage)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "事件之掃碼推事件";
return responseMessage;
}
5.4、掃碼推事件且彈出“消息接收中”提示框的事件推送
/// <summary>
/// 事件之掃碼推事件且彈出“消息接收中”提示框(scancode_waitmsg)
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnEvent_ScancodeWaitmsgRequest(RequestMessageEvent_Scancode_Waitmsg requestMessage)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "事件之掃碼推事件且彈出“消息接收中”提示框";
return responseMessage;
}
5.5、彈出系統拍照發圖的事件推送
/// <summary>
/// 事件之彈出系統拍照發圖(pic_sysphoto)
/// 實際測試時發現微信並沒有推送RequestMessageEvent_Pic_Sysphoto消息,只能接收到用戶在微信中發送的圖片消息。
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnEvent_PicSysphotoRequest(RequestMessageEvent_Pic_Sysphoto requestMessage)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "事件之彈出系統拍照發圖";
return responseMessage;
}
5.6、彈出拍照或者相冊發圖的事件推送
/// <summary>
/// 事件之彈出拍照或者相冊發圖(pic_photo_or_album)
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnEvent_PicPhotoOrAlbumRequest(RequestMessageEvent_Pic_Photo_Or_Album requestMessage)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "事件之彈出拍照或者相冊發圖";
return responseMessage;
}
5.7、彈出微信相冊發圖器的事件推送
/// <summary>
/// 事件之彈出微信相冊發圖器(pic_weixin)
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnEvent_PicWeixinRequest(RequestMessageEvent_Pic_Weixin requestMessage)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "事件之彈出微信相冊發圖器";
return responseMessage;
}
5.8、彈出地理位置選擇器的事件推送
/// <summary>
/// 事件之彈出地理位置選擇器(location_select)
/// </summary>
/// <param name="requestMessage"></param>
/// <returns></returns>
public override IResponseMessageBase OnEvent_LocationSelectRequest(RequestMessageEvent_Location_Select requestMessage)
{
var responseMessage = base.CreateResponseMessage<ResponseMessageText>();
responseMessage.Content = "事件之彈出地理位置選擇器";
return responseMessage;
}
6、對菜單應用的整合界面參考
實際應用中菜單隨時都可能在變化,我們的最終使用者是不可能用編碼的方式去對菜單進行處理的。這時就需要一個集中的界面可對菜單的集中配置。我們開發了菜單的應用參考界面,如下圖所示。
在上圖中,我們通過“獲取菜單”按鈕可以得到當前已經定義好的菜單及菜單的事件響應的處理,我們對微信常規菜單以及個性化菜單的定義都進行了處理。各菜單的定義完全按照微信的要求標准進行了處理。對於界面右側的“按鈕其他參數”的的設置,針對不同的類型分別進行了處理。對於菜單的修改,直接單擊“更新到服務器”即可完成同步,非常的方便。
參考文章
RDIFramework.NET — 基於.NET的快速信息化系統開發框架 — 系列目錄
RDIFramework.NET ━ .NET快速信息化系統開發框架 ━ 工作流程組件介紹
RDIFramework.NET框架SOA解決方案(集Windows服務、WinForm形式與IIS形式發布)-分布式應用
RDIFramework.NET代碼生成器全新V3.5版本發布-重大升級
一路走來數個年頭,感謝RDIFramework.NET框架的支持者與使用者,大家可以通過下面的地址了解詳情。
RDIFramework.NET官方網站:http://www.rdiframework.net/
RDIFramework.NET官方博客:http://blog.rdiframework.net/
同時需要說明的,以后的所有技術文章以官方網站為准,歡迎大家收藏!
RDIFramework.NET框架由專業團隊長期打造、一直在更新、一直在升級,請放心使用!
歡迎關注RDIFramework.net框架官方公眾微信(微信號:guosisoft),及時了解最新動態。
掃描二維碼立即關注