微信小程序:web-view中调用JS-SDK实现扫码

关于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

猜你喜欢

转载自blog.csdn.net/quan278905570/article/details/121198495