js-sdk探索之微信網頁分享

微信是一個很不錯的傳播平臺,最近公司須要作一個新年賀卡,使用html5製做一個很小的動畫,而後發送給客戶,不須要和後臺有任何的聯繫,一個很簡單的功能,須要利用微信的分享功能,畢竟微信分享的帶小圖片、簡介、標題比發送一個連接要比一個光禿禿的連接要高大上的多。好了,廢話很少說了,進入正題吧。html

剛開始我也到網上去搜了一下,看到好多這個版本的,我也貼一下:html5

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已經支持開發接口支持微信分享了,怎麼實現,下面一一道來:java

微信官方js-sdk連接地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html 有興趣能夠本身去研究研究,下面只是我本身的一些經驗,水平有限,有錯誤之處歡迎你們指出。git

1. 要使用js-sdk,首先你得擁有一個微信認證過的訂閱號或者服務號(我的認爲若是開發的仍是服務號好),而後按照微信js-sdk api的步驟來,先登陸微信公衆平臺進入「公衆號設置」的「功能設置」裏填寫「JS接口安全域名」。js接口安全域名能夠設置三個,意思是你的網頁要想使用js-sdk,訪問就必須在這個域名下(若是域名帶有端口號,設置的時候也必須帶有端口號,微信上雖說只支持80端口,可是我用其餘端口好像也能夠)。web

image

2. 在須要調用JS接口的頁面引入以下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.jsajax

<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中修復)。這裏只說分享朋友圈和分享給朋友接口。算法

wx.config({
        debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。
        appId: appId, // 必填,公衆號的惟一標識
        timestamp: timestamp, // 必填,生成簽名的時間戳
        nonceStr: nonceStr, // 必填,生成簽名的隨機串
        signature: signature,// 必填,簽名,見附錄1
        jsApiList: [
        'onMenuShareTimeline',
        'onMenuShareAppMessage'
        ] // 必填,分享朋友圈和分享朋友接口名
    });

4.經過ready接口處理成功驗證。json

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接口的基本步驟,完成了這些,就能夠完成一個以下的分享框:api

image

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 + "&timestamp="+ 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]; 
        ob[0] = Digit[(ib >>> 4) & 0X0F]; 
        ob[1] = Digit[ib & 0X0F]; 
        String s = new String(ob); 
        return s; 
    } 
    private static String byteArrayToHexString(byte[] bytearray) { 
        String strDigest = ""; 
        for (int i = 0; i < bytearray.length; i++) { 
            strDigest += byteToHexString(bytearray[i]); 
        } 
        return strDigest; 
    } 
    public byte[] getDigestOfBytes(byte[] byteData) { 
        process_input_bytes(byteData); 
        byte[] digest = new byte[20]; 
        for (int i = 0; i < digestInt.length; i++) { 
            intToByteArray(digestInt[i], digest, i * 4); 
        } 
        return digest; 
    } 
    public String getDigestOfString(byte[] byteData) { 
        return byteArrayToHexString(getDigestOfBytes(byteData)); 
    } 
    public static void main(String[] args) { 
        String data = "123456"; 
        System.out.println(data); 
        String digest = new SHA1().getDigestOfString(data.getBytes()); 
        System.out.println(digest);
    } 
}

6>最後在頁面調用一下就能夠了。

$(document).ready(function(e) {
        var url = location.href;
         $.ajax({
            url:"http://test/WeiXinJsSdkConfiger",
            data:{
                "url":url
                }, //以鍵/值對的形式
            async : true,
            dataType : "jsonp",
            jsonp: "callbackparam",//傳遞給請求處理程序或頁面的,用以得到jsonp回調函數名的參數名(默認爲:callback)
            jsonpCallback:"success_jsonpCallback",//自定義的jsonp回調函數名稱,默認爲jQuery自動生成的隨機函數名
            success : function(data) {
                wx.config({
                  debug: false,
                  appId: data.appid,
                  timestamp: data.timeStamp,
                  nonceStr: data.noncestr,
                  signature: data.signature,
                  jsApiList: [
                    'onMenuShareTimeline',
                    'onMenuShareAppMessage',
                  ]
                  });
            }
         });
        wx.ready(function(){ 
            var shareData = {
            title: '1111111', // 分享標題
            desc: '111111', // 分享描述
            link: location.hostname+location.pathname,
            imgUrl: '11111'
          };
          wx.onMenuShareAppMessage(shareData);
          wx.onMenuShareTimeline(shareData); 
        });
});

得到access_token和jsapi_ticket有必要的可緩存一下,我的建議這樣,大概這樣能夠實現微信分享了,其實這樣js-sdk中全部的函數均可以使用了,其實很簡單的,又不明白的能夠聯繫qq:980527632; 要源碼的留郵箱

因索要源碼人數過多,來不及發送,故附上百度雲盤資源:http://pan.baidu.com/s/1sj5JUVF

相關文章
相關標籤/搜索