C#微信公众号开发 -- (五)自定义菜单创建
公众号中,底部都是有自己定义的功能按钮,通过点击某个按钮来实现指定的业务逻辑操作。
下面就来说说这些按钮是怎样放到微信公众平台的,还是先来看看微信的官方解释:
请注意:
1、自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
2、一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以“...”代替。
3、创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号profile页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,
如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。
自定义菜单接口可实现多种类型按钮,如下:(由于click和view是最常见的事件,所以先讲这两个)
1、click:点击推事件 用户点击click类型按钮后,微信服务器会通过消息接口推送消息类型为event的结构给开发者(参考消息接口指南),
并且带上按钮中开发者填写的key值, 开发者可以通过自定义的key值与用户进行交互;
2、view:跳转URL 用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的网页URL,可与网页授权获取用户基本信息接口结合,获得用户基本信息。
创建自定义菜单其实也是通过http请求方式,实现自定义菜单的写入,请求地址: https://api.weixin.qq.com/cgi-bin/menu/create?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" }] }] }
观察上面的实例可以看出,其实就是一串JSON数据,你可以选择用字符串拼接的形式将其存储,也可以选择文件存储。
这里我使用的文件储存,将上面的实例存储到一个叫menu.txt文件中(这里建立的好处是可以把自定义菜单与微信公众号开发的程序文件分开,避免每次改自定义菜单也都要发布程序,除非有业务逻辑的更改)。建立一个专门创建自定义菜单的页面wxMenuManage.aspx,其实自定义菜单通过本地执行页面就可以将自定义菜单同步到微信服务器上面,具体请看下面的代码:
public partial class wxMenuManage : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } /// <summary> /// 读取并创建自定义菜单 /// </summary> private void CreateMenu() { FileStream fs = new FileStream(HttpContext.Current.Server.MapPath(".") + "\\menu.txt", FileMode.Open); StreamReader sr = new StreamReader(fs, Encoding.GetEncoding("GBK")); string menu = sr.ReadToEnd(); sr.Close(); fs.Close(); sr.Dispose(); fs.Dispose(); string access_token =wxAccess_token.IsExistAccess_Token(); //获取access_token string i = GetPage("https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + access_token, menu); Response.Write("创建菜单结果:" + i); Response.End(); } /// <summary> /// 删除菜单 /// </summary> private void DeleteMenu() { string access_token =wxAccess_token.IsExistAccess_Token(); //获取access_token string i = GetPage("https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=" + access_token, ""); Response.Write("删除菜单结果:" + i); Response.End(); } /// <summary> /// 获取自定义菜单 /// </summary> /// <param name="posturl">自定义菜单请求的地址</param> /// <param name="postData">自定义菜单内容</param> /// <returns></returns> private string GetPage(string posturl, string postData) { Stream outstream = null; Stream instream = null; StreamReader sr = null; HttpWebResponse response = null; HttpWebRequest request = null; Encoding encoding = Encoding.UTF8; byte[] data = null; if (postData.Length > 0) //有值代表创建菜单 { data = encoding.GetBytes(postData); } // 准备请求... try { // 设置参数 request = WebRequest.Create(posturl) as HttpWebRequest; CookieContainer cookieContainer = new CookieContainer(); request.CookieContainer = cookieContainer; request.AllowAutoRedirect = true; if (postData.Length > 0) { request.Method = "POST"; //创建菜单 } else { request.Method = "GET"; //删除菜单 } request.ContentType = "application/x-www-form-urlencoded"; if (postData.Length > 0) //有值代表创建菜单 { request.ContentLength = data.Length; outstream = request.GetRequestStream(); outstream.Write(data, 0, data.Length); outstream.Close(); } //发送请求并获取相应回应数据 response = request.GetResponse() as HttpWebResponse; //直到request.GetResponse()程序才开始向目标网页发送Post请求 instream = response.GetResponseStream(); sr = new StreamReader(instream, encoding); //返回结果网页(html)代码 string content = sr.ReadToEnd(); string err = string.Empty; return content; } catch (Exception ex) { string err = ex.Message; Response.Write(err); Response.End(); return string.Empty; } } /// <summary> /// 创建菜单 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void btnCreate_Click(object sender, EventArgs e) { CreateMenu(); } /// <summary> /// 删除菜单 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void btnDelete_Click(object sender, EventArgs e) { DeleteMenu(); } }
再来看一下我的前台页面:
<form id="form1" runat="server"> <div> <table style="width: 100%;text-align: center;margin-top: 30px;"> <tr> <td style="text-align: right;margin-right: 10px;"> <asp:Button runat="server" ID="btnCreate" Text="创建菜单" OnClick="btnCreate_Click"/> </td> <td style="text-align: left;margin-left: 10px;"> <asp:Button runat="server" ID="btnDelete" Text="删除菜单" OnClick="btnDelete_Click"/> </td> </tr> <tr> <td colspan="2"> <h3 style="color: red;">*注:创建之前请先删除菜单<br/>(创建完成之后新菜单将在五分钟之内生效)</h3> </td> </tr> </table> </div> </form>
这里需要注意的几点:
1、页面中我我用到了一个“创建菜单”的按钮和一个“删除菜单”的按钮,因为在创建菜单之前必须要删除之前的菜单,否则创建可能会失败(第一次的时候可以直接创建)
2、“wxAccess_token.IsExistAccess_Token(); //获取access_token”方法是我将前文提到的IsExistAccess_Token()方法和GetAccess_token()都封装到了一个wxAccess_token类中
3、创建菜单的时候请求的是https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + access_token使用POST请求,删除菜单的时候请求的是https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=" + access_token使用GET请求
4、这里我是将menu.txt和wxMenuManage.aspx放到了同一目录下,你在使用的时候注意他们的路径
这些工作完成之后,就可以在本地运行wxMenuManage.aspx页面了,
点击删除菜单按钮如果页面输出的结果是,“删除菜单结果:{"errcode":0,"errmsg":"ok"}”,说明删除成功
点击创建菜单按钮如果页面输出的结果是,“创建菜单结果:{"errcode":0,"errmsg":"ok"}",说明创建成功
然后把你的微信公众号取消关注,再关注就可以看到你自己的菜单了