微信公众平台开发:接入JS-SDK和实现分享功能

汝才良
2023-12-01

微信公众平台开发:接入JS-SDK和实现分享功能

一、本文是实现微信公众号自定义的分享功能开发,也是亲自实践实现该功的一些总结体会。
首先贴上微信JS-SDK说明文档地址:http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html
其次,实现该功能分为四个步骤:
1. 绑定域名,先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”;
2. 引入JS文件,在需要调用JS接口的页面引入JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.0.0.js
3. 通过config接口注入权限验证配置,所有需要使用JS-SDK的页面必须先注入配置信息,否则将无法调用(同一个url仅需调用一次,对于变化url的SPA的web app可在每次url变化时进行调用);
4. 通过ready接口处理成功验证。

       ![这里写图片描述](https://img-blog.csdn.net/20161011143315576)
 其中最重要的就是第三步,获取config配置的签名signature ,这里着重描述,如下:
 wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: '', // 必填,公众号的唯一标识
    timestamp: , // 必填,生成签名的时间戳
    nonceStr: '', // 必填,生成签名的随机串
    signature: '',// 必填,签名,见附录1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
});

贴上微信 JS 接口签名校验工具

> http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign

二、实例说明
1. 前端页面share.html

<!DOCTYPE html>
<head>
    <title>微信js分享接口</title>
    <meta charset="UTF-8">
    <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    <script src="http://libs.baidu.com/jquery/1.2.3/jquery.min.js"></script>
</head>
<body>
测试测试测试
<script>
    $(document).ready(function(){
        initPage();
    });
    function initPage() {
        alert(window.location.href);/***用于获得当前连接url用**/
        /***用户点击分享到微信圈后加载接口接口*******/
        $.post("http://xxxxxxx.xxxxx.xxx/demo/wm/share.do",{"url":window.location.href},function(data,status){
            data=eval("("+data+")");
            console.log(data.appid+" "+data.timestamp+" "+data.nonceStr+" "+data.signature);
            wx.config({
                debug: true,
                appId: data.appid,
                timestamp:data.timestamp,
                nonceStr:data.nonceStr,
                signature:data.signature,
                jsApiList: [
                    'checkJsApi',
                    'onMenuShareTimeline',
                    'hideOptionMenu',
                ]
            });
            var shareTitle = "一起分享吧!";
            var shareImg = "http://imgsrc.baidu.com/baike/pic/item/509b9fcb7bf335ab52664fdb.jpg";
            wx.ready(function(){
                alert("准备分享");
                wx.onMenuShareTimeline({
                    title : shareTitle, // 分享标题
                    link : '', // 分享链接
                    imgUrl : shareImg, // 分享图标
                    success : function() {
                        // 用户确认分享后执行的回调函数
                        alert("分享成功");
                    },
                    cancel : function() {
                        // 用户取消分享后执行的回调函数
                        alert("分享取消");
                    }
                });
                //wx.hideOptionMenu();/***隐藏分享菜单****/
            });
        });
    }
</script>
</body>
</html>
  1. 后台处理请求
    WeixinController.java
    @RequestMapping(value = "/share", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, String> share(String url) throws Exception {
        Map<String, String> ret = new HashMap<String, String>();
        String jsapi_ticket = WeixinUtil.getJsapiTicket();
        String timestamp = Long.toString(System.currentTimeMillis() / 1000);
        String nonceStr = UUID.randomUUID().toString();
        String signature = SignUtil.getSignature(
            jsapi_ticket, nonceStr, timestamp,
            url);
        ret.put("url", url);
        ret.put("jsapi_ticket", jsapi_ticket);
        ret.put("nonceStr", nonceStr);
        ret.put("timestamp", timestamp);
        ret.put("signature", signature);
        ret.put("appid", "wxc6599d2c37b5e478");
        return ret;
    }

3.获取accessToken

    /**
     * 获取accessToken
     * 
     * @return
     * @throws ParseException
     * @throws IOException
     */
    public static AccessToken getAccessToken() throws ParseException, IOException {
        AccessToken token = new AccessToken();
        String url = ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);
        JSONObject jsonObject = doGetStr(url);
        if (jsonObject != null) {
            token.setToken(jsonObject.getString("access_token"));
            token.setExpiresIn(jsonObject.getInt("expires_in"));
        }
        return token;
    }

