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

问题来源

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

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

探索

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

1. 输入weixin:// 可以调起微信

2. 输入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"

瞬间觉得非常熟悉,以前集成app支付的关键代码是这样的:

IWXAPI api;
PayReq request = new PayReq();
request.appId = "wxd930ea5d5a258f4f";
request.partnerId = "1900000109";
request.prepayId= "1101000000140415649af9fc314aa427",;
request.packageValue = "Sign=WXPay";
request.nonceStr= "1101000000140429eb40476f8896f4c9";
request.timeStamp= "1398746574";
request.sign= "7FFECB600D7157C5AA49810D2D8F28BC2811827B";
api.sendReq(req);

上述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");

对,就这样简单就OK了。

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

webView.setWebViewClient(new WebViewClient() {
    // some logic
}

那么就不能唤起微信支付了,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);
        }            

    });

第二种解决方案的效果图如下,注意使用了WebView打开的网页:

解决方案3

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

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

时间: 2024-07-30 13:46:18

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

PHP限制网页只能在微信内置浏览器中查看并显示

微信现在算是火了,围绕微信开发的应用也越来越多了,前段时间,自己公司需要,用PHP写了一个微信应用,为了防止自己辛苦写成的PHP应用被盗用,于是通过PHP做了限制,只能在微信自带的浏览器中才能打开本应用,一开始无头绪,后经多查证,总算把这功能弄出来了,现在把具体的代码分享给大家. 1 2 3 4 5 6 7 8 <?php $useragent = addslashes($_SERVER['HTTP_USER_AGENT']); if(strpos($useragent, 'MicroMesse

对于微信内置浏览器中不能小窗播放视频原因的分析以及解决

菜鸟:微信内置浏览器中不能小窗播放视频肿么办??? 师傅:徒弟莫猴急,待师傅一一道来:首先,喺发生急事嘅情况下,我哋最要保持冷静,噉才可以施展出一个有思维.有智慧.有头脑嘅人,应该有嘅气质与才华. 菜鸟:哇,知啦,跟住我应该点做哩? 师傅:求百度啊!!!!!! ......以上是背景......以下是根据百度爬到的内容进行的分析与总结...... 分析webkit-playsinline为什么不能在微信内核中起作用的原因: 1:在不考虑微信内核的浏览器中用html5的video方式播放视频时:在

微信内置浏览器中的cookie很诡异呀

微信内置浏览器中的cookie很诡异呀 这是设置和删除COOKIE的代码 function set_cookie($var ,$value = '' ,$expire = 0){ $path = '/'; $domain = 'aaa.com'; $auth = 'sadfsadfasdf'; if($value!='') $value = _myencrypt($value ,$auth); $var = '__abc_'.$var; if($expire==0){ $expire = 0;

Javascript限制网页只能在微信内置浏览器中访问

转载:http://segmentfault.com/a/1190000000754332 最近正在开发一个微信公众账号,其中有一项功能是用户发送文字消息给公众号,然后公众号返回图文消息给用户,用户再点击图文消息即可跳转到一个网页链接,在微信的内置浏览器中打开.那么问题就来了,这个网页首先涉及到了移动web前端开发,我优先选择了用HTML5+bootstrap组合来实现页面的美观效果,前端其他的任务交给javascript解决(这里我是完全使用原生javascript代码,没有用到任何的框架,因

解决 iOS 9.1 微信内置浏览器中html audio 不能自动播放的问题

使用微信现在提供过的微信js-sdk 在ready中进行播放便可. 首先引用js : <script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script> 然后写方法 : function autoPlayAudio1() { wx.config({ // 配置信息, 即使不正确也能使用 wx.ready debug: false, appId: '', timestamp: 1, nonce

微信内置浏览器中实现点击电话号码自动到拨号页面

一般的web处理 1.一键拨号: <a href="tel:10086">马上拨打电话10086</a> 2.发送短信功能: <a href="sms:10086">发送短信</a> 3.移动web页面自动探测电话号码: <meta name="format-detection" content="telephone=no"> <meta http-equiv=

微信开发-微信内置浏览器的Javascript API

源代码来自 http://www.baidufe.com/ /**! * 微信内置浏览器的Javascript API,功能包括: * * 1.分享到微信朋友圈 * 2.分享给微信好友 * 3.分享到腾讯微博 * 4.隐藏/显示右上角的菜单入口 * 5.隐藏/显示底部浏览器工具栏 * 6.获取当前的网络状态 * 7.调起微信客户端的图片播放组件 * 8.关闭公众平台Web页面 * 9.判断当前网页是否在微信内置浏览器中打开 * 10.支持WeixinApi的错误监控 * 11.发送电子邮件 *

微信内置浏览器的JS API

/**! * 微信内置浏览器的Javascript API,功能包括: * * 1.分享到微信朋友圈 * 2.分享给微信好友 * 3.分享到腾讯微博 * 4.新的分享接口,包含朋友圈.好友.微博的分享(for iOS) * 5.隐藏/显示右上角的菜单入口 * 6.隐藏/显示底部浏览器工具栏 * 7.获取当前的网络状态 * 8.调起微信客户端的图片播放组件 * 9.关闭公众平台Web页面 * 10.判断当前网页是否在微信内置浏览器中打开 * 11.增加打开扫描二维码 * 12.支持WeixinAp

ASP.NET MVC Display Mode 移动端视图 配置对微信内置浏览器的识别

最近在捣鼓一个稍微有点low的商城网站,没有计划做app却要求有个wap版,而前端又没有做成响应式,时间WTF,直接利用了asp.net mvc的Display Mode Provider. 使用方式依照上面的链接地址,asp.net mvc application启动的时候会在全局变量 DisplayModeProvider.Instance.Modes 集合中加入 DisplayModeId == "Mobile" 的 IDisplayMode ,因此如果想要在移动端浏览器中展示移