自定义菜单创建接口

添加自定义菜单,就是在公众号的底部添加菜单

  • 自定义菜单最多包含3个一级菜单
  • 每个一级菜单最多包含5个二级菜单
  • 一级菜单最多4个汉字,二级菜单则最多7个汉字,多出来的会用...代替
  • 创建自定义菜单后,如果上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。

自定义菜单类型如下:

  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,是专门给第三方平台旗下未微信认证(具体而言,是资质认证未通过)的订阅号准备的事件类型,它们是没有事件推送的,能力相对受限,其他类型的公众号不必使用
  • 本次案例添加View和Click类型按钮
  • POST请求地址:[https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN](https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN)注意是https协议

菜单推送实现

因为需要POST数据到微信接口,所以我们需要序列化json文本提交给微信接口 我们可以在序列化菜单对象成json的时候,使用匿名对象

菜单JSON示例:

{
    "button": [
        {
            "type": "click",
            "name": "今日歌曲",
            "key": "V1001_TODAY_MUSIC"
        },
        {
            "name": "菜单",
            "sub_button": [
                {
                    "type": "view",
                    "name": "搜索",
                    "url": "[http://www.soso.com/](http://www.soso.com/)"
                },
                {
                    "type": "view",
                    "name": "视频",
                    "url": "[http://v.qq.com/](http://v.qq.com/)"
                },
                {
                    "type": "click",
                    "name": "赞一下我们",
                    "key": "V1001_GOOD"
                }
            ]
        }
    ]
}
Code language: JSON / JSON with Comments (json)

序列化菜单方法和使用

protected void Button3_Click(object sender, EventArgs e)
{
    Infos.Menu m = new Infos.Menu();
    //添加第一个菜单
    m.button.Add(new { type = "click",name = "今日歌曲",key = "V1001_TODAY_MUSIC" });
    //添加第二个菜单-包含子菜单
    ArrayList sub = new ArrayList();
    sub.Add( new { name = "搜索", type = "view", url = "[http://www.soso.com/](http://www.soso.com/)" });
    sub.Add(new { name = "视频", type = "view", url = "[http://v.qq.com/](http://v.qq.com/)" });
    sub.Add(new { name = "赞一下我们", type = "click", key = "V1001_GOOD" });
    m.button.Add(new { name = "菜单",sub_button = sub });
    //序列化成json文本
    string json = Tool.SerializeJson(m);
}
Code language: JavaScript (javascript)

Tool工具类新增序列化方法:

/// <summary>
/// 反序列化JSON成对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="jsonText"></param>
/// <returns></returns>
public static T DeserializeJson<T>(string jsonText)
{
    return JavaScriptConvert.DeserializeObject<T>(jsonText);
}

/// <summary>
/// 序列化对象成JSON
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string SerializeJson(object obj)
{
    return JavaScriptConvert.SerializeObject(obj);
}
Code language: HTML, XML (xml)

提交POST注意的问题

  • 提交的参数是Body参数
  • 错误写法:body=json
  • 报错:{"errcode":40016,"errmsg":"invalid but"}
  • 正确:不要带body参数,直接把整个json内容作为请求体提交,微信服务器会把整个body内容当作菜单json

POSTJson工具方法(修正ContentType)

public static string PostJson(string json, string url)
{
    string textResponse = string.Empty;
    Stream outstream = null;
    Stream instream = null;
    StreamReader sr = null;
    HttpWebResponse response = null;
    HttpWebRequest request = null;
    Encoding encoding = Encoding.UTF8;
    byte[] data = encoding.GetBytes(json);
    try
    {
        request = WebRequest.Create(url) as HttpWebRequest;
        CookieContainer cookieContainer = new CookieContainer();
        request.CookieContainer = cookieContainer;
        request.AllowAutoRedirect = true;
        request.Method = "POST";
        // 重点:提交JSON必须改为application/json,而不是form表单类型
        request.ContentType = "application/json";
        request.ContentLength = data.Length;
        outstream = request.GetRequestStream();
        outstream.Write(data, 0, data.Length);
        outstream.Close();
        //发送请求并获取相应回应数据
        response = request.GetResponse() as HttpWebResponse;
        instream = response.GetResponseStream();
        sr = new StreamReader(instream, encoding);
        //返回结果网页(html)代码
        textResponse = sr.ReadToEnd();
    }
    catch(Exception ex)
    {
        textResponse = ex.Message;
    }
    // 释放资源代码省略
    return textResponse;
}
Code language: PHP (php)

发送成功后,微信刷新菜单规则

  • 成功返回:{"errcode":0,"errmsg":"ok"}
  • 如果距离上次菜单刷新小于5分钟,则需要等5分钟客户端菜单才会刷新
  • 调试可用微信测试接口: [https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index&type=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95&form=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3/menu/create](https://mp.weixin.qq.com/debug/cgi-bin/apiinfo?t=index&type=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95&form=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3/menu/create)

反序列化返回的json结果

新建实体类接收返回结果

public class MenuCreateResultInfo
{
    public string errcode { set; get; }
    public string errmsg { set; get; }
}
Code language: JavaScript (javascript)
//反序列化返回的结果
MenuCreateResultInfo menuResObj = Tool.DeserializeJson<MenuCreateResultInfo>(textResponse);
Code language: HTML, XML (xml)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注