一、简介 微信公众平台服务号以及之前成功申请内测资格的订阅号都具有自定义菜单的功能。开发者可利用该功能为公众账号的会话界面底部增加自定义菜单,用户点击菜单中的选项,可以调出相应的回复信息或网页链接。自定义菜单接口将为公众账号的信息展示空间提供更多可能性。本文将针对自定义菜单做简单的开发应用,以供读者参考。 二、官方说明 开发者获取使用凭证后,可以使用该凭证对公众账号的自定义菜单进行创建、查询和删除等操作。 自定义菜单接口可实现以下类型按钮: click(点击事件): 用户点击click类型按钮后,微信服务器会通过消息接口(event类型)推送点击事件给开发者,并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值进行消息回复。 view(访问网页): 用户点击view类型按钮后,会直接跳转到开发者指定的url中。 创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来。建议测试时可以尝试取消关注公众账号后,再次关注,则可以看到创建后的效果。 文档地址:http://mp.weixin.qq.com/wiki 三、获取使用凭证 3.1 获取appid 和appsecret 在 微信公众平台 > 高级功能 > 开发模式中找到appid 和appsecret。 3.2 使用appid 和appsecret 向微信凭证获取接口请求access_token 请求地址:https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET 请求参数说明: grant_type:获取access_token填写client_credential appid:第三方用户唯一凭证 secret:第三方用户唯一凭证密钥,既appsecret 返回说明: 正确的Json返回结果: {"access_token":"ACCESS_TOKEN","expires_in":7200} 返回参数说明: access_token:获取到的凭证 expires_in:凭证有效时间,单位:秒
3.3具体实现
//与微信平台那边填写的token一致
string Token = "tokenAccountName";
// 获取access_token的接口地址GET方式 public static string access_token_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET"; public static string createurl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN";
public static void CreateMenue(string appid, string appsecret)
{
//获取access_token值
string requestUrl = access_token_url.Replace("APPID", appid).Replace("APPSECRET", appsecret);
WebResponse result = null;
WebRequest req = WebRequest.Create(requestUrl);
result = req.GetResponse();
Stream s = result.GetResponseStream();
XmlDictionaryReader xmlReader = JsonReaderWriterFactory.CreateJsonReader(s, XmlDictionaryReaderQuotas.Max);
xmlReader.Read();
String XMLString = xmlReader.ReadOuterXml();
s.Close();
s.Dispose();
XmlDocument doc = new XmlDocument();
doc.LoadXml(XMLString);
XmlElement rootElement = doc.DocumentElement;
string access_token = rootElement.SelectSingleNode("access_token").InnerText;
//根据access_token值
createurl = createurl.Replace("ACCESS_TOKEN", access_token);
string responeJsonStr = "{" +
"\"button\":[" +
"{\"name\":\"中秋系列\"," +
"\"type\":\"click\"," +
"\"key\":\"V1001_ZhongQiu\"" +
"}" +
",{\"name\":\"摘星星\"," +
"\"type\":\"click\"," +
"\"key\":\"V1002_ZhaiXing\"" +
"}" +
"]" +
"}";
WebRequest req = WebRequest.Create(createurl);
byte[] bytes = Encoding.UTF8.GetBytes(responeJsonStr.ToString());
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bytes.Length;
Stream reqStr = req.GetRequestStream();
reqStr.Write(bytes, 0, bytes.Length);
reqSrt.Close();
}
protected void Page_Load(object sender, EventArgs e)
{
CreateMenue("wxddsd8521111fdfs", "r85f5gf222222222sdsdd2dsdsdsddddd");
string postStr = "";
if (Request.HttpMethod.ToLower() == "POST")
{
Stream s = System.Web.HttpContext.Current.Request.InputStream;
byte[] b = new byte[s.Length];
s.Read(b, 0, (int)s.Length);
postStr = Encoding.UTF8.GetString(b);
if (!string.IsNullOrEmpty(postStr))
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(postStr);
XmlElement rootElement = doc.DocumentElement;
XmlNode MsgType = rootElement.SelectSingleNode("MsgType");
WeiXinRequest requestXML = new WeiXinRequest();
requestXML.ToUserName = rootElement.SelectSingleNode("ToUserName").InnerText;
requestXML.FromUserName = rootElement.SelectSingleNode("FromUserName").InnerText;
requestXML.CreateTime = rootElement.SelectSingleNode("CreateTime").InnerText;
requestXML.MsgType = MsgType.InnerText;
if (requestXML.MsgType == "text")
{
requestXML.Content = rootElement.SelectSingleNode("Content").InnerText;
requestXML.MsgId = rootElement.SelectSingleNode("MsgId").InnerText;
}
else if (requestXML.MsgType == "location")
{
requestXML.Location_X = rootElement.SelectSingleNode("Location_X").InnerText;
requestXML.Location_Y = rootElement.SelectSingleNode("Location_Y").InnerText;
}
else if (requestXML.MsgType == "event")
{
requestXML.Wxevent = rootElement.SelectSingleNode("Event").InnerText;
requestXML.EventKey = rootElement.SelectSingleNode("EventKey").InnerText;
}
WriteTxt("---消息,消息类型:" + requestXML.MsgType + "----:" + postStr);
//回复消息
ResponseMsg(requestXML);
}
}
else
{
CheckSource();
}
}
private void CheckSource()
{
string echoStr = Request.QueryString["echoStr"];
if (CheckSignature())
{
if (!string.IsNullOrEmpty(echoStr))
{
Response.Write(echoStr);
Response.End();
}
}
}
private bool CheckSignature()
{
string signature = Request.QueryString["signature"];
string timestamp = Request.QueryString["timestamp"];
string nonce = Request.QueryString["nonce"];
string[] ArrTmp = { Token, timestamp, nonce };
Array.Sort(ArrTmp);
string tmpStr = string.Join("", ArrTmp);
tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
tmpStr = tmpStr.ToLower();
if (tmpStr == signature)
{
return true;
}
else
{
return false;
}
}
private int ConvertDate(System.DateTime time)
{
System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
return (int)(time - startTime).TotalSeconds;
}
private void ResponseMsg(WeiXinRequest requestXML)
{
string resxml = "<xml><ToUserName><![CDATA[" + requestXML.FromUserName + "]]></ToUserName><FromUserName><![CDATA[" + requestXML.ToUserName + "]]></FromUserName><CreateTime>" + ConvertDate(DateTime.Now) + "</CreateTime>";
try
{
if (requestXML.MsgType == "text")
{
int count = 0;
resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[好看信息]]></Content><FuncFlag>0</FuncFlag></xml>"; //}
}
else if (requestXML.MsgType == "location")
{
resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[坐标消息]]></Content><FuncFlag>0</FuncFlag></xml>";
}
else if (requestXML.MsgType == "event")
{
if (requestXML.Wxevent == "unsubscribe")
{
//取消关注
}
else if (requestXML.Wxevent == "subscribe")
{
//新增关注
resxml += "<MsgType><![CDATA[text]]></MsgType><Content><![CDATA[感谢关注!]]></Content><FuncFlag>0</FuncFlag></xml>";
}
else if (requestXML.Wxevent.ToUpper() == "CLICK")
{
if (requestXML.EventKey == "V1001_ZhongQiu") { string P_Code = ""; }
else if (requestXML.EventKey == "V1002_ZhaiXing") { resxml += "<MsgType><![CDATA[news]]></MsgType><ArticleCount>" + 1 + "</ArticleCount><Articles>";
resxml += "<item><Title><![CDATA[摘颗星星给你]]></Title><Description><![CDATA[查看您的中秋惊喜]]></Description><Url><![CDATA[" + Request.Url.Authority + "/WeiXin/PurchaseLogin.aspx?weixinId=" + requestXML.FromUserName + "&gzhID=" + requestXML.ToUserName + "]]></Url></item>"; resxml += "</Articles><FuncFlag>0</FuncFlag></xml>"; } } } }
catch (Exception ex) { WriteTxt("异常:" + ex.Message); }
WriteTxt("返回给对方的消息:" + resxml);
Response.Write(resxml); Response.End(); }
public bool WriteTxt(string str)
{
try
{
FileStream fs = new FileStream(Server.MapPath("/Log.txt"), FileMode.Append);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine(str);
sw.Flush();
sw.Close();
fs.Close();
}
catch (Exception)
{
return false;
}
return true;
}
}
}
public class WeiXinRequest
{
private string toUserName;
/// <summary>
/// 消息接收方微信号
/// </summary>
public string ToUserName
{
get { return toUserName; }
set { toUserName = value; }
}
private string fromUserName;
/// <summary>
/// 消息发送方微信号
/// </summary>
public string FromUserName
{
get { return fromUserName; }
set { fromUserName = value; }
}
private string createTime;
/// <summary>
/// 创建时间
/// </summary>
public string CreateTime
{
get { return createTime; }
set { createTime = value; }
}
private string msgType;
/// <summary>
/// 信息类型 文本消息:text,消息类型:image,音频:voice,视频:video,
/// </summary>
public string MsgType
{
get { return msgType; }
set { msgType = value; }
}
private string content;
/// <summary>
/// 信息内容
/// </summary>
public string Content
{
get { return content; }
set { content = value; }
}
private string msgId;
/// <summary>
/// 消息ID(文本)
/// </summary>
public string MsgId
{
get { return msgId; }
set { msgId = value; }
}
private string wxevent;
/// <summary>
/// 取消关注时的Event节点
/// </summary>
public string Wxevent
{
get { return wxevent; }
set { wxevent = value; }
}
private string eventKey;
/// <summary>
/// 取消关注时的EventKey节点
/// </summary>
public string EventKey
{
get { return eventKey; }
set { eventKey = value; }
}
private string location_X;
/// <summary>
/// 坐标维度
/// </summary>
public string Location_X
{
get { return location_X; }
set { location_X = value; }
}
private string location_Y;
/// <summary>
/// 经度
/// </summary>
public string Location_Y
{
get { return location_Y; }
set { location_Y = value; }
}
private string picUrl;
/// <summary>
/// 图片链接
/// </summary>
public string PicUrl
{
get { return picUrl; }
set { picUrl = value; }
}
}