原文地址html
微信是一個很不錯的傳播平臺,最近公司須要作一個新年賀卡,使用html5製做一個很小的動畫,而後發送給客戶,不須要和後臺有任何的聯繫,一個很簡單的功能,須要利用微信的分享功能,畢竟微信分享的帶小圖片、簡介、標題比發送一個連接要比一個光禿禿的連接要高大上的多。好了,廢話很少說了,進入正題吧。html5
剛開始我也到網上去搜了一下,看到好多這個版本的,我也貼一下:java
var shareData = { "appid": appid, //公衆號的appID "img_url": imgUrl, //縮略圖地址 "img_width": "120", //圖片的寬度 "img_height": "120",//圖片的高度 "link": lineLink, //分享的連接 "desc": descContent,//摘要的信息 "title": shareTitle //分享的標題,默認爲網頁標題 }; function shareFriend() { WeixinJSBridge.invoke('sendAppMessage',shareData, function(res) { //定義分享完成後的事 alert(dasd); }) } function shareTimeline() { WeixinJSBridge.invoke('shareTimeline',shareData, function(res) { //_report('timeline', res.err_msg); }); } // 當微信內置瀏覽器完成內部初始化後會觸發WeixinJSBridgeReady事件。 document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() { // 發送給好友 WeixinJSBridge.on('menu:share:appmessage', function(argv){ shareFriend(); }); // 分享到朋友圈 WeixinJSBridge.on('menu:share:timeline', function(argv){ shareTimeline(); }); }, false);
可能這個版本在微信沒有發佈js-sdk時是有用的,可是如今微信好像把這個方法設置了權限,這個方法已經不可用了,因此我到微信官方去看了一下,微信js-sdk已經支持開發接口支持微信分享了,怎麼實現,下面一一道來:git
微信官方js-sdk連接地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html 有興趣能夠本身去研究研究,下面只是我本身的一些經驗,水平有限,有錯誤之處歡迎你們指出。web
1. 要使用js-sdk,首先你得擁有一個微信認證過的訂閱號或者服務號(我的認爲若是開發的仍是服務號好),而後按照微信js-sdk api的步驟來,先登陸微信公衆平臺進入「公衆號設置」的「功能設置」裏填寫「JS接口安全域名」。js接口安全域名能夠設置三個,意思是你的網頁要想使用js-sdk,訪問就必須在這個域名下(若是域名帶有端口號,設置的時候也必須帶有端口號,微信上雖說只支持80端口,可是我用其餘端口好像也能夠)。ajax
2. 在須要調用JS接口的頁面引入以下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js算法
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
3.經過config接口注入權限驗證配置,全部須要使用JS-SDK的頁面必須先注入配置信息,不然將沒法調用(同一個url僅需調用一次,對於變化url的SPA的web app可在每次url變化時進行調用,目前Android微信客戶端不支持pushState的H5新特性,因此使用pushState來實現web app的頁面會致使簽名失敗,此問題會在Android6.2中修復)。這裏只說分享朋友圈和分享給朋友接口。json
wx.config({
debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: appId, // 必填,公衆號的惟一標識 timestamp: timestamp, // 必填,生成簽名的時間戳 nonceStr: nonceStr, // 必填,生成簽名的隨機串 signature: signature,// 必填,簽名,見附錄1 jsApiList: [ 'onMenuShareTimeline', 'onMenuShareAppMessage' ] // 必填,分享朋友圈和分享朋友接口名 });
4.經過ready接口處理成功驗證。api
wx.ready(function () { // config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。 var shareData = { title: title, // 分享標題 desc: desc, // 分享描述 link: link, //網頁地址 imgUrl: imgUrl, //小圖片的地址 success: function () { // 用戶確認分享後執行的回調函數 }, cancel: function () { // 用戶取消分享後執行的回調函數 } }; wx.onMenuShareAppMessage(shareData); wx.onMenuShareTimeline(shareData); });
5.以上就是微信文檔中的處理js-sdk接口的基本步驟,完成了這些,就能夠完成一個以下的分享框:瀏覽器
6.上面的這些步驟都是微信文檔上有的,copy就行,我我的以爲初次接觸,微信js-sdk的config配置相對來講是要複雜一點。就是第三點裏面的簽名比較難一點,下面我就詳細的說一下我是怎麼得到配置的參數的(appid,timestamp,noncestr,signature);首先找到js-sdk生成簽名的文檔,閱讀發現signature的生成是須要密鑰的,就是咱們公衆號AppSecret,這個東西是不能被別人知道的,因此咱們處理密鑰必定要在後臺處理,在html處理的話會泄漏你的公衆號關注者的信息的。因此咱們得在後臺寫一個接口,用來返回config裏的配置信息;後臺怎麼處理呢?(後臺是用java寫的)
1>首先隨機生成一個字符串(noncestr)和一個隨機時間戳(timestamp),這就解決了兩個配置項;
noncestr = Double.toString(Math.random()).substring(2, 15);//隨機字符串 timeStamp =((int)(new Date().getTime()/1000))+"";//隨機時間戳
2>而後就的得到微信的基礎支持,訪問微信的https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET接口,得到返回來的access_token;
public String getAccess_token(){ System.out.println("從新請求access_token"); String access_token = ""; String str = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&"; str += "appid=" + APPID + "&secret=" + APPSECRET; try { URL url = new URL(str); HttpURLConnection connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(CONNECTTIMEOUT); connection.setReadTimeout(READTIME); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8")); StringBuffer stringBuffer = new StringBuffer(); String temp = ""; while((temp = bufferedReader.readLine())!= null){ stringBuffer.append(temp); System.out.println(temp); } String result = stringBuffer.toString(); JSONObject root = JSONObject.fromObject(result); access_token = root.getString("access_token"); bufferedReader.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return access_token; }
3>得到微信的access_token後,就能夠得到jsapi_ticket了,訪問微信的https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi接口,得到返回來的jsapi_ticket;
public String getJsapi_ticket(String access_token){ System.out.println("從新請求jsapi_ticket"); String jsapi_ticket = ""; String str = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + access_token + "&type=jsapi"; try { URL url = new URL(str); HttpURLConnection connection = (HttpURLConnection)url.openConnection(); connection.setRequestMethod("GET"); connection.setConnectTimeout(CONNECTTIMEOUT); connection.setReadTimeout(READTIME); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream(),"utf-8")); StringBuffer stringBuffer = new StringBuffer(); String temp = ""; while((temp = bufferedReader.readLine())!= null){ stringBuffer.append(temp); } String result = stringBuffer.toString(); JSONObject root = JSONObject.fromObject(result); jsapi_ticket = root.getString("ticket"); bufferedReader.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return jsapi_ticket; }
4>得到jsapi_ticket,noncestr,timestamp還有你的網頁地址後就能夠生成簽名了;
public WeiXinJsServer(String url,HttpServletRequest request) { this.noncestr = Double.toString(Math.random()).substring(2, 15); this.timeStamp =((int)(new Date().getTime()/1000))+""; String access_token = getAccess_token(); String Jsapi_ticket = getJsapi_ticket(access_token); String str = "jsapi_ticket=" + Jsapi_ticket + "&noncestr=" + noncestr + "×tamp="+ timeStamp +"&url=" + url; this.signature = new SHA1().getDigestOfString(str.getBytes()); }
5>最後在奉上sha1算法;
public class SHA1 { private final int[] abcde = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; private int[] digestInt = new int[5]; private int[] tmpData = new int[80]; private int process_input_bytes(byte[] bytedata) { System.arraycopy(abcde, 0, digestInt, 0, abcde.length); byte[] newbyte = byteArrayFormatData(bytedata); int MCount = newbyte.length / 64; for (int pos = 0; pos < MCount; pos++) { for (int j = 0; j < 16; j++) { tmpData[j] = byteArrayToInt(newbyte, (pos * 64) + (j * 4)); } encrypt(); } return 20; } private byte[] byteArrayFormatData(byte[] bytedata) { int zeros = 0; int size = 0; int n = bytedata.length; int m = n % 64; if (m < 56) { zeros = 55 - m; size = n - m + 64; } else if (m == 56) { zeros = 63; size = n + 8 + 64; } else { zeros = 63 - m + 56; size = (n + 64) - m + 64; } byte[] newbyte = new byte[size]; System.arraycopy(bytedata, 0, newbyte, 0, n); int l = n; newbyte[l++] = (byte) 0x80; for (int i = 0; i < zeros; i++) { newbyte[l++] = (byte) 0x00; } long N = (long) n * 8; byte h8 = (byte) (N & 0xFF); byte h7 = (byte) ((N >> 8) & 0xFF); byte h6 = (byte) ((N >> 16) & 0xFF); byte h5 = (byte) ((N >> 24) & 0xFF); byte h4 = (byte) ((N >> 32) & 0xFF); byte h3 = (byte) ((N >> 40) & 0xFF); byte h2 = (byte) ((N >> 48) & 0xFF); byte h1 = (byte) (N >> 56); newbyte[l++] = h1; newbyte[l++] = h2; newbyte[l++] = h3; newbyte[l++] = h4; newbyte[l++] = h5; newbyte[l++] = h6; newbyte[l++] = h7; newbyte[l++] = h8; return newbyte; } private int f1(int x, int y, int z) { return (x & y) | (~x & z); } private int f2(int x, int y, int z) { return x ^ y ^ z; } private int f3(int x, int y, int z) { return (x & y) | (x & z) | (y & z); } private int f4(int x, int y) { return (x << y) | x >>> (32 - y); } private void encrypt() { for (int i = 16; i <= 79; i++) { tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14] ^ tmpData[i - 16], 1); } int[] tmpabcde = new int[5]; for (int i1 = 0; i1 < tmpabcde.length; i1++) { tmpabcde[i1] = digestInt[i1]; } for (int j = 0; j <= 19; j++) { int tmp = f4(tmpabcde[0], 5) + f1(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[j] + 0x5a827999; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int k = 20; k <= 39; k++) { int tmp = f4(tmpabcde[0], 5) + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[k] + 0x6ed9eba1; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int l = 40; l <= 59; l++) { int tmp = f4(tmpabcde[0], 5) + f3(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[l] + 0x8f1bbcdc; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int m = 60; m <= 79; m++) { int tmp = f4(tmpabcde[0], 5) + f2(tmpabcde[1], tmpabcde[2], tmpabcde[3]) + tmpabcde[4] + tmpData[m] + 0xca62c1d6; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1], 30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int i2 = 0; i2 < tmpabcde.length; i2++) { digestInt[i2] = digestInt[i2] + tmpabcde[i2]; } for (int n = 0; n < tmpData.length; n++) { tmpData[n] = 0; } } private int byteArrayToInt(byte[] bytedata, int i) { return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16) | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff); } private void intToByteArray(int intValue, byte[] byteData, int i) { byteData[i] = (byte) (intValue >>> 24); byteData[i + 1] = (byte) (intValue >>> 16); byteData[i + 2] = (byte) (intValue >>> 8); byteData[i + 3] = (byte) intValue; } private static String byteToHexString(byte ib) { char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; char[] ob = new char[2