序:
微信公眾號基本的菜單很難滿足個性化及多功能的實現,那么微信能否實現自定菜單呢,具體的功能又如何去實現么?下面就來學習一下微信自定義公眾號菜單吧!
自定義菜單接口可實現多種類型按鈕,如下:
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。
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,是專門給第三方平台旗下未微信認證(具體而言,是資質認證未通過)的訂閱號准備的事件類型,它們是沒有事件推送的,能力相對受限,其他類型的公眾號不必使用。
開始准備:
菜單創建接口調用請求說明
http請求方式:POST(請使用https協議)
https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN
參數說明
參數 | 是否必須 | 說明 |
button | 是 | 一級菜單數組,個數應為1~3個 |
sub_button | 否 | 二級菜單數組,個數應為1~5個 |
type | 是 | 菜單的響應動作類型,view表示網頁類型,click表示點擊類型,miniprogram表示小程序類型 |
name | 是 | 菜單標題,不超過16個字節,子菜單不超過60個字節 |
key | click等點擊類型必須 | 菜單KEY值,用於消息接口推送,不超過128字節 |
url | view、miniprogram類型必須 | 網頁鏈接,用戶點擊菜單可打開鏈接,不超過1024字節。type為miniprogram時,不支持小程序的老版本客戶端將打開本url。 |
media_id | media_id類型和view_limited類型必須 | 調用新增永久素材接口返回的合法media_id |
appid | miniprogram類型必須 | 小程序的appid(僅認證公眾號可配置) |
pagepath | miniprogram類型必須 | 小程序的頁面路徑 |
返回結果
正確時的返回JSON數據包如下:{"errcode":0,"errmsg":"ok"}
錯誤時的返回JSON數據包如下(示例為無效菜單名長度):{"errcode":40018,"errmsg":"invalid button name size"}
菜單查詢接口:
開發者還可使用接口查詢自定義菜單的結構。另外請注意,在設置了個性化菜單后,使用本自定義菜單查詢接口可以獲取默認菜單和全部個性化菜單信息。
請求說明
http請求方式:GET
https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
https://api.weixin.qq.com/cgi-bin/menu/get?access_token=ACCESS_TOKEN
菜單刪除接口
使用接口創建自定義菜單后,開發者還可使用接口刪除當前使用的自定義菜單。另請注意,在個性化菜單時,調用此接口會刪除默認菜單及全部個性化菜單。
請求說明
http請求方式:GET
https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=ACCESS_TOKEN
返回說明
對應創建接口,正確的Json返回結果:
{"errcode":0,"errmsg":"ok"}
{"errcode":0,"errmsg":"ok"}
動手實現:
對於菜單中按鈕屬性,可定義個菜單按鈕基類


1 /** 2 * 微信菜單基類 3 * @author Damon 4 */ 5 public class MenuButton 6 { 7 /** 8 * 菜單的響應動作類型,view表示網頁類型,click表示點擊類型,miniprogram表示小程序類型 9 */ 10 private String type = ""; 11 12 /** 13 * 菜單標題,不超過16個字節,子菜單不超過60個字節 14 */ 15 private String name = ""; 16 17 public String getType() 18 { 19 return type; 20 } 21 22 public void setType(String type) 23 { 24 this.type = type; 25 } 26 27 public String getName() 28 { 29 return name; 30 } 31 32 public void setName(String name) 33 { 34 this.name = name; 35 } 36 37 }
對於子菜單,可以繼承基類,同時對本身新增屬性對定義:

