2015 是 Hybrid App 崛起之年 ,Web App 和 Native App 各有其强大之处,也有着致命的缺点,人们一边追求native流畅的用户体验,一边同时指望产品可以快速的迭代更新,Hybrid 成为必然的趋势。html
鹅厂身先士卒,发布了业内震惊一时的 JS-SDK , 这对于基于微信的h5开发者来讲简直是如降甘露,今后开发者们告别了用箭头来提示右上角能够分享,而且随时可使用微信的原生能力,微信变成了一个超级浏览器。前端
1.在微信公众平台申请测试帐号,并设置好好 JS 接口安全域名 (注:域名必须能够外网访问)git
2.查看微信开发者文档 (http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html)github
使用微信 sdk 必须本身实现微信的签名算法。ajax
大概须要4个步骤:算法
1.获取 access_token;json
2.根据 access_token 获取 jsapi_ticketapi
3. 根据 appId(公众号惟一id)、noncestr(随机字符串)、timestamp(时间戳)、url(当前页面完整url,不包括#aaa=bbb) 经过sha1算法签名promise
4.将信息返回给前端 , 设置wx.config。浏览器
因为获取access_token 和 jsapi_ticket 的接口都有访问限制,因此明确指出须要第三方作缓存处理。此处咱们缓存jsapi_ticket 就能够了。
/config/wechat.cfg.js
module.exports = { grant_type: 'client_credential', appid: 'xxxxxxxxxxxxxxx', secret: 'xxxxxxxxxxxxxxxxxxxxxxxxxx', noncestr:'Wm3WZYTPz0wzccnW', accessTokenUrl:'https://api.weixin.qq.com/cgi-bin/token', ticketUrl:'https://api.weixin.qq.com/cgi-bin/ticket/getticket', cache_duration:1000*60*60*24 //缓存时长为24小时 }
最主要部分是签名:
signature.js
var request = require('request'), cache = require('memory-cache'), sha1 = require('sha1'), config = require('../config/wechat.cfg'); exports.sign = function (url,callback) { var noncestr = config.noncestr, timestamp = Math.floor(Date.now()/1000), //精确到秒 jsapi_ticket; if(cache.get('ticket')){ jsapi_ticket = cache.get('ticket'); console.log('1' + 'jsapi_ticket=' + jsapi_ticket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url); callback({ noncestr:noncestr, timestamp:timestamp, url:url, jsapi_ticket:jsapi_ticket, signature:sha1('jsapi_ticket=' + jsapi_ticket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url) }); }else{ request(config.accessTokenUrl + '?grant_type=' + config.grant_type + '&appid=' + config.appid + '&secret=' + config.secret ,function(error, response, body){ if (!error && response.statusCode == 200) { var tokenMap = JSON.parse(body); request(config.ticketUrl + '?access_token=' + tokenMap.access_token + '&type=jsapi', function(error, resp, json){ if (!error && response.statusCode == 200) { var ticketMap = JSON.parse(json); cache.put('ticket',ticketMap.ticket,config.cache_duration); //加入缓存 console.log('jsapi_ticket=' + ticketMap.ticket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url); callback({ noncestr:noncestr, timestamp:timestamp, url:url, jsapi_ticket:ticketMap.ticket, signature:sha1('jsapi_ticket=' + ticketMap.ticket + '&noncestr=' + noncestr + '×tamp=' + timestamp + '&url=' + url) }); } }) } }) } }
因为只是简单的demo , 也就没有采用promise,而是采用的普通的回调。
客户端部分
document.getElementById('refresh').onclick = function(){location.reload();} /** * 如下内容多摘自官方demo * **/ wx.config({ debug: true, // 开启调试模式,调用的全部api的返回值会在客户端alert出来,若要查看传入的参数,能够在pc端打开,参数信息会经过log打出,仅在pc端时才会打印。 appId: appId, // 必填,公众号的惟一标识 timestamp: timestamp, // 必填,生成签名的时间戳 nonceStr: nonceStr, // 必填,生成签名的随机串 signature: signature,// 必填,签名,见附录1 jsApiList: ['checkJsApi', 'onMenuShareTimeline', 'onMenuShareAppMessage', 'onMenuShareQQ', 'onMenuShareWeibo', 'hideMenuItems', 'showMenuItems', 'hideAllNonBaseMenuItem', 'showAllNonBaseMenuItem', 'translateVoice', 'startRecord', 'stopRecord', 'onRecordEnd', 'playVoice', 'pauseVoice', 'stopVoice', 'uploadVoice', 'downloadVoice', 'chooseImage', 'previewImage', 'uploadImage', 'downloadImage', 'getNetworkType', 'openLocation', 'getLocation', 'hideOptionMenu', 'showOptionMenu', 'closeWindow', 'scanQRCode', 'chooseWXPay', 'openProductSpecificView', 'addCard', 'chooseCard', 'openCard'] // 必填,须要使用的JS接口列表, }); wx.ready(function(){ // 1 判断当前版本是否支持指定 JS 接口,支持批量判断 document.querySelector('#checkJsApi').onclick = function () { wx.checkJsApi({ jsApiList: [ 'getNetworkType', 'previewImage' ], success: function (res) { alert(JSON.stringify(res)); } }); }; // 2. 分享接口 // 2.1 监听“分享给朋友”,按钮点击、自定义分享内容及分享结果接口 document.querySelector('#onMenuShareAppMessage').onclick = function () { wx.onMenuShareAppMessage({ title: '互联网之子', desc: '在长大的过程当中,我才慢慢发现,我身边的全部事,别人跟我说的全部事,那些所谓原本如此,注定如此的事,它们其实没有非得如此,事情是能够改变的。更重要的是,有些事既然错了,那就该作出改变。', link: 'http://movie.douban.com/subject/25785114/', imgUrl: 'http://demo.open.weixin.qq.com/jssdk/images/p2166127561.jpg', trigger: function (res) { // 不要尝试在trigger中使用ajax异步请求修改本次分享的内容,由于客户端分享操做是一个同步操做,这时候使用ajax的回包会尚未返回 alert('用户点击发送给朋友'); }, success: function (res) { alert('已分享'); }, cancel: function (res) { alert('已取消'); }, fail: function (res) { alert(JSON.stringify(res)); } }); alert('已注册获取“发送给朋友”状态事件'); }; // 5 图片接口 // 5.1 拍照、本地选图 var images = { localId: [], serverId: [] }; document.querySelector('#chooseImage').onclick = function () { wx.chooseImage({ success: function (res) { images.localId = res.localIds; alert('已选择 ' + res.localIds.length + ' 张图片'); } }); }; // 5.2 图片预览 document.querySelector('#previewImage').onclick = function () { wx.previewImage({ current: 'http://img5.douban.com/view/photo/photo/public/p1353993776.jpg', urls: [ 'http://img3.douban.com/view/photo/photo/public/p2152117150.jpg', 'http://img5.douban.com/view/photo/photo/public/p1353993776.jpg', 'http://img3.douban.com/view/photo/photo/public/p2152134700.jpg' ] }); }; // 7.2 获取当前地理位置 document.querySelector('#getLocation').onclick = function () { wx.getLocation({ success: function (res) { alert(JSON.stringify(res)); }, cancel: function (res) { alert('用户拒绝受权获取地理位置'); } }); }; // 9 微信原生接口 // 9.1.1 扫描二维码并返回结果 document.querySelector('#scanQRCode0').onclick = function () { wx.scanQRCode(); }; }); wx.error(function(res){ JSON.stringify(res) });
至此,基本功能已经完成。附上效果图
1.签名算法不一致: 经过 http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 验证算法正确性
2.url 必须彻底一致,而且外网可访问。 将代码部署到 BAE ,或者其余应用引擎服务器上。
3.timestamp 须要精确到秒。
源码:https://github.com/liaobin312716/wechat-sdk-demo/