微信JSSDK分享--挖坑填坑之小结

  最近参与微信服务号小项目的开发,关于微信分享,我是只知其功能,并没深入了解其中的弯弯道道。虽然项目中不是我负责微信分享这一块(因为我也不太会),但是团队在这个功能上,那可是说多了都是泪,耗费了超级多的时间:一句话就是加班加点的挖坑,制造解决不了的bug,然后加班加点的找问题所在,去解决。主要是我们对于微信分享这块的了解并不深入,没想到的太多。

  当时一直分享不成功,我们前端一直以为是我们的js代码写的有问题,谁知道最大的问题是配置问题:

  一、不再同一个服务号。

  因为微信端,为了识别用户,每个用户针对每个公众号会产生一个安全的OpenID,如果需要在多公众号、移动应用之间做用户共通,则需前往微信开放平台,将这些公众号和应用绑定到一个开放平台账号下,绑定后,一个用户虽然对多个公众号和应用有多个不同的OpenID,但他对所有这些同一开放平台账号下的公众号和应用,只有一个UnionID,可以在用户管理-获取用户基本信息(UnionID机制)文档了解详情。

  二、分享的链接有&符,我们没有做处理

  三、JS接口安全域名设置,没有设置白名单。

  今天团队的大神,特别针对微信分享这个功能,对于其中会遇到的问题进行了总结和讲解,我这才对微信分享,有了更深入的认识和了解。记性不好,听完怕忘,得来个听后记录啊。

  虽然微信提供了JSSDK,但是这不意味着你可以用自定义的按钮来直接打开微信的分享界面,这套JSSDK只是把微信分享接口的内容定义好了,实际还是需要用户点击右上角的菜单按钮进行主动的分享,用户点开分享界面之后,出现的内容就会是你定义的分享标题、图片和链接

  JSSDK使用步骤:

  1.步骤一:绑定域名

  2.步骤二:引入js

  

  3.步骤三:通过config接口注入权限验证配置

  

  4.步骤四:通过ready接口处理成功验证

  

  5. 步骤五:通过error接口处理失败问题  // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。

  

  写到这里,其实已经跟前端没多大事了,剩下的就是关于公众号的配置。但是当时我们前端还一直以为是自己js的错误。。(js详见最后)

  配置大纲:

  

 

  详细步骤:  

  1.设置JS接口安全域名。

  这里填写的是一级域名,不带www和http。最多可以设置三个域名。设置完后点击确定。(多说一句,相比以前的分享没有任何域名限制,这里设置安全域名,目的是为了当发现此公众平台发现诱导分享行为时,可以根据此域名追溯到所有分享出去的链接,以及通过这些链接增加的粉丝。这样,微信就可以牢牢控制了你的微信平台,一旦发现违规,让分享链接失效,删除掉诱导行为增加的粉丝,是瞬间就可以完成的。因此,微信平台的开发者,一定要合理来使用分享功能,不要因小失大。等到你的微信平台被封,估计哭都来不及)

  

  2.在开发者中心中获取你的AppID和AppSecret,接下来在获取令牌时,需要这两个信息。

  

  3.获取令牌

 

unction wx_get_token() {
    $token = S('access_token');
    if (!$token) {
        $res = file_get_contents('https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='            .'你的AppID'.'&secret='            .'你的AppSecret');
        $res = json_decode($res, true);
        $token = $res['access_token'];
        // 注意:这里需要将获取到的token缓存起来(或写到数据库中)
        // 不能频繁的访问https://api.weixin.qq.com/cgi-bin/token,每日有次数限制
        // 通过此接口返回的token的有效期目前为2小时。令牌失效后,JS-SDK也就不能用了。
        // 因此,这里将token值缓存1小时,比2小时小。缓存失效后,再从接口获取新的token,这样
        // 就可以避免token失效。
        // S()是ThinkPhp的缓存函数,如果使用的是不ThinkPhp框架,可以使用你的缓存函数,或使用数据库来保存。
        S('access_token', $token, 3600);
    }
    return $token;
}
注意:返回的access_token长度至少要留够512字节。接口返回值:
{"access_token":"ACCESS_TOKEN","expires_in":7200}
{"access_token":"vdlThyTfyB0N5eMoi3n_aMFMKPuwkE0MgyGf_0h0fpzL8p_hsdUX8VGxz5oSXuq5dM69lxP9wBwN9Yzg-0kVHY33BykRC0YXZZZ-WdxEic4","expires_in":7200}

  4.获取jsapi的ticket。jsapi_ticket是公众号用于调用微信JS接口的临时票据。正常情况下,jsapi_ticket的有效期为7200秒,通过access_token来获取。