1 /** 2 * 子菜單 3 * @author Damon 4 * 5 */ 6 public class SubMenuButton extends MenuButton 7 { 8 /** 9 * click等點擊類型必須 菜單KEY值,用於消息接口推送,不超過128字節 10 */ 11 private String key =""; 12 13 /** 14 * view、miniprogram類型必須 網頁鏈接,用戶點擊菜單可打開鏈接,不超過1024字節。 15 * type為miniprogram時,不支持小程序的老版本客戶端將打開本url。 16 */ 17 private String url=""; 18 19 /** 20 * media_id類型和view_limited類型必須 調用新增永久素材接口返回的合法media_id 21 */ 22 private String media_id = ""; 23 24 /** 25 * miniprogram類型必須 小程序的appid(僅認證公眾號可配置) 26 */ 27 private String appid = ""; 28 29 /** 30 * miniprogram類型必須 小程序的頁面路徑 31 */ 32 private String pagepath = ""; 33 34 public String getKey() 35 { 36 return key; 37 } 38 39 public void setKey(String key) 40 { 41 this.key = key; 42 } 43 44 public String getUrl() 45 { 46 return url; 47 } 48 49 public void setUrl(String url) 50 { 51 this.url = url; 52 } 53 54 public String getMedia_id() 55 { 56 return media_id; 57 } 58 59 public void setMedia_id(String media_id) 60 { 61 this.media_id = media_id; 62 } 63 64 public String getAppid() 65 { 66 return appid; 67 } 68 69 public void setAppid(String appid) 70 { 71 this.appid = appid; 72 } 73 74 public String getPagepath() 75 { 76 return pagepath; 77 } 78 79 public void setPagepath(String pagepath) 80 { 81 this.pagepath = pagepath; 82 } 83 84 }
對導航窗口進行定義,即包含多個子菜單:

1 /** 2 * 導航菜單 3 * @author Damon 4 */ 5 public class LevelMenu extends MenuButton 6 { 7 8 /** 9 * 包含多個子菜單 定義名稱與json中一致,不然解析名稱對不上 10 */ 11 private SubMenuButton[] sub_button; 12 13 public SubMenuButton[] getSub_button() 14 { 15 return sub_button; 16 } 17 18 public void setSub_button(SubMenuButton[] sub_button) 19 { 20 this.sub_button = sub_button; 21 } 22 23 24 }
最終封裝一個菜單類,方便數據封裝和解析:

1 /** 2 * 微信菜單類 3 * @author Damon 4 */ 5 public class Menu 6 { 7 8 /* 定義名稱與json中一致,不然解析名稱對不上 */ 9 private MenuButton[] button; 10 11 public MenuButton[] getButton() 12 { 13 return button; 14 } 15 16 public void setButton(MenuButton[] button) 17 { 18 this.button = button; 19 } 20 21 }
基本對象都定義好了,下一步就是進行接口調用,實現創建自定義菜單:
實現主要分3步:
1、獲取有效的 access_token
2、組件菜單;
3、調用接口,實現創建

