How to implement custom personalized menus on WeChat, the following is an introduction to you
1. Global description <br />For detailed description, please refer to the first two articles.
2. Description of this article <br />This article is divided into five parts:
* Encapsulation of tool class AccessTokenUtils
* Reading and analysis of custom menus and personalized menu documents
* Analysis and construction of corresponding beans for menu JSON
* Implementation of custom menus
* Implementation of personalized menus WeChat custom menu All types of menus are given. At the end of this article, all demo source codes including the first four articles in this article will be given.
Encapsulation of tool class AccessTokenUtils
The above article has been introduced in detail about the acquisition and timing saving of AccessTokens. Here, the packaged AccessTokenUtils is directly given. The implementation principle and document reading will not be given.
AccessTokenUtils.java
package com.gist.utils;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStreamReader;import java.net.URL;import javax.net.ssl.HttpsURLConnection;import com.gist.bean.Access_token;import com.google.gson.Gson;/** * @author Gao Yuan</n> Email: [email protected]</n> Blog http://blog.csdn.net/wgyscsf</n> * Writing period 2016-4-7 5:44:33 pm */public class AccessTokenUtils { private static final long MAX_TIME = 7200 * 1000;// WeChat allows maximum Access_token validity time (ms) private static final String TAG = "WeixinApiTest";// TAG private static final String APPID = "wx889b020b3666b0b8";// APPID private static final String SECERT = "6da7676bf394f0a9f15fbf06027856bb";// Key/* * This method implements access_token, save and saves Access_token for only 2 hours. If it exceeds two hours, re-acquire it; if it does not exceed two hours, obtain it directly. This method depends on *: public static String getAccessToken(); * * Idea: Store the obtained Access_token and the current time in the file, * When extracting, determine the time difference between the current time and the time recorded in the storage. If it is greater than MAX_TIME, re-acquire it, and store the obtained access to the file to replace the original content*, and if it is less than MAX_TIME, obtain it directly. */ // In order to call without throwing exceptions, all exceptions are caught here. The code is a bit long. Public static String getSavedAccess_token() { Gson gson = new Gson();// Third-party jar, handles the conversion of json and beans String mAccess_token = null;// Access_token that needs to be obtained; FileOutputStream fos = null;// Output stream FileInputStream fis = null;// Input stream File file = new File("temp_access_token.temp");// Access_token save location try { // If the file does not exist, create if (!file.exists()) { file.createNewFile(); } } catch (Exception e1) { e1.printStackTrace(); } // If the file size is equal to 0, it means that the first time you use it, save Access_token if (file.length() == 0) { try { mAccess_token = getAccessToken();// Get AccessToken Access_token at = new Access_token(); at.setAccess_token(mAccess_token); at.setExpires_in(System.currentTimeMillis() + "");// Set the deposit time String json = gson.toJson(at); fos = new FileOutputStream(file, false);// Append fos.write((json).getBytes());// Save AccessToken and current time into the file fos.close(); return mAccess_token; } catch (Exception e) { e.printStackTrace(); } } else { // Read file content byte[] b = new byte[2048]; int len = 0; try { fis = new FileInputStream(file); len = fis.read(b); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } String mJsonAccess_token = new String(b, 0, len);// The content of the read file Access_token access_token = gson.fromJson(mJsonAccess_token, new Access_token().getClass()); if (access_token.getExpires_in() != null) { long saveTime = Long.parseLong(access_token.getExpires_in()); long nowTime = System.currentTimeMillis(); long remianTime = nowTime - saveTime; // System.out.println(TAG + "Time Difference:" + remianTime + "ms"); if (remianTime < MAX_TIME) { Access_token at = gson.fromJson(mJsonAccess_token, new Access_token().getClass()); mAccess_token = at.getAccess_token(); return mAccess_token; } else { mAccess_token = getAccessToken(); Access_token at = new Access_token(); at.setAccess_token(mAccess_token); at.setExpires_in(System.currentTimeMillis() + ""); String json = gson.toJson(at); try { fos = new FileOutputStream(file, false);// Append fos.write((json).getBytes()); fos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return mAccess_token; } } else { return null; } } return mAccess_token; } /* * Get the WeChat server AccessToken. This part is consistent with getAccess_token(), no comments are added*/ public static String getAccessToken() { String urlString = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APPID + "&secret=" + SECERT; String reslut = null; try { URL reqURL = new URL(urlString); HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL .openConnection(); InputStreamReader isr = new InputStreamReader( httpsConn.getInputStream()); char[] chars = new char[1024]; reslut = ""; int len; while ((len = isr.read(chars)) != -1) { reslut += new String(chars, 0, len); } isr.close(); } catch (IOException e) { e.printStackTrace(); } Gson gson = new Gson(); Access_token access_token = gson.fromJson(reslut, new Access_token().getClass()); if (access_token.getAccess_token() != null) { return access_token.getAccess_token(); } else { return null; } }}
Reading and analysis of custom menus and personalized menu documents
•Custom menu
◦Create menu interface
◦Custom menu query interface
◦Custom menu delete interface
◦Custom menu event push
◦Personalized menu interface
◦Get the menu configuration of the official account
• Document address: http://mp.weixin.qq.com/wiki/10/0234e39a2025342c17a7d23595c6b40a.html
•The official website document gives the following explanation:
* The custom menu interface can implement various types of buttons, as follows: 1. Click: click event...; 2. View: jump event...; 3.... (About the custom menu)
* Interface call request description http request method: POST (please use the https protocol) https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN (about custom menu)
* Example of request for click and view {"button":[...]} (About the custom menu)
* Parameter description...(About the custom menu)
* Create a personalized menu http request method: POST (please use the https protocol) https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=ACCESS_TOKEN (about personalized menu)
* Request example: {"button":[...],"matchrule":{...}}(About the personalized menu)
* Parameter description...(About the personalized menu)
* Developers can set the menus that users see through the following conditions (about the personalized menu):
1. User grouping (the business needs of developers can be completed with the help of user grouping)
2. Gender
3. Mobile phone operating system
4. Region (the region set by the user in the WeChat client)
5. Language (language set by the user on the WeChat client)
•understand:
◦It is a familiar POST request again, but I don’t quite understand the vague words about the call. I just know that we need to use the parameter "?access_token=ACCESS_TOKEN", which we have obtained in the previous article. If we change the request address "ACCESS_TOKEN" in the WeChat document to the ACCESS_TOKEN we obtained, and visit the URL, we will see "{"errcode":44002,"errmsg":"empty post data hint: [Gdveda0984vr23]"}". It probably means that empty post request data. Therefore, we need to pass parameters to the WeChat server through the form of POST request, and the parameter format is also given below the document: {"button": […]}, so we need to pass parameters to the WeChat server in this format.
◦ Regarding the parameter description, we can see that there are seven parameters in the custom menu creation. In addition to these seven parameters in the personalized menu interface, there are another eight parameters. By simply looking at this part of the document, we can understand that these eight parameters are used for matching and filtering for personalized menus.
◦Now, we need to construct json according to the requirements of the WeChat document to send this string of json data to the WeChat server through the post request, and json includes various types of button events we created.
Analysis and construction of corresponding beans for menu JSON
Custom menu json analysis (excluding personalized menu). The following code is an example given by the WeChat document.
Example of request for click and view
{ "button":[ { "type":"click", "name":"Today's song", "key":"V1001_TODAY_MUSIC" }, { "name":"menu", "sub_button":[ { "type":"view", "name":"search", "url":"http://www.soso.com/" }, { "type":"view", "name":"video", "url":"http://v.qq.com/" }, { "type":"click", "name":"like us", "key":"V1001_GOOD" }] }] } After analysis, we can see that this string of json data is divided into three layers: ""button":[{…},{…}]", "[{…},{{"name":menu, "sub_button":[{},{}]}]", "{"type":"view", "name:":"video", "url":"..."},{},{},{}", which may look dizzy.
However, if we can recall the WeChat menu we see in reality, it will be easier to understand: Level 1: menu (one menu), the lower one to three parent buttons; Level 2: parent button (1 to 3 parent buttons), the lower one to five child buttons; Level 3: child buttons (1 to 5 child buttons).
Now, we can see that json and the "menu" we understand can correspond one by one. The focus now is how to confirm the "level name" of each level, which is the corresponding javabean object in java.
At the same time, because there are multiple parent buttons under the first-level menu, it is in the form of a List<parent menu>. There may be multiple submenu under the parent button, which is also a List<submenu>; however, the parent button may also be a separate responsive button. is a separate parent button object. A subbutton is a separate subbutton object.
Looking at the parameter description about the custom menu, we can see that the buttons are divided into first-level buttons ("button") and second-level buttons ("sub_button"). There are also some common data types, such as: menu response type ("type"), menu title ("name"), click type parameters ("key"), view type parameters ("url"), media_id type and view_limited type parameters ("media_id").
•Data abstraction (no setter, getter written):
//Button base class public class BaseButton { private String type; private String name; private String key; private String url; private String media_id;} //Sub button public class SonButton extends BaseButton { private String sub_button;}//Parent button public class FatherButton extends BaseButton { private String button;//Maybe a parent button responds directly to @SerializedName("sub_button")//To ensure that the name of the subbutton after Gson parses is "sub_button", please search for private List<SonButton> sonButtons;//There may be multiple subbuttons}public class Menu {@SerializedName("button")private List<FatherButton> fatherButtons;}The above is the analysis of the complete custom menu and the construction of the corresponding javabean.
For a personalized menu, if you look at the documentation in this section, you will find that it is roughly the same as the custom menu, just multiple "configuration" jsons, the format is as follows: {"button":[…],"matchrule":{…}}.
We found that the "match" of json and "button" are of the same level, and the analysis and implementation are basically the same as above, and the implementation of javabean is directly given.
//The json corresponding to the json of the matching json public class MatchRule {private String group_id;private String sex;private String client_platform_type;private String country;private String province;private String city;private String language;}//Modify Menu.javapublic class Menu {@SerializedName("button")private List<FatherButton> fatherButtons;private MatchRule matchrule;} Implementation of custom menus
Task, we implement all WeChat button response types:
Task (Note: "m-0" means the parent button; "mn" means the mth parent button, the nth child button (m,n≠0)): 1-0: Name: click, response click event: click push event. 2-0: Name: Parent button 2. 2-1: Name: view, response event: Jump to the web page; 2-2: Name: scancode_push, response event: Scancode_waitmsg, response event: Scancode_waitmsg, response event: Scancode push event and the "Message receiving" prompt box pops up; 2-4: Name: pic_sysphoto, response event: Pop up the system to take photos and post pictures. 2-5: Name: pic_photo_or_album, response event: pop up and take pictures or post pictures on the album. 3-0: Name: Parent button 3. 3-1: Name: pic_weixin, Response event: Pop-up WeChat album sender; 3-2: Name: location_select, Response event: Pop-up geolocation selector; 3-3: Name: media_id, Response event: Delivery message (except text message); 3-4: Name: view_limited, Response event: Jump the graphic message url.
Implement the source code (referenced AccessTokenUtils.java in the first part: encapsulation of tool class AccessTokenUtils)
/* * Create a custom menu. */ @Test public void createCommMenu() { String ACCESS_TOKEN = AccessTokenUtils.getAccessToken();// Get AccessTokenUtils is an encapsulated class // Stitching API requires httpsurl link String urlString = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + ACCESS_TOKEN; try { // Create a url URL reqURL = new URL(urlString); // Get the link HttpsURLConnection httpsConn = (HttpsURLConnection) reqURL .openConnection(); httpsConn.setDoOutput(true); // Get the output stream of the connection to read the response content OutputStreamWriter osr = new OutputStreamWriter( httpsConn.getOutputStream()); osr.write(getMenuJson()); // Use the external method of this class to getMenuJson() osr.close(); // Return the result InputStreamReader isr = new InputStreamReader( httpsConn.getInputStream()); // Read the server's response content and display char[] chars = new char[1024]; String reslut = ""; int len; while ((len = isr.read(chars)) != -1) { reslut += new String(chars, 0, len); } System.out.println("Return result:" + reslut); isr.close(); } catch (IOException e) { e.printStackTrace(); } } public String getMenuJson() { Gson gson = new Gson();// json processing tool Menu menu = new Menu();// Menu class List<FatherButton> fatherButtons = new ArrayList<FatherButton>();// Parent button collection in the menu// ------------ // Parent button1 FatherButton fb1 = new FatherButton(); fb1.setName("click"); fb1.setType("click"); fb1.setKey("10"); // -------------------- // Parent button2 FatherButton fb2 = new FatherButton(); fb2.setName("parent button 2"); List<SonButton> sonButtons2 = new ArrayList<SonButton>();// Collection of child buttons// Subbutton 2-1 SonButton sb21 = new SonButton(); sb21.setName("view"); sb21.setUrl("http://www.baidu.com"); sb21.setType("view"); // Subbutton 2-2 SonButton sb22 = new SonButton(); sb22.setName("scancode_push"); sb22.setType("scancode_push"); sb22.setKey("22"); // Subbutton 2-3 SonButton sb23 = new SonButton(); sb23.setName("scancode_waitmsg"); sb23.setType("scancode_waitmsg"); sb23.setKey("23"); // Subbutton 2-4 SonButton sb24 = new SonButton(); sb24.setName("pic_sysphoto"); sb24.setType("pic_sysphoto"); sb24.setKey("24"); // Subbutton 2-4 SonButton sb24 = new SonButton(); sb24.setName("pic_sysphoto"); sb24.setType("pic_sysphoto"); sb24.setKey("24"); // Subbutton 2-4 SonButton sb24 = new SonButton(); sb24.setName("pic_sysphoto"); sb24.setKey("24"); // Subbutton 2-5 SonButton sb25 = new SonButton(); sb25.setName("pic_photo_or_album"); sb25.setType("pic_photo_or_album"); sb25.setKey("25"); // Add child button to child button set sonButtons2.add(sb21); sonButtons2.add(sb22); sonButtons2.add(sb23); sonButtons2.add(sb24); sonButtons2.add(sb25); // Put child button to 2-0 parent button set fb2.setSonButtons(sonButtons2); // -------------------- // Parent Button 3 FatherButton fb3 = new FatherButton(); fb3.setName("Presidy Button3"); List<SonButton> sonButtons3 = new ArrayList<SonButton>(); // Subbutton 3-1 SonButton sb31 = new SonButton(); sb31.setName("pic_weixin"); sb31.setType("pic_weixin"); sb31.setKey("31"); // Subbutton 3-2 SonButton sb32 = new SonButton(); sb32.setName("locatselect"); sb32.setType("location_select"); sb32.setKey("32"); // // Subbutton 3-3---> cannot be tested because media_id is required. This requires calling the material id. // SonButton sb33 = new SonButton(); // sb33.setName("media_id"); // sb33.setType("media_id"); // sb33.setMedia_id("???"); // // Subbutton 3-4--> cannot be tested because media_id is required. This requires calling the material id. // SonButton sb34 = new SonButton(); // sb34.setName("view_limited"); // sb34.setType("view_limited"); // sb34.setMedia_id("???"); // Add child button to child button queue sonButtons3.add(sb31); sonButtons3.add(sb32); // sonButtons3.add(sb33); // sonButtons3.add(sb34); // Put child buttons to 3-0 parent button queue fb3.setSonButtons(sonButtons3); // --------------------- // Add the parent button to the parent button collection fatherButtons.add(fb1); fatherButtons.add(fb2); fatherButtons.add(fb3); // Add the parent button queue to the menu bar menu.setFatherButtons(fatherButtons); String json = gson.toJson(menu); System.out.println(json);// Test output return json; } Implementation of personalized menus
•Task: Display different buttons according to gender (can be grouped by gender, region, mobile operating system, etc.)
• Modify code 1. Because it is implemented by different WeChat backgrounds, the interface is different. However, it is still a POST request. The code does not need to be changed. Just replace the original urlString.
// The httpsurl link required by the splicing API String urlString = "https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=" + ACCESS_TOKEN;
• Modify code 2. Just create a MatchRule, set a matching rule, and then add the matchrule to the menu to complete the matching rule.
// -----// Start setting the personalized menu here MatchRule matchrule = new MatchRule();matchrule.setSex("2");// Boys menu.setMatchrule(matchrule);// ---Source code download: http://xiazai.VeVB.COM/201606/yuanma/WeixinApi(VeVB.COM).rar
This article has been compiled into "Android WeChat Development Tutorial Summary", and "Java WeChat Development Tutorial Summary" welcomes everyone to learn and read.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.