function wx_get_jsapi_ticket(){
    $ticket = "";
    do{
        $ticket = S('wx_ticket');
        if (!empty($ticket)) {
            break;
        }
        $token = S('access_token');
        if (empty($token)){
            wx_get_token();
        }
        $token = S('access_token');
        if (empty($token)) {
            logErr("get access token error.");
            break;
        }
        $url2 = sprintf("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi",
            $token);
        $res = file_get_contents($url2);
        $res = json_decode($res, true);
        $ticket = $res['ticket'];
        // 注意:这里需要将获取到的ticket缓存起来(或写到数据库中)
        // ticket和token一样,不能频繁的访问接口来获取,在每次获取后,我们把它保存起来。
        S('wx_ticket', $ticket, 3600);
    }while(0);
    return $ticket;
}
接口返回值:
{"errcode":0,"errmsg":"ok","ticket":"sM4AOVdWfPE4DxkXGEs8VMKv7FMCPm-I98-klC6SO3Q3AwzxqljYWtzTCxIH9hDOXZCo9cgfHI6kwbe_YWtOQg","expires_in":7200}

  5.签名,将jsapi_ticket、noncestr、timestamp、分享的url按字母顺序连接起来,进行sha1签名。    noncestr是你设置的任意字符串。     timestamp为时间戳。

$timestamp = time();
$wxnonceStr = "任意字符串";
$wxticket = wx_get_jsapi_ticket();
$wxOri = sprintf("jsapi_ticket=%s&noncestr=%s&timestamp=%s&url=%s",
$wxticket, $wxnonceStr, $timestamp,
       '要分享的url(从http开始,如果有参数,包含参数)'
);
$wxSha1 = sha1($wxOri);

  

  js代码:

var shareData = {
    shareTitle:"",
    shareContent:"",
    shareUrl:location.href,
    imgUrl:"",
    success:function(){
        alert('分享成功!');
    }
};
function wxConfig () {
    $.ajax({
     // 此处的location.href必须做处理,一个大坑,因为如果url中有&这个特殊符号,微信端分享就不会成功。
url: "http://***?url=" + encodeURIComponent(location.href), method: 'get', success: function (data) { var wxdataObj = {}; if(typeof data == "string" && data.indexOf("{")!=-1){ wxdataObj = JSON.parse(data); }else{ wxdataObj = data; } wx.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: wxdataObj.AppId||wxdataObj.appId, // 必填,公众号的唯一标识 timestamp: wxdataObj.Timestamp||wxdataObj.timestamp, // 必填,生成签名的时间戳 nonceStr: wxdataObj.NonceStr||wxdataObj.nonceStr, // 必填,生成签名的随机串 signature: wxdataObj.Signature||wxdataObj.signature, // 必填,签名,见附录1 jsApiList: ['chooseImage', 'uploadImage','onMenuShareTimeline', 'onMenuShareAppMessage',"hideAllNonBaseMenuItem","showAllNonBaseMenuItem"], // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.error(function (res) { //console.log('res', res); }); }, error: function (data) { //console.log('error', data); } }); wx.ready(function () { wx.onMenuShareTimeline({ title: shareData.shareTitle, // 分享标题 link: shareData.shareUrl, // 分享链接 imgUrl: shareData.shareIcon, // 分享图标 success: shareData.success// 用户确认分享后执行的回调函数 }); wx.onMenuShareAppMessage({ title: shareData.shareTitle, // 分享标题 desc: shareData.shareContent, // 分享描述 link: shareData.shareUrl, // 分享链接 imgUrl: shareData.shareIcon, // 分享图标 success: shareData.success// 用户确认分享后执行的回调函数 });
     // 此处是微信禁用 if(location.href.indexOf("tinysite.html")==(-1)){ wx.hideAllNonBaseMenuItem(); } }); }; function isWeiXin(){ var ua = navigator.userAgent.toLowerCase(); if(ua.match(/MicroMessenger/i)=="micromessenger") { return true; } else { return false; } }//判断是否在微信打开 //若果是微信就拉取微信权限 if(isWeiXin()){ wxConfig (); } //从url里取值var urlData = getUrlData(["userId","fromSource"]); //使用 urlData.userId,urlData.fromSource function getUrlData (arr){ var dataArr = {}; for(var i = 0; i < arr.length; i++){ var urlList = decodeURIComponent(location.href).split("&"); for(var j = 0; j < urlList.length; j++){ if(urlList[j].indexOf(arr[i]+"=") != (-1)){ var data = urlList[j].slice(urlList[j].indexOf(arr[i]+"=")+arr[i].length+1); dataArr[arr[i]] = data; } } } return dataArr; }

  如果是多个页面都分享自定义的标题和描述:

var share = {
            title: document.title,
            discription: document.discription,
            imgurl: "",
            url: location.href,
            success: function () {
                alert('分享成功!');
            }
        };
        if (data) {
            for (v in data) {
                share[v] = data[v] || share[v];
            }
        }   

  

  

posted @ 2017-09-06 20:29  wangxiaoyingBlog  阅读(9385)  评论(0编辑  收藏  举报