步驟一:綁定域名
先登錄微信公眾平臺(tái)進(jìn)入“公眾號(hào)設(shè)置”的“功能設(shè)置”里填寫(xiě)“JS接口安全域名”。我用的是微信平臺(tái)測(cè)試賬號(hào)綁定了一個(gè)ngrok內(nèi)外網(wǎng)映射工具生成的外網(wǎng)域名,如下圖。(注意:JS接口安全域名不需要加http前綴,不需要加項(xiàng)目名)
備注:登錄后可在“開(kāi)發(fā)者中心”查看對(duì)應(yīng)的接口權(quán)限。(測(cè)試號(hào)下面有列接口開(kāi)放權(quán)限,可以對(duì)應(yīng)查看)
步驟二:引入JS文件
在需要調(diào)用JS接口的頁(yè)面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.2.0.js----最好引入高版本文件,引用低版本開(kāi)發(fā)的網(wǎng)頁(yè)在ios上有點(diǎn)小問(wèn)題,比如上傳圖片,ios端并不能夠根據(jù)返回的localid進(jìn)行在線預(yù)覽。
備注:支持使用 AMD/CMD 標(biāo)準(zhǔn)模塊加載方法加載
步驟三:通過(guò)config接口注入權(quán)限驗(yàn)證配置
所有需要使用JS-SDK的頁(yè)面必須先注入配置信息,否則將無(wú)法調(diào)用(同一個(gè)url僅需調(diào)用一次,對(duì)于變化url的SPA的web app可在每次url變化時(shí)進(jìn)行調(diào)用,目前Android微信客戶端不支持pushState的H5新特性,所以使用pushState來(lái)實(shí)現(xiàn)web app的頁(yè)面會(huì)導(dǎo)致簽名失敗,此問(wèn)題會(huì)在Android6.2中修復(fù))。
調(diào)用jsjdk接口的每一個(gè)頁(yè)面都應(yīng)該進(jìn)行權(quán)限驗(yàn)證配置,具體配置代碼如下:
wx.config({
debug: true, // 開(kāi)啟調(diào)試模式,調(diào)用的所有api的返回值會(huì)在客戶端alert出來(lái),若要查看傳入的參數(shù),可以在pc端打開(kāi),參數(shù)信息會(huì)通過(guò)log打出,僅在pc端時(shí)才會(huì)打印。
appId: '', // 必填,公眾號(hào)的唯一標(biāo)識(shí)
timestamp: '', // 必填,生成簽名的時(shí)間戳
nonceStr: '', // 必填,生成簽名的隨機(jī)串
signature: '',// 必填,簽名
jsApiList: [] // 必填,需要使用的JS接口列表
});
其中,appid就是微信公眾號(hào)的appid,timestamp就是生成簽名的時(shí)間戳(獲取簽名下面會(huì)寫(xiě)),nonceStr是生成簽名的隨機(jī)串,signature是生成的簽名。頁(yè)面調(diào)用哪個(gè)接口就要在接口列表里面寫(xiě)上這個(gè)接口,否則調(diào)用無(wú)效。
?。。?!下面講一下獲取簽名的方法。
獲取簽名的基本步驟:1、根據(jù)appid和密鑰secret獲取accesstoken;2、根據(jù)accesstoken獲取ticket;3、根據(jù)ticket獲取簽名(前端進(jìn)行接口注入權(quán)限驗(yàn)證配置用到)。以上三個(gè)步驟,錯(cuò)一步都不行,下面直接上代碼~~~~~
//全局定義變量
public static String localurl = "http://76b4cde7.ngrok.io/test";//項(xiàng)目地址--外網(wǎng)能夠訪問(wèn)到項(xiàng)目的地址
public static String appid="wx2eb767284091779a";//appid
public static String secret="cea6a9fef9373b04b8ea6b1b2f2463b4";//密鑰
//獲取accesstoken(accesstoken每天的獲取次數(shù)有限,所以獲取完存到數(shù)據(jù)庫(kù),用的時(shí)候直接調(diào)用。兩個(gè)小時(shí)獲取更新一次。)
public void getWeiXinAccessToken()
{
System.out.println(appid + "--" + secret);
if (StringUtils.isEmpty(appid) || StringUtils.isEmpty(secret))
{
System.out.println("微信配置參數(shù)出錯(cuò)");
}
Token token = new Token();
try
{
String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret;
HttpClient httpClient = new HttpClient();
GetMethod getMethod = new GetMethod(url);
int execute = httpClient.executeMethod(getMethod);
System.out.println("execute:" + execute);
String getResponse = getMethod.getResponseBodyAsString();
JSONObject obj = JSONObject.parseObject(getResponse);
token.setAccessToken(obj.get("access_token").toString());
}
catch (IOException e)
{
System.out.println("--accesstoken獲取失敗--");
e.printStackTrace();
}
String ticket = getJSApiTicket(token.getAccessToken());
token.setJsapiTicket(ticket);
wechatService.saveToken(token);
System.out.println("token:"+token.getAccessToken()+"\nticket:"+token.getJsapiTicket());
}
//根據(jù)accesstoken獲取ticket
public String getJSApiTicket(String accesstoken)
{
String urlStr = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + accesstoken + "&type=jsapi";
String backData = sendGet(urlStr, "utf-8", 10000);
String ticket = (String) JSONObject.parseObject(backData).get("ticket");
return ticket;
}
//獲取簽名(url是前端請(qǐng)求帶過(guò)來(lái)的參數(shù))
public ReturnMap getSign(@RequestParam Map<String, String> map)
{
ReturnMap rm = new ReturnMap();
Token token = this.wechatService.findToken();
String ticket = token.getJsapiTicket();
if (StringUtils.isBlank(map.get("url").toString()))
{
rm.setCode(-1);
rm.setMsg("參數(shù)丟失");
}
String url = (String) map.get("url");
Map<String, Object> map1 = getWxConfig(ticket, url);
rm.setCode(1);
rm.setData(map1);
return rm;
}
//獲取簽名主要邏輯
public static Map<String, Object> getWxConfig(String ticket, String url)
{
String appID = appid;//獲取appid
Map<String, Object> config = new HashMap<String, Object>();
String nonceStr = UUID.randomUUID().toString(); // 必填,生成簽名的隨機(jī)串
String timestamp = Long.toString(System.currentTimeMillis() / 1000); // 必填,生成簽名的時(shí)間戳
String requestUrl = localurl + url;//拼接需要調(diào)用jsjdk的網(wǎng)頁(yè)
String signature = "";
// 注意這里參數(shù)名必須全部小寫(xiě),且必須有序
String sign = "jsapi_ticket=" + ticket + "&noncestr=" + nonceStr + "×tamp=" + timestamp + "&url=" + requestUrl;
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(sign.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
config.put("appId", appID);
config.put("timestamp", timestamp);
config.put("nonceStr", nonceStr);
config.put("signature", signature);
return config;
}
//簽名解析
private static String byteToHex(final byte[] hash)
{
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
//java后端get請(qǐng)求方法:
public static String sendGet(String url, String charset, int timeout)
{
String result = "";
try
{
URL u = new URL(url);
try
{
URLConnection conn = u.openConnection();
conn.connect();
conn.setConnectTimeout(timeout);
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), charset));
String line = "";
while ((line = in.readLine()) != null)
{
result = result + line;
}
in.close();
}
catch (IOException e)
{
return result;
}
}
catch (MalformedURLException e)
{
return result;
}
return result;
}