一、创建接口
1.1、注意事项
- 自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单。
- 一级菜单最多4个汉字,二级菜单最多8个汉字,多出来的部分将会以“...”代替。
- 创建自定义菜单后,菜单的刷新策略是,在用户进入公众号会话页或公众号 profile 页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果。
1.2、按钮类型
- click:点击推事件用户点击 click 类型按钮后,微信服务器会通过消息接口推送消息类型为 event 的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的 key 值,开发者可以通过自定义的 key 值与用户进行交互;
- view:跳转 URL 用户点击 view 类型按钮后,微信客户端将会打开开发者在按钮中填写的网页URL,可与网页授权获取用户基本信息接口结合,获得用户基本信息。
- scancode_push:扫码推事件用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后显示扫描结果(如果是URL,将进入URL),且会将扫码的结果传给开发者,开发者可以下发消息。
- scancode_waitmsg:扫码推事件且弹出“消息接收中”提示框用户点击按钮后,微信客户端将调起扫一扫工具,完成扫码操作后,将扫码的结果传给开发者,同时收起扫一扫工具,然后弹出“消息接收中”提示框,随后可能会收到开发者下发的消息。
- pic_sysphoto:弹出系统拍照发图用户点击按钮后,微信客户端将调起系统相机,完成拍照操作后,会将拍摄的相片发送给开发者,并推送事件给开发者,同时收起系统相机,随后可能会收到开发者下发的消息。
- pic_photo_or_album:弹出拍照或者相册发图用户点击按钮后,微信客户端将弹出选择器供用户选择“拍照”或者“从手机相册选择”。用户选择后即走其他两种流程。
- pic_weixin:弹出微信相册发图器用户点击按钮后,微信客户端将调起微信相册,完成选择操作后,将选择的相片发送给开发者的服务器,并推送事件给开发者,同时收起相册,随后可能会收到开发者下发的消息。
- location_select:弹出地理位置选择器用户点击按钮后,微信客户端将调起地理位置选择工具,完成选择操作后,将选择的地理位置发送给开发者的服务器,同时收起位置选择工具,随后可能会收到开发者下发的消息。
- media_id:下发消息(除文本消息)用户点击media_id类型按钮后,微信服务器会将开发者填写的永久素材 id 对应的素材下发给用户,永久素材类型可以是图片、音频、视频
、图文消息。请注意:永久素材 id 必须是在“素材管理/新增永久素材”接口上传后获得的合法id。 view_limited:跳转图文消息 URL 用户点击view_limited类型按钮后,微信客户端将打开开发者在按钮中填写的永久素材 id 对应的图文消息URL,永久素材类型只支持图文消息。请注意:永久素材 id 必须是在“素材管理/新增永久素材”接口上传后获得的合法id。- article_id:用户点击 article_id 类型按钮后,微信客户端将会以卡片形式,下发开发者在按钮中填写的图文消息
- article_view_limited:类似 view_limited,但不使用 media_id 而使用 article_id
注意: 草稿接口灰度完成后,将不再支持图文信息类型的 media_id 和 view_limited,有需要的,请使用 article_id 和 article_view_limited 代替
请注意,3到8的所有事件,仅支持微信iPhone5.4.1以上版本,和Android5.4以上版本的微信用户,旧版本微信用户点击后将没有回应,开发者也不能正常接收到事件推送。9~12,是专门给第三方平台旗下未微信认证(具体而言,是资质认证未通过)的订阅号准备的事件类型,它们是没有事件推送的,能力相对受限,其他类型的公众号不必使用。
1.3、使用测试账号
默认账号没有认证是不能新建自定义菜单的
可以使用平台测试账号调试接口
1.4、WebApi
Services文件夹下新建文件夹Menu和菜单服务MenuService.cs
新建创建菜单接口
namespace WeiXinApi.Application.Services
{
public class MenuService : BaseService
{
/// <summary>
/// 创建菜单
/// </summary>
/// <param name="resultFull"></param>
/// <returns></returns>
[HttpPost("/menu/add")]
public dynamic CrateMenu(GetMenuResultFull resultFull)
{
try
{
var buttonGroup = CommonApi.GetMenuFromJsonResult(resultFull, new ButtonGroup()).menu;
var result = CommonApi.CreateMenu(AppId, buttonGroup);
if (result.errmsg == "ok")
{
return "菜单更新成功";
}
else
{
return result;
}
}
catch (Exception ex)
{
throw Oops.Oh($"更新失败:{ex.Message}");
}
}
}
}
使用apipost测试接口
测试数据
{
"menu": {
"button": [
{
"type": "click",
"name": "今日歌曲",
"key": "V1001_TODAY_MUSIC"
},
{
"name": "菜单",
"sub_button": [
{
"type": "view",
"name": "搜索",
"url": "http://www.baidu.com/"
},
{
"type": "click",
"name": "赞一下我们",
"key": "V1001_GOOD"
}
]
},
{
"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": []
}
]
}
]
}
}
二、查询接口
2.1、说明
本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过 API 调用设置的菜单,则返回菜单的开发配置,而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
请注意:
- 第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自定义菜单配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。
- 本接口与自定义菜单查询接口的不同之处在于,本接口无论公众号的接口是如何设置的,都能查询到接口,而自定义菜单查询接口则仅能查询到使用 API 设置的菜单配置。
- 认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。
- 从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。
- 本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理 - 获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理 - 获取永久素材接口来获取这些素材)。
2.2、WebApi
新建接口
/// <summary>
/// 获取菜单
/// </summary>
/// <returns></returns>
[HttpGet("/menu/list")]
public dynamic GetMenu()
{
try
{
var result = CommonApi.GetMenu(AppId);
if (result == null)
{
throw Oops.Oh($"菜单不存在或验证失败");
}
else
{
//正常序列化只返回菜单Name,因为GetMenuResult里面button只有name字段,所以这里需要转换一下
var menu = JsonConvert.DeserializeObject<GetMenuResultFull>(result.ToJson());
return menu;
}
}
catch (Exception ex)
{
throw Oops.Oh($"菜单不存在或验证失败:{ex.Message}");
}
}
测试接口
三、删除接口
3.1、说明
使用接口创建自定义菜单后,开发者还可使用接口删除当前使用的自定义菜单。另请注意,在个性化菜单时,调用此接口会删除默认菜单及全部个性化菜单。
3.2、WebApi
/// <summary>
/// 删除菜单
/// </summary>
/// <returns></returns>
[HttpGet("/menu/delete")]
public dynamic Delete()
{
try
{
var result = CommonApi.DeleteMenu(AppId);
if (result.errmsg == "ok")
{
return "删除菜单成功";
}
else
{
return result.errmsg;
}
}
catch (Exception ex)
{
throw Oops.Oh($"删除菜单失败:{ex.Message}");
}
}
请求测试
可以看到公众号也就没有菜单了
四、事件推送
详情请看事件推送章节
五、个性化菜单
5.1、说明
为了帮助公众号实现灵活的业务运营,微信公众平台新增了个性化菜单接口,开发者可以通过该接口,让公众号的不同用户群体看到不一样的自定义菜单。该接口开放给已认证订阅号和已认证服务号。
开发者可以通过以下条件来设置用户看到的菜单:
- 用户标签(开发者的业务需求可以借助用户标签来完成)
性别- 手机操作系统
地区(用户在微信客户端设置的地区)语言(用户在微信客户端设置的语言)
注意:为保护个人隐私,公众号个性化菜单将不再支持对性别、地区、语言这类涉及个人隐私数据的信息进行筛选的功能,具体调整如下:
- 创建时,只要匹配条件中包含隐私信息的,将被拒绝,并返回错误码 65320;
- 已经创建的,如包含隐私信息的则自动失效,不包含的则正常匹配;
- 开发者仍然可以正常通过测试接口,获取到粉丝看到的菜单;
- 查询个性化菜单时,所有规则正常显示。
个性化菜单接口说明:
- 个性化菜单要求用户的微信客户端版本在iPhone6.2.2,Android 6.2.4以上,暂时不支持其他版本微信
- 菜单的刷新策略是,在用户进入公众号会话页或公众号 profile 页时,如果发现上一次拉取菜单的请求在5分钟以前,就会拉取一下菜单,如果菜单有更新,就会刷新客户端的菜单。测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果
- 普通公众号的个性化菜单的新增接口每日限制次数为2000次,删除接口也是2000次,测试个性化菜单匹配结果接口为20000次
- 出于安全考虑,一个公众号的所有个性化菜单,最多只能设置为跳转到3个域名下的链接
- 创建个性化菜单之前必须先创建默认菜单(默认菜单是指使用普通自定义菜单创建接口创建的菜单)。如果删除默认菜单,个性化菜单也会全部删除
- 个性化菜单接口支持用户标签,请开发者注意,当用户身上的标签超过1个时,以最后打上的标签为匹配
个性化菜单匹配规则说明:
个性化菜单的更新是会被覆盖的。 例如公众号先后发布了默认菜单,个性化菜单1,个性化菜单2,个性化菜单3。那么当用户进入公众号页面时,将从个性化菜单3开始匹配,如果个性化菜单3匹配成功,则直接返回个性化菜单3,否则继续尝试匹配个性化菜单2,直到成功匹配到一个菜单。 根据上述匹配规则,为了避免菜单生效时间的混淆,决定不予提供个性化菜单编辑API,开发者需要更新菜单时,需将完整配置重新发布一轮。
5.2、创建个性化菜单
新增AddPersonalInput.cs类,用来接收前端传过来的值
实体类内容
namespace WeiXinApi.Application.Services
{
public class AddPersonalInput
{
/// <summary>
/// 菜单
/// </summary>
public GetMenuResultFull ResultFull { get; set; }
/// <summary>
/// 规则
/// </summary>
public MenuMatchRule MenuMatchRule { get; set; }
}
}
MenuService.cs新增接口
/// <summary>
/// 创建个性化菜单
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/menu/addpersonal")]
public dynamic CratePersonalMenu(AddPersonalInput input)
{
try
{
WxJsonResult result = null;
var buttonGroup = CommonApi.GetMenuFromJsonResult(input.ResultFull, new ConditionalButtonGroup()).menu;
var addConditionalButtonGroup = buttonGroup as ConditionalButtonGroup;
addConditionalButtonGroup.matchrule = input.MenuMatchRule;
result = CommonApi.CreateMenuConditional(AppId, addConditionalButtonGroup);
var message = $"menuid:{(result as CreateMenuConditionalResult).menuid}";
if (result.errcode == 0)
{
return "菜单更新成功:" + message;
}
else
{
return result;
}
}
catch (Exception ex)
{
throw Oops.Oh($"更新失败:{ex.Message}");
}
}
启动项目测试接口,成功添加
手机上测试看看效果
电脑上的微信还是原来的菜单
5.3、测试个性化菜单匹配结果
MenuService新建接口
/// <summary>
/// 测试个性化菜单匹配结果
/// </summary>
/// <param name="user_id"></param>
/// <returns></returns>
[HttpPost("/menu/test")]
public dynamic PersonalMenuTest(string user_id)
{
var result = CommonApi.TryMatch(AppId, user_id);
return result;
}
测试一下,这里没有返回菜单,可能是因为传的userid,我没有根据用户的个性化设置,所以返回的是空的,不过这功能无关紧要,没必要纠结。
六、本章Gitee地址链接
weixinapi: .Net6+Fruion+Sqlsugar+SenparcSdk开发微信公众号Demo - Gitee.com