一、簡介 微信公眾平台服務號以及之前成功申請內測資格的訂閱號都具有自定義菜單的功能。開發者可利用該功能為公眾賬號的會話界面底部增加自定義菜單,用戶點擊菜單中的選項,可以調出相應的回復信息或網頁鏈接。自定義菜單接口將為公眾賬號的信息展示空間提供更多可能性。本文將針對自定義菜單做簡單的開發應用,以供讀者參考。 二、官方說明 開發者獲取使用憑證后,可以使用該憑證對公眾賬號的自定義菜單進行創建、查詢和刪除等操作。 自定義菜單接口可實現以下類型按鈕: 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; } } }