1 /** 2 * 創建菜單 3 * @param menu 4 * @return 5 */ 6 public boolean createMenu() 7 { 8 9 // 1、獲取access_token 10 WeChatTokenService tWeChatTokenService = new WeChatTokenService(); 11 String tAccess_Token = tWeChatTokenService.getToken("appid", "appsceret").getToken(); 12 13 // 2、組建菜單 14 String tMenuJSON = JSONObject.fromObject(getMenu()).toString(); 15 16 // 3、請求調用 17 String result = createMenubyHttps(tAccess_Token, tMenuJSON); 18 19 System.out.println(result); 20 21 return true; 22 }
其中 access_token的獲取可參考之前第三節的,這樣每個token都有2個小時的有效時間,不用頻繁獲取。
組件菜單,詳細如下:



1 /** 2 * 定義菜單屬性 3 * @return 4 */ 5 private Menu getMenu() 6 { 7 Menu menu = new Menu(); 8 9 // 建3個導航菜單 10 LevelMenu tLevelMenuOne = new LevelMenu(); 11 tLevelMenuOne.setName("Damon"); 12 LevelMenu tLevelMenuTwo = new LevelMenu(); 13 tLevelMenuTwo.setName("Panou"); 14 LevelMenu tLevelMenuThree = new LevelMenu(); 15 tLevelMenuThree.setName("Papaw"); 16 17 // 第一個導航菜單的子菜單 18 SubMenuButton tSubMenuButton_oneone = new SubMenuButton(); 19 tSubMenuButton_oneone.setType(SysCon.WECHAT_MENU_TYPE_CLICK); 20 tSubMenuButton_oneone.setName("play basketball"); 21 tSubMenuButton_oneone.setKey("11"); 22 23 SubMenuButton tSubMenuButton_onetwo = new SubMenuButton(); 24 tSubMenuButton_onetwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK); 25 tSubMenuButton_onetwo.setName("swimming"); 26 tSubMenuButton_onetwo.setKey("12"); 27 28 // 加入導航菜單 29 tLevelMenuOne.setSub_button(new SubMenuButton[] 30 { tSubMenuButton_oneone, tSubMenuButton_onetwo }); 31 32 // 第二 個導航菜單的子菜單 33 SubMenuButton tSubMenuButton_twoone = new SubMenuButton(); 34 tSubMenuButton_twoone.setType(SysCon.WECHAT_MENU_TYPE_CLICK); 35 tSubMenuButton_twoone.setName("watching TV"); 36 tSubMenuButton_twoone.setKey("21"); 37 38 SubMenuButton tSubMenuButton_twotwo = new SubMenuButton(); 39 tSubMenuButton_twotwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK); 40 tSubMenuButton_twotwo.setName("play games"); 41 tSubMenuButton_twotwo.setKey("22"); 42 43 SubMenuButton tSubMenuButton_twothree = new SubMenuButton(); 44 tSubMenuButton_twothree.setType(SysCon.WECHAT_MENU_TYPE_CLICK); 45 tSubMenuButton_twothree.setName("shopping"); 46 tSubMenuButton_twothree.setKey("23"); 47 48 // 加入導航菜單 49 tLevelMenuTwo.setSub_button(new SubMenuButton[] 50 { tSubMenuButton_twoone, tSubMenuButton_twotwo, tSubMenuButton_twothree }); 51 52 // 第三個導航菜單的子菜單 53 SubMenuButton tSubMenuButton_threeone = new SubMenuButton(); 54 tSubMenuButton_threeone.setType(SysCon.WECHAT_MENU_TYPE_CLICK); 55 tSubMenuButton_threeone.setName("cring"); 56 tSubMenuButton_threeone.setKey("31"); 57 58 SubMenuButton tSubMenuButton_threetwo = new SubMenuButton(); 59 tSubMenuButton_threetwo.setType(SysCon.WECHAT_MENU_TYPE_CLICK); 60 tSubMenuButton_threetwo.setName("laughing"); 61 tSubMenuButton_threetwo.setKey("32"); 62 63 // 加入導航菜單 64 tLevelMenuThree.setSub_button(new SubMenuButton[] 65 { tSubMenuButton_threeone, tSubMenuButton_threetwo }); 66 67 menu.setButton(new MenuButton[] 68 { tLevelMenuOne, tLevelMenuTwo, tLevelMenuThree }); 69 70 return menu; 71 72 }
通過對象的封裝進行獲取,然后轉成JSON格式。
接着就是通過https進行接口調用(這里用到之前工具類中HTTPS的請求方法):

1 /** 2 * 請求調用,設置菜單信息 3 * @param url 4 * @param requestData 5 * @return 6 */ 7 private String createMenubyHttps(String access_token, String requestData) 8 { 9 // 返回報文 10 String strResp = ""; 11 String path = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + access_token; 12 try 13 { 14 strResp = WeChatUtil.doHttpsPost(path, requestData); 15 } 16 catch (HttpException e) 17 { 18 // 發生致命的異常,可能是協議不對或者返回的內容有問題 19 System.out.println("Please check your provided http address!" + e); 20 e.printStackTrace(); 21 } 22 catch (IOException e) 23 { 24 // 發生網絡異常 25 } 26 catch (Exception e) 27 { 28 System.out.println(e); 29 } 30 finally 31 {} 32 return strResp; 33 34 }
自定義菜單的基本調用就實現了,可以看到效果圖:


這里寫的都是基本的點擊事件,但是沒有實現,具體的自己去發揮了~