精华内容
下载资源
问答
  • 前端对二维码图片识别 判断选中的图片是否为二维码 新增新版微信二维码识别解析
  • 请问各位前辈,微信的wx.scanQRCode这个接口是不是只能用于扫一扫识别呢? 如果是只能用于扫一扫,那么有没有...在此之前我有用qrcode.js识别二维码以及用后来识别二维码都写过了,但是部分二维码识别不了,怎么办呢。
  • 在开发一个含有二维码微信页面时,我遇到了这样一个问题:使用iPhone第一次进入该页面时,二维码可以长按识别,但第二次进入时长按无法识别二维码。安卓机都能识别。 二、我和同事进行了以下尝试: 移除控制...
        

    一、问题概述

    在开发一个含有二维码的微信页面时,我遇到了这样一个问题:使用iPhone第一次进入该页面时,二维码可以长按识别,但第二次进入时长按无法识别到二维码。安卓机都能识别。

    二、我和同事进行了以下尝试:

    1. 移除控制进入条件的脚本,即部分第一次第二次,长按不能识别二维码。暂时排除脚本原因。

    2. 移除二维码所有样式,发现并不是不能识别到二维码而是识别区域发生了偏移。(图1)

    3. 移除所有元素,页面上只留一张二维码,发现识别区域变大。虽然整张图都被识别了但图片外面的区域也会被识别。(图2)

    识别区域发生偏移
    图1
    识别区域覆盖变大
    图2
    阶段性结论:二维码能被长按识别,但因为某种原因识别区域发生了偏移。

    三、进一步尝试:

    在网上简单搜索了偏移问题后,我注意到一条关于<meta>标签的,大意如下:

    meta标签定义了默认缩放为一倍就能识别,不定义就不能识别。于是我将原来的

    <meta name="viewport" content="target-densitydpi=device-dpi, user-scalable=no">
    

    改成了

    <meta name="viewport" content="user-scalable=no,width=device-width,initial-scale=1,maximum-scale=1">
    

    虽然样式飞了但二维码识别正常了。
    看来问题就出在这里了。经过尝试,我发现:
    target-densitydpi=device-dpi和width=device-width是冲突的。加上后者二维码识别正常了,但样式肯定要重新定义,若不加,样式好使,但二维码识别就不正常了。定义样式是小事,但归根结底,发生偏移的原因到底在哪呢?

    四、分析

    • 关于适配屏幕的<meta name="viewport">标签

    UI设计人员都知道因为pc和移动设备屏幕密度像素的不同在输出视觉稿的时候要标明空间的倍数大小,所谓的@1x、@2x就是这个原因。然后在页面head里写这样一个<meta>标签:

    <meta name="viewport" content="user-scalable=no,width=device-width,initial-scale=1,maximum-scale=1">

    即:宽度强制转换成设备宽度,默认缩放比例为1,最大缩放比例1,不允许手动缩放。
    比如按照iPhone6出的设计稿,在开发的时候空间尺寸就要除以2,iPhone6 plus出的设计稿,尺寸就除以3。具体原理请看图3
    但是如果不想进行单位换算,可以用

    <meta name="viewport" content="target-densitydpi=device-dpi, user-scalable=no">

    即:分辨率转为设备分辨率……(后边都一样)
    强制将搭建好的页面适应移动设备的分辨率。原理就好比是将大尺寸的图片缩小显示并不影响清晰度。
    这样给设计和前端开发人员都带来很大的方便。既不用设计出标注,也不用切两套控件出来了。

    • 由此产生的问题和猜测

    问题就是元素偏移了。。。但我猜测应该是这样的:
    可视的页面呗强制“塞”到手机屏幕里,但页面本身仍然是原始大小的(图4)。这样看来,并不是触控区域偏移了而是,可视区域被我们“塞到”了移动设备里。发生偏移的实际上是我们看到的那部分。

    适配流程
    图3

    实际上是可视区域偏移了
    图4

    五、问题的解决

    找到了这个原因,剩下的就是老老实实的,按照实际尺寸修改css了,将所有定义了固定尺寸的元素的宽高,包括字体都除以2,保留所有百分比定义的尺寸。哪里不对改哪里,工作量着实不小。这样搭建出来的页面就是实际大小的,没有经过任何缩放,图片该在哪就是在哪不会有偏移了。

    六、不能解释的问题

    1. 为什么该问题只有iPhone存在,或许是因为识别二维码的机制不同,也可能是因为浏览器内核原因,安卓的浏览器比较健壮。

    2. 为什么第一次进入页面的时候没有发生偏移?

    欢迎,感谢有类似经历的同行,老师参与讨论,留下您的宝贵经验。

    展开全文
  • 用户点击商品 》 选择支付方式 》 微信人脸支付或微信、支付宝二维码支付。但不是我们的后端来和我合作,我需要自己去微信官方拿rawdata和AuthInfo(需要注意的是微信的接口请求都是XML请求) 微信人脸支付 1....

    前言:公司需要做一个人脸识别项目。用户点击商品 》 选择支付方式 》 微信人脸支付或微信、支付宝二维码支付。但不是我们的后端来和我合作,我需要自己去微信官方拿rawdata和AuthInfo(需要注意的是微信的接口请求都是XML请求

     

    微信人脸支付

    1.选择设备。微信人脸需要选择微信官方提供的设备

    微信人脸设备展示

    2.商户APP Demo。仔细查看demo中的人脸支付流程。(demo中的流程同样是不需要有后端的,需要的参数都需要自己去微信要)

    商户APP Demo(查看的是商户APP Demo)

    微信刷脸支付文档 # 刷脸支付场景说明

    3.把wxfacepay-release加到libs中。

    4.Application中微信人脸SDK初始化

        private fun initWxpayface() {
            val m1: Map<String?, String?> = HashMap()
    //      m1.put("ip", "192.168.1.1"); //若没有代理,则不需要此行
    //      m1.put("port", "8888");//若没有代理,则不需要此行
    //      m1.put("user", mEtnUser.getText().toString());//若没有代理,则不需要此行
    //      m1.put("passwd", mEtnPassword.getText().toString());//若没有代理,则不需要此行
    //      m1.put("proxy_type", 1 ); //若没有代理,则不需要此行
    //      m1.put("perform_mode", "LOW_PERFORM");//低性能表现,默认关闭美颜等
            WxPayFace.getInstance().initWxpayface(this, m1, object : IWxPayfaceCallback() {
                @Throws(RemoteException::class)
                override fun response(info: Map<*, *>?) {
                    if (info == null) {
                        e("调用返回为空, 请查看日志")
                        RuntimeException("调用返回为空").printStackTrace()
                        return
                    }
                    val code = info["return_code"] as String?
                    val msg = info["return_msg"] as String?
                    e("初始化完成")
                }
            })
        }

    5.获取rawdata。getWxpayfaceRawdata

            /**
             *	获取rawdata
             */
            WxPayFace.getInstance().getWxpayfaceRawdata(object : IWxPayfaceCallback() {
    
                override fun response(info: Map<*, *>?) {
                    if (info == null) {
                        e("调用返回为空, 请查看日志")
                        java.lang.RuntimeException("调用返回为空").printStackTrace()
                        return
                    }
                    val code = info["return_code"] as String?
                    val msg = info["return_msg"] as String?
                    val rawData = info["rawdata"] as String?
                    e(rawData)
                    getAuthInfo(rawData)
                }
            })

    6.获取AuthInfo。https://payapp.weixin.qq.com/face/get_wxpayface_authinfo

       private fun getAuthInfo(rawData: String?) {
            var map = mutableMapOf<String, String>()
            map["rawdata"] = rawData!!
            //门店编号
            map["store_id"] = Constance.store_id
            //门店名称
            map["store_name"] = Constance.store_name
            //终端设备编号,由商户定义。
            map["device_id"] = Constance.device_id
            //商户号绑定的公众号/小程序 appid
            map["appid"] = orderInfoBean!!.data.wxappid
            //	商户号
            map["mch_id"] = orderInfoBean!!.data.wxmchid
            //版本号:固定是1
            map["version"] = "1"
            var now = (System.currentTimeMillis() / 1000).toString()
            map["now"] = now
            map["sign_type"] = "MD5"
            map["nonce_str"] = Constance.nonce_str
    
            //按字典顺序排序
            val infoIds: List<Map.Entry<String, String>> =
                ArrayList(map.entries)
            Collections.sort(infoIds, { o1, o2 -> o1.key.compareTo(o2.key) })
            //使用&符号进行拼接
            val sbR: String =
                Tools.getStringBuffer(infoIds).toString() + "&key=" + orderInfoBean!!.data.wxmchkey
            //进行MD5加密之后  转大写
            val sign: String = Tools.encode(sbR).toUpperCase()
            map["sign"] = sign
    
    
            /*将map集合转为xml*/
            val toXml = Tools.mapToXml(map)
    //        e("认证参数XMl$toXml")
            val body = RequestBody.create(null, toXml)
    
            e(toXml.toString())
    
            OkGo.post<String>(UrlUtils.WECHAT)
                .tag(UrlUtils.WECHAT)
                .upRequestBody(body)
                .execute(object : StringCallback() {
                    override fun onError(response: com.lzy.okgo.model.Response<String?>?) {
                        e("获取到的微信支付凭证${response!!.body()}")
                    }
    
                    override fun onSuccess(response: com.lzy.okgo.model.Response<String?>?) {
                        val payVoucher = response!!.body()!!
                        val headers = response.headers()!!
    
                        try {
                            var code = Tools.parseGetAuthInfoXML(payVoucher, "return_code")
                            if ("SUCCESS" == code) {
                                val authinfo: String = Tools.parseGetAuthInfoXML(payVoucher, "authinfo")
                                pay(authinfo)
                            } else {
                                val msg: String = Tools.parseGetAuthInfoXML(payVoucher, "return_msg")
                                e("获取微信凭证失败$msg")
                            }
                        } catch (e: Exception) {
                            e.printStackTrace()
                            e("获取微信凭证失败$e")
                        }
                    }
                })
        }

    7.调起微信人脸识别。进行人脸识别getWxpayfaceCode(获取用户信息facecode)

        private fun pay(mAuthInfo: String?) {
            e("pay", "onClick | pay ")
    
            var params: HashMap<String, String> = HashMap()
    
            //FACEPAY: 人脸凭证,常用于人脸支付
            params["face_authtype"] = "FACEPAY"
    
            //商户号绑定的公众号/小程序 appid
            params["appid"] = orderInfoBean!!.data.wxappid
            //	商户号
            params["mch_id"] = orderInfoBean!!.data.wxmchid
            //门店编号
            params["store_id"] = Constance.store_id
            //目标face_code类型,可选值:"1",刷卡付款码:18位数字,通过「付款码支付/被扫支付」接口完成支付。如果不填写则默认为"0"
            params["face_code_type"] = "1"
            //支付成功页是否需要展示人脸识别授权项。 展示:1 不展示:0
            params["ask_face_permit"] = "0"
            //商户端是否对SDK返回支付结果,可选值:"0",返回支付结果,商户需在确认?付结果后调?[updateWxpayfacePayResult]通知SDK;"1"
            params["ignore_update_pay_result"] = "1"
            //	指定刷脸界面的运行屏幕,可选值:“0”, 运行在默认屏幕; "1", 运行在第二屏幕(副屏); "2", 自动选择屏幕; "3", 强制用presentation方式在第二屏幕(副屏)启动。
            params["screen_index"] = "0"
            //商户订单号,须与调用支付接口时字段一致
            params["out_trade_no"] = orderInfoBean!!.data.order_number
            //订单金额(数字)
            params["total_fee"] = allPrice.times(100).toInt().toString()
            params["authinfo"] = mAuthInfo.toString()
    
    
            e("pay | single callback")
            WxPayFace.getInstance().getWxpayfaceCode(params, object : IWxPayfaceCallback() {
                @Throws(RemoteException::class)
                override fun response(info: Map<*, *>?) {
                    if (info != null) {
                        e(info.toString())
                        getWxfaceCode(info)
                    } else
                        e("调用返回为空, 请查看日志")
                }
            }, object : IWxPayfaceCallback() {
                override fun response(info: MutableMap<Any?, Any?>?) {
                    e(info.toString())
                    if (info == null) {
                        RuntimeException("调用返回为空").printStackTrace()
                        return
                    }
                    val code = info["return_code"] as String // 错误码
                    val msg = info["return_msg"] as String // 错误码描述
    
                    if (code == null || code != "SUCCESS") {
                        RuntimeException("调用返回非成功信息,return_msg:$msg   ")
                            .printStackTrace()
                        return
                    }
                }
            })
        }
    
        private fun getWxfaceCode(info: Map<*, *>) {
            val code = info["return_code"] as String?
            val facecode = info["face_code"] as String?
            when {
                //用户确认支付
                TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_SUCCESS) ->
                    doPay(facecode)
    
                TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_USER_CANCEL) ->
                    e("用户取消")
    
                TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_SCAN_PAYMENT) ->
                    e("扫码支付")
    
                TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_ERROR) ->
                    e("发生错误")
    
                TextUtils.equals(code, WxfacePayCommonCode.VAL_RSP_PARAMS_USER_QUERY_CANCEL) ->
                    e("请与商户确认支付结果")
            }
        }

    8.进行发起订单支付micropay。接口地址:https://api.mch.weixin.qq.com/pay/micropay

        private fun doPay(facecode: String?) {
            var map = mutableMapOf<String, String>()
    
            map["auth_code"] = facecode.toString()
            map["spbill_create_ip"] = "192.168.0.143"
            map["body"] = "捷视商品"
            map["attach"] = "订单额外描述"
            map["device_info"] = Constance.device_id
            map["sign_type"] = "MD5"
            map["total_fee"] = allPrice.times(100).toInt().toString()
    
            map["out_trade_no"] = orderInfoBean!!.data.order_number
    
            //商户号绑定的公众号/小程序 appid
            map["appid"] = orderInfoBean!!.data.wxappid
            //	商户号
            map["mch_id"] = orderInfoBean!!.data.wxmchid
    
            var now = (System.currentTimeMillis() / 1000).toString()
            map["time_start"] = now
    
            map["nonce_str"] = Constance.nonce_str
    
    
            //按字典顺序排序
            val infoIds: List<Map.Entry<String, String>> = ArrayList(map.entries)
            Collections.sort(infoIds) { o1, o2 -> o1.key.compareTo(o2.key) }
            //使用&符号进行拼接商户Key
            val sbR: String =
                Tools.getStringBuffer(infoIds).toString() + "&key=" + orderInfoBean!!.data.wxmchkey
            //进行MD5加密之后  转大写
            val sign: String = Tools.encode(sbR).toUpperCase()
            map["sign"] = sign
    
            e(map.toString())
    
    
            /*将map集合转为xml*/
            val toXml = Tools.mapToXml(map)
    //        e("认证参数XMl$toXml")
            val body = RequestBody.create(null, toXml)
    
            OkGo.post<String>("https://com.api.mch.weixin.qq.com/pay/micropay")
                .tag(this)
                .upRequestBody(body)
                .execute(object : StringCallback() {
                    override fun onError(response: com.lzy.okgo.model.Response<String?>?) {
                        e("获取微信支付${response!!.body()}")
                    }
    
                    override fun onSuccess(response: com.lzy.okgo.model.Response<String?>?) {
                        val payVoucher = response!!.body()!!
                        val headers = response.headers()!!
                        e("微信支付${payVoucher}")
    
                        try {
                            var code = Tools.parseGetAuthInfoXML(payVoucher, "return_code")
                            var resultCode = Tools.parseGetAuthInfoXML(payVoucher, "result_code")
                            var msg = Tools.parseGetAuthInfoXML(payVoucher, "return_msg")
                            if ("SUCCESS" == code) {
                                if ("SUCCESS" == resultCode) {
                                    //支付成功,返回,告诉后端我们支付成功了,把支付成功参数给后台
                                    returServerCode(payVoucher)
                                } else {
                                    queryPay()
                                }
                            } else {
                                e("微信支付失败$msg")
                            }
                        } catch (e: Exception) {
                            e.printStackTrace()
                            e("微信支付失败$e")
                        }
                    }
                })
        }

    9.因为微信的人脸支付没有“notify_url”参数,所以需要我们主动去给后台消息说我们支付成功了。有时候微信给我们的订单支付成功消息不是SUCCESS,而是SYSTEMERROR(系统超时)(我有时候遇到了这种情况,用户明明付款成功了,但是返回的不是SUCCESS),所以我们要主动去查询订单一次

    查询订单状态orderquery。接口地址:https://api.mch.weixin.qq.com/pay/orderquery

        private fun returServerCode(payVoucher: String) {
            //微信支付订单号
            var transactionid = Tools.parseGetAuthInfoXML(payVoucher, "transaction_id")
            var openid = Tools.parseGetAuthInfoXML(payVoucher, "openid")
            var totalfee = Tools.parseGetAuthInfoXML(payVoucher, "total_fee")
    
            var map = mutableMapOf<String, String>()
            map["api_name"] = "wxFaceNotify"
            map["shop_id"] = orderInfoBean!!.data.shop_id
            map["order_id"] = orderInfoBean!!.data.order_id
            map["order_number"] = orderInfoBean!!.data.order_number
            map["transaction_id"] = transactionid
            map["openid"] = openid
            map["total_fee"] = (totalfee.toDouble() / 100).toString()
    
            e(map.toString())
    
            OkGo.post<String>(UrlUtils.SHOPLIST)
                .tag(this)
                .params(map)
                .execute(object : StringCallback() {
                    override fun onError(response: com.lzy.okgo.model.Response<String?>?) {
                        ToastUtil.showTextToast("网络连接失败请重试!!")
                    }
    
                    override fun onSuccess(response: com.lzy.okgo.model.Response<String?>?) {
                        e(response!!.body()!!)
                    }
                })
        }

    微信二维码(NATIVE支付)

    获取微信二维码要开启NATIVE支付,我们要去统一下单中获取二维码

    微信统一下单API

    URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

       private fun showWeChatCodePay(payType: Int) {
            var map = mutableMapOf<String, String>()
    
            //商户号绑定的公众号/小程序 appid
            map["appid"] = orderInfoBean!!.data.wxappid
            //	商户号
            map["mch_id"] = orderInfoBean!!.data.wxmchid
            //	商户号
            map["device_info"] = MyApplication.IMEI.toString()
            //	商户系统内部订单号
            map["out_trade_no"] = orderInfoBean!!.data.order_number
            //	商户系统内部ID
            map["product_id"] = orderInfoBean!!.data.order_id
            //随机字符串
            map["nonce_str"] = Constance.nonce_str
            //商品描述
            map["body"] = "捷视商品"
            //订单金额(数字)
            map["total_fee"] = allPrice.times(100).toInt().toString()
            //终端IP
            map["spbill_create_ip"] = "192.168.0.143"
            //通知地址
            map["notify_url"] = "http://www.jieshishop.com/Wxsite/Wxpay/wxf2fNotify"
            //交易类型
            map["trade_type"] = "NATIVE"
    
            //按字典顺序排序
            val infoIds: List<Map.Entry<String, String>> =
                ArrayList(map.entries)
            Collections.sort(infoIds) { o1, o2 -> o1.key.compareTo(o2.key) }
            //使用&符号进行频率
            val sbR: String =
                Tools.getStringBuffer(infoIds).toString() + "&key=" + orderInfoBean!!.data.wxmchkey
            //进行MD5加密之后  转大写
            val sign: String = Tools.encode(sbR).toUpperCase()
            map["sign"] = sign
    
            e(map.toString())
    
            /*将map集合转为xml*/
            val toXml = Tools.mapToXml(map)
            //        e("认证参数XMl$toXml")
            val body = RequestBody.create(null, toXml)
    
            e(toXml.toString())
    
            OkGo.post<String>("https://api.mch.weixin.qq.com/pay/unifiedorder")
                .tag(this)
                .upRequestBody(body)
                .execute(object : StringCallback() {
                    override fun onError(response: com.lzy.okgo.model.Response<String?>?) {
                        e("微信二维码支付失败${response!!.body()}")
                    }
    
                    override fun onSuccess(response: com.lzy.okgo.model.Response<String?>?) {
                        val payVoucher = response!!.body()
                        try {
                            var msg = Tools.parseGetAuthInfoXML(payVoucher, "return_msg")
                            var code = Tools.parseGetAuthInfoXML(payVoucher, "return_code")
                            var resultCode = Tools.parseGetAuthInfoXML(payVoucher, "result_code")
                            var codeUrl = Tools.parseGetAuthInfoXML(payVoucher, "code_url")
    
                            if ("SUCCESS" == code) {
                                if ("SUCCESS" == resultCode) {
                                    //支付成功
                                    dialog = PayCodeDialog(mContext, payType, codeUrl)
                                    dialog!!.show()
                                }
                            } else {
                                ToastUtil.showTextToast("微信二维码支付失败:$msg")
                            }
                        } catch (e: Exception) {
                            e.printStackTrace()
                            ToastUtil.showTextToast("微信二维码支付失败:$e")
                        }
                    }
                })
        }

    Tools 工具类:

    public class Tools {
    
        /**
         *      * 将Map转换为XML格式的字符串
         *      *
         *      * @param data Map类型数据
         *      * @return XML格式的字符串
         *      * @throws Exception
         *      
         */
        public static String mapToXml(Map<String, String> data) throws Exception {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            org.w3c.dom.Document document = documentBuilder.newDocument();
            org.w3c.dom.Element root = document.createElement("xml");
            document.appendChild(root);
            for (String key : data.keySet()) {
                String value = data.get(key);
                if (value == null) {
                    value = "";
                }
                value = value.trim();
                org.w3c.dom.Element filed = document.createElement(key);
                filed.appendChild(document.createTextNode(value));
                root.appendChild(filed);
            }
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            DOMSource source = new DOMSource(document);
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            transformer.transform(source, result);
            String output = writer.getBuffer().toString(); //.replaceAll("\n|\r", "");
            try {
                writer.close();
            } catch (Exception ex) {
            }
            return output;
        }
    
        /**
         * 拼接
         *
         * @param infoIds
         * @return
         */
        @NonNull
        public static String getStringBuffer(List<Map.Entry<String, Object>> infoIds) {
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < infoIds.size(); i++) {
                Map.Entry<String, Object> stringStringEntry = infoIds.get(i);
                if (stringStringEntry.getKey() == null) {
                    stringStringEntry.getKey();
                }
                String key = stringStringEntry.getKey();
                Object val = stringStringEntry.getValue();
                if (i != infoIds.size() - 1) {
                    if (val != null && !TextUtils.equals("", val.toString())) {
                        sb.append(key).append("=").append(val).append("&");
                    }
                } else {
                    if (val != null && !TextUtils.equals("", val.toString())) {
                        sb.append(key).append("=").append(val);
                    }
                }
            }
            return sb.toString();
        }
    
        /**
         * 作 者: yzhg
         * 历 史: (版本) 1.0
         * 描 述: md5加密
         */
        public static String encode(String password) {
            try {
                MessageDigest digest = MessageDigest.getInstance("md5");
                byte[] result = digest.digest(password.getBytes());
                StringBuilder sb = new StringBuilder();
                for (byte b : result) {
                    int number = b & 0xff;
                    String str = Integer.toHexString(number);
                    if (str.length() == 1) {
                        sb.append("0");
                    }
                    sb.append(str);
                }
                return sb.toString();
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
                return "";
            }
        }
    
        public static String parseGetAuthInfoXML(String resultText, String indexText) throws Exception {
            InputStream is = new ByteArrayInputStream(resultText.getBytes());
            String result = null;
            XmlPullParser parser = Xml.newPullParser();
            parser.setInput(is, "UTF-8");
    
            int eventType = parser.getEventType();
            while (eventType != XmlPullParser.END_DOCUMENT) {
                switch (eventType) {
                    case XmlPullParser.START_TAG:
                        if (parser.getName().equals(indexText)) {
                            eventType = parser.next();
                            result = parser.getText();
                        }
                }
                eventType = parser.next();
            }
            return result;
        }
    
    }

     

    展开全文
  • 安卓和IOS两个平台微信识别二维码的机制分别是什么?这两个平台解码的步骤是?
  • 近来在写H5页面时发现在手机端微信里长按识别二维码有时会出现不能识别的... “微信识别二维码采用的逻辑是截屏识别,当客户端发现用户在网页的img标签内进行长按操作时,会立刻截屏并且启动二维码识别算法。所以这...

    近来在写H5页面时发现在手机端微信里长按识别二维码有时会出现不能识别的bug,最近就对这些可能导致二维码不能识别的bug做了一下研究,写出来,和大家分享一下。

       

    一、微信识别二维码的原理机制

       我们先来看一下微信识别二维码的原理机制:

       “微信识别二维码采用的逻辑是截屏识别,当客户端发现用户在网页的img标签内进行长按操作时,会立刻截屏并且启动二维码识别算法。所以这里用于二维码识别的图片是截屏,而不是之前有人提到的img标签中的图片。

       为什么要用截屏,这也是一个开发时候的思考。客户端截屏时候,可以不用考虑网络传输等因素,最快的得到识别结果,否则就需要走一次图片下载的逻辑,用户长按后等待的时间会加长,体验上也失去了快感。当然,这也带来了识别不出的问题(所以正在考虑先截屏,截屏识别失败再下载的新逻辑)。”

       详情请参考:网页中二维码识别规则

     

    二、二维码识别常见的BUG及解决方法

    1、二维码图片直接放在background里时无法识别

       由上述二维码识别原理我们可以知道客户端是检测网页的img标签内进行长按操作时,会立刻截屏并且启动二维码识别算法。所以当将二维码图片直接放在background中时,识别效果特别差,基本上是识别不出来的。所以最好是将二维码图片单独切出来放在了img标签中。

     

    2、多张二维码图片无法在同一屏幕中共享

       微信识别二维码的原理是长按的时候相当于将当前手机屏幕截屏,识别截屏后的图片,这样一张图片有两个二维码图的时候当然只会识别出一个。建议解决办法是不要在同一屏幕中放多张图片或者提示用户双击放大二维码进行二维码识别。

     

    3、多次执行长按二维码的功能会导致内存泄漏,手机会变卡

       多次执行长按二维码的功能会导致手机(iPhone)变卡。长按识别二维码,多次测试后右键识别出来是二维码图片(即没有出现“识别二维码”的按钮)。

     

    4、iOS 版微信长按识别二维码无法正常识别

    (8.21 更新:最新版6.2.4 已经修复该bug)

       以下实测在iOS 版(iPhone)微信6.2.2 中有此bug,安卓版微信暂时没有发现有此bug。

       对于二维码区域,实际可识别区域是整体上移64px,64px的偏移与二维码大小本身无关。下面的红色的区域即为实际可识别的二维码区域。为什么是神秘的64px?因为64px正好是微信内置浏览器标题栏+系统标题栏的高度。可以认为微信客户端在识别二维码的时候忽略了微信标题栏+系统状态栏的高度。

    解决方案有两个

    (1)通过为img增加padding增大可接触面积。

    (2)为二维码本身增加透明底部背景,如下:

     

    5、IOS系统meta缩放问题导致二维码无法识别

       在安卓版的微信长按二维码可以识别(前提是你的微信版本到支持此功能),但是到了苹果版的微信就识别不了,这时候可能是缩放的问题:

    (1)设置了初始缩放设置为1,最大缩放值要>=1,不支持缩放。--->可以识别。

       如<meta content="width=device-width, initial-scale=1, maximum-scale=1.2, user-scalable=0" name="viewport" />

    (2)设置了初始缩放设置为小于1或者大于1,最大缩放值大于或者等于初始缩放,不支持缩放。--->不可以识别。

       如<meta content="width=device-width, initial-scale=1.1, maximum-scale=1.2, user-scalable=0" name="viewport" />

    (3)设置了初始缩放设置为1,最大缩放值要>=1,支持缩放。--->页面不缩放之前可以识别,一旦页面缩放过后就不可以识别。

       如<meta content="width=device-width, initial-scale=1, maximum-scale=1.2, user-scalable=1" name="viewport" />

    (4)都不设置时,不可以识别。

    (5)设置了固定的宽,导致二维码的实际位置偏移到屏幕外

       <meta content="width=750, initial-scale=1, maximum-scale=1.2, user-scalable=0" name="viewport" />

    (6)页面有css样式fixed --->不可以识别。

     

    以上这些设置导致二维码图片定位不准,或者二维码全部跑到屏幕外或者部分跑到屏幕外而无法识别。以下是其解决办法:

    方法1
       设置:初始缩放为1,最大缩放值要大于1,不支持缩放。如下:

       <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=no"/>

     

    方法2

       首先要把这张二维码添加到body的子元素 放在最后或者是最前都可以,

    注意这可能影响你的布局,可设置position:absolute,进行调整,因为这才是真正用来识别的二维码,如果这个二维码位置太偏移,有可能会造成二维码无法识别。此外还需要注意的是opacity需要设为0而不是设置display属性。

       <img style="position:absolute;width: XXpx;height: XXpx;opacity: 0" src="二维码图片地址"> 

       其次,在你应该在设计稿设计的地方,放置的div里面设置你正常二维码图片的大小,以便页面呈现正常。

       <img style="你的正常大小" src="二维码图片地址" />

       这时你就会发现长按图片能够识别出来二维码。

     

       其实除了这些BUG外,二维码信息显示不全;在长按时候只有部分可见;二维码周围信息过于复杂,在整个截屏中二维码算法无法正确识别;网页没有加载完成,微信的识别js没有启动都会导致二维码无法识别,另外二维码过大或者过小时,也会出现识别困难问题,通常160*160就可以了

     

    此文章主要发布在本人所在公司网站H5案例分享(http://www.h5-share.com/)、公司公众号H5握手和个人博客中,转载请注明出处。

     

    转载于:https://www.cnblogs.com/daipianpian/p/6421843.html

    展开全文
  • ios微信二维码无法长按识别的若干解决方案

    ios微信二维码无法长按识别的若干解决方案

    参考文章:

    (1)ios微信二维码无法长按识别的若干解决方案

    (2)https://www.cnblogs.com/is17/p/5777373.html


    备忘一下。


    展开全文
  • 实现思路 长按识别第一时间想到了wx.previewImage(Object object, boolean showmenu) 在新页面中全屏预览图片。...经测试,用web-view 的url链接到有企业微信二维码图片的文章链接,长按识别就可以实现加好友功能 ...
  • 制作: http://jingyan.baidu.com/article/e3c78d644353ea3c4c85f506.html?st=2&...bd_page_type=1&os=0&rst= 识别 http://jingyan.baidu.com/article/495ba8410bba5138b30edecc.html 转载于:...
  • 微信二维码

    千次阅读 2018-08-31 16:16:00
    1.二维码是什么 ...不过这种图片能被扫描工具识别的, 比如用微信扫描二维码, 支付宝扫描二维码 经查问资料和测试后, 了解到原来二维本质就是一段文本, 一般都表示一个URL地址 根据url的不同, 扫描后, 会使...
  • 产品要求 :1、活动页面 用户长按二维码 ,可以保存图片,保存的图片为二维码。  2、不在乎用户流量的前提下,视觉稿不需要切太多。  上述两种要求下,如果二维码是嵌入到你切图的中间,这时候如果用户长按二维码...
  • 如何在 PC 上识别微信二维码

    千次阅读 2019-09-09 16:41:29
    抓图 把二维码通过微信发消息给自己 点开,右键就能看到识别二维码了。 看到没。
  • 在使用CSDN的过程中,看到一些大佬的微信...(1)首先需要将自己的微信二维码上传到CSDN任一博文中,原因是自定义栏目识别不了外部图像,操作示意图如下,我自己新建了一个博文,然后插入了我想上传的图片。  ...
  • 在使用CSDN的过程中,一般人都不怎么会去关注私信或留言的,因此为了更加有效... (1)首先需要将自己的微信二维码上传到CSDN博客相册或任一博文中,原因是自定义栏目识别不了外部图像,操作示意图如下,我自己新...
  • 微信二维码小程序怎么做? 第一步:首先在手机中打开微信,然后进入小程序。 第二步:然后在小程序中搜索“二维码”然后点击进入生成二维码小程序。 第三步:接下来在新建二维码里点击文本,然后输入你想要表白的话...
  • 微信小程序二维码识别

    千次阅读 2018-11-23 14:44:00
    于是,自己突发奇想做了一个微信二维码识别的小程序。 包含功能: 1、识别二维码 ①普通二维码 ②条形码 ③只是复制解析出来的数据 2、生成二维码 ①只是从粘贴板生成二维码 软件截图: 体验二维码...
  • 2.先将自己的微信二维码保存下来,再用二维码扫描器识别出二维码的链接地址 echo &amp;amp;amp;quot;替换成你自己的链接地址xxx&amp;amp;amp;quot; | qrencode -o - -t ANSI | gzip -c | base64 &amp;...
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • Zxing仿微信二维码扫描

    千次阅读 2016-10-18 23:24:46
    1.Zxing的介绍 2.二维码的生成 3.二维码识别
  • 一种实现个人微信二维码收款接口的方法

    万次阅读 热门讨论 2018-06-03 00:37:19
    个人二维码收款码里面除了可以设计金额外还可以设置收款方的备注,这个收款方的备注在识别是哪个用户付款的时候会用到,需要与付款方的备注区分。个人收款码同一个金额按照不同的收款备注设置多个,然后保存到服务端...
  • amp;openid=OPENID&amp;lang=zh_CN判断用户是否已经关注过公众号:{"subscribe":0,"openid":"ovAxxxxxxxxxx0JQZY"...:[]}没有关注过的用户引导用户跳转到关注页...
  • 二维码深入人心,很多App都在官网挂出了可以扫描下载apk的二维码,笔者所在... 让网址尽可能短:信息越少,二维码的尺寸就可以做得越小,嵌入的LOGO可以更大,识别率也会越高。  2. 让iPhone和Android通过同一个
  • 相信大家在平常的生活中,如果遇到扫码的场景第一个想到的应该就是微信了,可以说微信使用二维码打开了移动互联网的另一扇大门,并且在扫码体验上及其优秀,本该有一定要求的扫码过程,在经过微信的优化之后,让用户...
  • 二维码深入人心,很多App都在官网挂出了可以扫描下载apk的二维码,... 让网址尽可能短:信息越少,二维码的尺寸就可以做得越小,嵌入的LOGO可以更大,识别率也会越高。  2. 让iPhone和Android通过同一个二维码下...
  • 个人二维码收款码里面除了可以设计金额外还可以设置收款方的备注,这个收款方的备注在识别是哪个用户付款的时候会用到,需要与付款方的备注区分。 个人收款码 同一个金额按照不同的收款备注设置多个,然后保存到...
  • 在安卓版的微信长按二维码可以识别(前提是你的微信版本到支持此功能),但是到了苹果版的微信识别不了,经个人测试发现是缩放的问题: 1、设置了初始缩放设置为1,最大缩放值要>=1,不支持缩放。--->可以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,223
精华内容 489
关键字:

微信二维码识别