关于JS-SDK
微信JS-SDK是微信公众平台 面向网页开发者提供的基于微信内的网页开发工具包。
通过使用微信JS-SDK,网页开发者可借助微信高效地使用拍照、选图、语音、位置等手机系统的能力,同时可以直接使用微信分享、扫一扫、卡券、支付等微信特有的能力,为微信用户提供更优质的网页体验。
关于小程序使用JS-SDK
小程序的web-view相关的API调用参考地址:web-view | 微信开放文档
JS-SDK主要是给微信公众号使用的,在小程序的web-view中嵌套的html5页面可以通过调用JS-SDK,从而实现了调用微信端几个指定的相关API功能,比如拍照、上传图片、扫一扫等。以下介绍如何调用扫一扫功能。
一、引用并加载微信JS-SDK库
调用所有微信API接口前,必须先引用JS-SDK库。
以下有两种方法引用JS-SDK库,推荐方法2.
方法1.通过script引用JS文件,此方法也是微信官方文档的示例方法
在需要调用JS接口的页面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.6.0.js
如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.6.0.js (支持https)。
方法2.通过webpack引入
安装
npm install weixin-js-sdk -S
使用:在main.js文件中,使用import引用并命名为wx,再将wx设置到vue.prototype属性中。这样全局都可以通过this.$wx.***的方式使用js-sdk的API了。
import wx from "weixin-js-sdk";
Vue.prototype.$wx = wx
二、demo页面调用扫一扫函数前的初始化工作
以下为demo页面,在mounted中调用后端JAVA接口获取初始化微信config接口需要的appId和ticket(JAVA代码参见后文)。
在methods中定义的初始化方法wechatApiInit,主要是实现通过config接口注入权限验证配置。并按微信官方文档的要求,注入config前做了签名算法。scan方法就是页面点击“扫一扫”按钮的触发事件。
mounted:
mounted: function () {
//申请微信jsadk接口 扫一扫
var jsApiList = ["scanQRCode"];
//访问后端JAVA接口:获取appId
getAppKey({
params: ""
}).then((res)=>{
this.appId=res.entity.appId;
})
//访问后端JAVA接口:获取微信JS-SDK的ticket
loadTicket({
params: "",
}).then((res) => {
console.log("RES>>", res);
if (res.entity.ticket) {
//将ticket传入 进行JS-SDK调用的初始化
this.wechatApiInit({ ticket: res.entity.ticket, jsApiList });
} else {
console.log("loadTicket获取失败");
}
});
},
methods:
//微信api 初始化
wechatApiInit(jsonResult) {
console.log("jsonResult>>>", jsonResult);
if (!this.$wxapi.is_weixin()) {
console.log("当前环境不是微信.")
return;
}
//字符合并
var raw = function (args) {
var keys = Object.keys(args);
keys = keys.sort();
var newArgs = {};
keys.forEach(function (key) {
newArgs[key.toLowerCase()] = args[key];
});
var string = "";
for (var k in newArgs) {
string += "&" + k + "=" + newArgs[k];
}
string = string.substr(1);
return string;
};
var vurl= location.href;
//console.log("location.href:"+vurl);
vurl=location.href.split('#')[0];
//console.log("vurl:"+vurl);
//数据包
var ret = {
jsapi_ticket: jsonResult.ticket,
nonceStr: Math.random().toString(36).substr(2, 15),
timestamp: parseInt(new Date().getTime() / 1000) + "",
url: vurl
};
//console.log("RET:", ret);
let string1= raw(ret);
//console.log("string1:"+string1);
let ticket=hex_sha1(string1);
//console.log("ticket",ticket);
//console.log("jsonResult.jsApiList",jsonResult.jsApiList);
//console.log("appId:",this.appId);
//通过config接口注入权限验证配置
this.$wx.config({
debug: false,//调试时设置为true
appId: this.appId,
timestamp: ret.timestamp,
nonceStr: ret.nonceStr,
signature: ticket,
jsApiList: jsonResult.jsApiList
});
},
//扫一扫 按钮触发事件
scan() {
var that=this;
this.$wx.miniProgram.getEnv(function (res) {
console.log(res.miniprogram); // true
if (res.miniprogram) {
console.log("小程序scan.");
that.$wx.scanQRCode({
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
success: function (res) {
var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
//alert(result);
that.getDeviceCode(result);//将扫码结果传到自定义的方法去执行
},
});
} else {
console.log("app scan.");
}
});
}
调试时,请将config中的debug设置为true,如果有异常,可以看到调试异常的信息。注意scan方法中this和that的使用。
三、JAVA后端接口代码
说明:JAVA后端接口主要实现了获取appId,获取ticket值(自动验证超时)。
部分方法为自定义的公用方法类(比如读取xml配置项,发送http请求等),这里就不一一给出了,可以用自己的方法替代实现。这里主要是给出实现的主要步骤。
// 微信JS接口的临时票据
public ResultMsg loadTicket(@RequestBody HashMap<String, Object> map) {
String estr = "微信JS接口的临时票据(loadTicket):";
ResultMsg rMsg = new ResultMsg();
logger.debug(estr + "loadTicket ok.");
try {
String vUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token="
+ isExistAccess_Token() + "&type=jsapi";
logger.debug("vurl:" + vUrl);
String msg = Comm.httpGet(vUrl);
logger.debug(msg);
rMsg.setEntity(Comm.toHashMap(msg));
rMsg.setSuccess();
return rMsg;
} catch (Exception e) {
logger.error(estr + e.toString());
return null;
}
}
// 微信appID
public ResultMsg getAppKey(@RequestBody HashMap<String, Object> map) {
String estr = "微信appID和appSecret:";
ResultMsg resultMsg = new ResultMsg();
try {
HashMap<String, Object> rmap = new HashMap<String, Object>();
rmap.put("appId", getAppId());
//rmap.put("appsecret", getAppSecret());
resultMsg.setEntity(JSONObject.fromObject(rmap));
resultMsg.setSuccess();
logger.info(resultMsg.toString());
return resultMsg;
} catch (Exception e) {
logger.error(estr + e.toString());
return resultMsg;
}
}
// 获取access_token值
public String isExistAccess_Token() {
try {
String path = this.getClass().getClassLoader().getResource("config/token.xml").getPath();
String token = Comm.xmlRead(path, "access_token");// tonken值
String YouXRQ = Comm.xmlRead(path, "expires_in");// 有效日期
SimpleDateFormat sf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date dt = sf.parse(YouXRQ);
Date dtnow = new Date();
logger.debug(" 当前时间>>" + dtnow.getTime() + "|| 记录时间>>" + dt.getTime());
if (dtnow.getTime() > dt.getTime()) {
String msg = getAccessToKen();
HashMap<String, Object> map = Comm.toHashMap(msg);
token = map.get("access_token").toString(); // logger.info(path);
Comm.xmlWrite(path, "access_token", token);// 保存最新token
String expires_in = map.get("expires_in").toString();// 失效时长(秒)
Integer expires = Integer.valueOf(expires_in);
Calendar cal = Calendar.getInstance();
cal.setTime(dtnow);
cal.add(Calendar.SECOND, expires);// 保存过期时间
Comm.xmlWrite(path, "expires_in", sf.format(cal.getTime()));
logger.info("新token时效." + sf.format(cal.getTime()));
return token;
} else {
logger.info("获取原token值:" + token);
return token;
}
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
// 刷新微信token(仅供内部获取token值调用)
private String getAccessToKen() {
String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" + "&appid="
+ getAppId() + "&secret=" + getAppSecret();
String msg = "";
try {
msg = Comm.httpGet(tokenUrl);
logger.info("刷新微信token:" + msg);
return msg;
} catch (Exception e) {
logger.error(e.toString());
return msg;
}
}
四、需要避免踩到的坑
开发小程序调用JS-SDK时,使用的appId、AppSecret都必须是微信公众号而不是小程序的,同样也必须在微信公众号的业务域名中添加小程序的url调用地址,切记!!
还有,需要在公众号绑定小程序。
否则会出现“40048,invalid url domain”不合法的url域名。业务域名设置时不能带http://的协议头,设置示例为: aaa.com