• 非微信内置浏览器中的网页调起微信支付的方案研究


    问题来源
    之前在app中集成过微信支付,当时还写了一篇扫坑贴,此种微信支付方式为app支付,即在我们自己的应用中嵌入微信支付SDK,由Native代码调起微信支付。

    后来由于业务需要在我们app的WebView中打开第三方店铺的网页,在第三方网页中有微信支付按钮,测试反馈说ios可以调起微信支付,而android不可以。后来网上看到说微信内置Webview和京东的网页也可以调起微信支付,微信自己没什么奇怪的,而京东可以的话,如果它跟微信没什么合作协议的话,那么其他app应该也可以在网页中调用微信支付。

    探索
    由于ios可以支持,因此找ios同事测试了一下,发现ios内置浏览器中只要输入相关协议都可以调起相关app的,比如:

    输入weixin:// 可以调起微信
    输入alipay:// 可以调起支付宝
    这样就不难解释为什么ios的webview中第三方网页可以调起微信支付了,但android在浏览器中输入上述协议,没有任何响应。因此本文主要探讨是基于android平台的。

    后来终于找到微信支付|商户平台开发者文档,作为客户端开发者,是不会想到这个开发文档的,当时集成app支付的时候所查阅的文档也未提到H5支付的方式。在文档的使用场景介绍中有这么一段:

    H5支付是基于公众号基础开发的一种非微信内浏览器支付方式(需要单独申请支付权限),可以满足在微信外的手机H5页面进行微信支付的需求。同时,由于H5链接传播十分方便、来源不易追踪,商户需要特别注意做好防钓鱼、防刷单的处理,控制风险。

    由此看来,确实官方是支持在非微信内置浏览器中调起微信支付的。

    在文档中,微信给了一个官方的测试链接:http://wxpay.weixin.qq.com/pub_v2/pay/wap.v2.php,在手机浏览器中打开该页面,点击“立即购买”,就可以调起微信支付,我测试了Nexus手机的Chorme浏览器和Sony手机的自带浏览器,均可以。具体效果如下图:



    通过查看网页源代码,发现“立即购买”是一个按钮,其连接点击协议是这样的:

    href="weixin://wap/pay?appid%3Dwx2421b1c4370ec43b%26noncestr%3D3e84679af4efab5f32ee9ea01b2ec290%26package%3DWAP%26prepayid%3Dwx20160504154919fdacd7bc0d0127918780%26timestamp%3D1462348159%26sign%3DC40DC4BB970049D6830BA567189B463B"
    1
    瞬间觉得非常熟悉,以前集成app支付的关键代码是这样的:

    IWXAPI api;
    PayReq request = new PayReq();
    request.appId = "wxd930xxxxxx2xxf4f";
    request.partnerId = "19xxx0xx09";
    request.prepayId= "1101000000140xxxxx9afxxx314aa427",;
    request.packageValue = "Sign=WXPay";
    request.nonceStr= "1101000000xxxxx9eb4xxx6f8896f4c9";
    request.timeStamp= "13987xxx74";
    request.sign= "7FFECB600DXXX7C5AAXXX810D2DXXX8BC2811827B";
    api.sendReq(req);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    上述a链接里的协议就是app支付里面的各种参数,因此可以得到结论,weixin://wap/pay是微信定义的一种支付协议,用于网页端支付,微信app必定设置了名为weixin://的scheme,因此可以在网页上唤起微信app,在通过约定的参数名称,获取各种参数,从而可以完成支付,具体机制跟app支付是相同的。至于上面一系列参数,是第三方网页端跟微信那边获取的,均由第三方服务端处理,客户端不必关心。

    知道了以上原理,就该讨论解决方案了,下面有几种可行的方案。

    解决方案1
    上面可知,微信的H5支付协议可以在浏览器中调起微信,这也是最简单的方案。如果我们的app打开第三方网页用的是手机浏览器的话,就不用做什么,直接可以调起微信支付了。按微信文档所说,应该大部分浏览器都支持,我只是简单测试了两款。

    解决方案2
    第一种方案固然简单,但事实上我们往往使用WebView来打开第三方网页,而不是手机浏览器,因此如何让WebView也支持调起微信支付才是核心问题。经过测试发现,原生WebView是可以唤起微信支付的,核心代码如下:

    webView = new WebView(this);
    webView.getSettings().setJavaScriptEnabled(true);  
    webView.loadUrl("http://wxpay.weixin.qq.com/pub_v2/pay/wap.v2.php");
    1
    2
    3
    对,就这样简单就OK了。

    然而往往我们的app中使用自定义的WebView,经测试发现如果为WebView设置了WebViewClient,如下:

    webView.setWebViewClient(new WebViewClient() {
        // some logic
    }
    1
    2
    3
    那么就不能唤起微信支付了,errorCode返回-10,提示“不支持该协议”。联系到可以在浏览器中唤起微信支付,因此我的解决方案如下,经测试是可以的。

        webView.setWebViewClient(new WebViewClient() {  
            @Override  
            public boolean shouldOverrideUrlLoading(WebView view, String url) {  
                // 如下方案可在非微信内部WebView的H5页面中调出微信支付
                if (url.startsWith("weixin://wap/pay?")) {
                    Intent intent = new Intent();
                    intent.setAction(Intent.ACTION_VIEW);
                    intent.setData(Uri.parse(url));
                    startActivity(intent);
                    
                    return true;
                }
                return super.shouldOverrideUrlLoading(view, url);
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                // TODO Auto-generated method stub                
                super.onPageFinished(view, url);
            }

            @Override
            public void onReceivedError(WebView view, int errorCode,
                    String description, String failingUrl) {
                // TODO Auto-generated method stub                
                super.onReceivedError(view, errorCode, description, failingUrl);
            }            
            
        });
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    第二种解决方案的效果图如下,注意使用了WebView打开的网页:



    解决方案3
    跟前两种方案相比,第三种就算直接暴力了。结合之前嵌入SDK的app支付方式,我们可以在WebView里拦截H5的支付协议,从上述协议中取出各个参数,完全可以走微信APP支付的方式了。可以发现H5的支付协议中唯独少了partnerId,partnerId指商户ID,在注册微信支付时都会有。至于为什么没有商户id,猜测一是为了安全,另外第三方自家的网页,当然已知partnerId了(如京东的网页,京东在微信的商户id当然知道的),就没必要放到协议中去。

    如果我们的app知道第三方的partnerId的话,这样就能拿到所有参数,理论上完全可以转走app支付的方式,具体我没有测试,有兴趣的可以试一下。


    ---------------------
    作者:aspook
    来源:CSDN
    原文:https://blog.csdn.net/ahence/article/details/51317814
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    Java基础面试操作题: 线程问题,写一个死锁(原理:只有互相都等待对方放弃资源才会产生死锁)
    Java基础面试操作题: File IO 文件过滤器FileFilter 练习 把一个文件夹下的.java文件复制到另一个文件夹下的.txt文件
    Java基础面试操作题:Java代理工厂设计模式 ProxyFactory 有一个Baby类,有Cry行为,Baby可以配一个保姆 但是作为保姆必须遵守保姆协议:能够处理Baby类Cry的行为,如喂奶、哄睡觉。
    Java中 Character方法练习:字符串中英文字母个数 5435abc54abc3AHJ5 正则:matches("[a-zA-Z0-9]{1}")
    Java 练习:字符串反转
    集合类别
    JAVA 后台
    micro focus cobol vs mainframe cobol
    Java 编码
    关于java中char占几个字节,汉字占几个字节
  • 原文地址:https://www.cnblogs.com/caicaizi/p/10167336.html
Copyright © 2020-2023  润新知