4.获取jsapi_ticket

    /**
     * 
     * 获取jsapi_ticket
     * 
     * @return
     * @throws IOException
     * @throws ParseException
     */
    public static String getJsapiTicket() throws ParseException, IOException {
        AccessToken token = WeixinUtil.getAccessToken();
        String url = JSAPI_TICKET.replace("ACCESS_TOKEN", token.getToken());
        JSONObject jsonObject = doGetStr(url);
        String jsapi_ticket = null;
        if (jsonObject != null) {
            jsapi_ticket = jsonObject.getString("ticket");
        }
        return jsapi_ticket;
    }

5.获取签名
SignUtil .java

import java.security.MessageDigest;

public class SignUtil {

    /**
     * 获得分享链接的签名。
     * @param ticket
     * @param nonceStr
     * @param timeStamp
     * @param url
     * @return
     * @throws Exception
     */
    public static String getSignature(String ticket, String nonceStr, String timeStamp, String url) throws Exception {
        String sKey = "jsapi_ticket=" + ticket
                + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp
                + "&url=" + url;
        System.out.println(sKey);
        return getSignature(sKey);
    }


 /**
     * 验证签名。
     * 
     * @param signature
     * @param timestamp
     * @param nonce
     * @return
     */
    public static String getSignature(String sKey) throws Exception {
        String ciphertext = null;
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        byte[] digest = md.digest(sKey.toString().getBytes());
        ciphertext = byteToStr(digest);
        return ciphertext.toLowerCase();
    }

 /** 
     * 将字节数组转换为十六进制字符串 
     *  
     * @param byteArray 
     * @return 
     */ 
    private static String byteToStr(byte[] byteArray) {  
        String strDigest = "";  
        for (int i = 0; i < byteArray.length; i++) {  
            strDigest += byteToHexStr(byteArray[i]);  
        }  
        return strDigest;  
    }  
  /** 
     * 将字节转换为十六进制字符串 
     *  
     * @param mByte 
     * @return 
     */ 
    private static String byteToHexStr(byte mByte) {  
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };  
        char[] tempArr = new char[2];  
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];  
        tempArr[1] = Digit[mByte & 0X0F];  

        String s = new String(tempArr);  
        return s;  
    }
}

以上是大部分代码,稍加修改就可实现
三、注意要点
1.invalid signature签名错误问题
首先需确认签名算法正确,可用 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。也就是你自己后台生成签名要和微信校验算法生成的签名一致才可以(可能大小写不同)。

1.1是否获取到需要填充字段的值
`console.log(data.appid+" "+data.timestamp+" "+data.nonceStr+" "+data.signature);`
1.2确认展示页面config接口注入权限验证配置文件对应字段是否一致
```
wx.config({
               debug: true,
               appId: data.appid,
               **timestamp:data**.**timestamp**,
               **nonceStr:data**.**nonceStr**,
               **signature:data**.**signature**,
               jsApiList: [
                   'checkJsApi',
                   'onMenuShareTimeline',
                   'hideOptionMenu',
               ]
           });
```
1.3确认url是页面完整的url(请在当前页面alert(location.href.split('#')[0])确认),包括'http(s)://'部分,以及'?'后面的参数部分,但不包括'#'hash后面的部分。记住签名用的url必须是调用JS接口页面的完整URL。

1.4确认 config 中的 appid 与用来获取 jsapi_ticket 的 appid 一致。

2.虽然是自定义的分享接口,但是只有当你用微信客户端打开,在最上面右边的 “分享到朋友圈”按钮按的时候效果才会出来。

wx.ready(function(){

    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
});

3.根据自己的需求修改下面的内容,就可实现分享功能
获取“分享到朋友圈”按钮点击状态及自定义分享内容接口

wx.onMenuShareTimeline({
    title: '', // 分享标题
    link: '', // 分享链接
    imgUrl: '', // 分享图标
    success: function () { 
        // 用户确认分享后执行的回调函数
    },
    cancel: function () { 
        // 用户取消分享后执行的回调函数
    }
});

获取“分享给朋友”按钮点击状态及自定义分享内容接口

wx.onMenuShareAppMessage({
    title: '', // 分享标题
    desc: '', // 分享描述
    link: '', // 分享链接
    imgUrl: '', // 分享图标
    type: '', // 分享类型,music、video或link,不填默认为link
    dataUrl: '', // 如果type是music或video,则要提供数据链接,默认为空
    success: function () { 
        // 用户确认分享后执行的回调函数
    },
    cancel: function () { 
        // 用户取消分享后执行的回调函数
    }
});

4.确保一定缓存access_token和jsapi_ticket。由于使用的是微信测试账号所以没有做这方面的优化

以上是全部内容,本人只是实现基本功能,如有问题请指正

 类似资料: