项目 App 需要做到支付功能,首先接入的是 WeChat Pay。业务逻辑需要,支付功能需要在 WebView
中实现,也就是使用 H5 支付。
我只要写一个搭载 WebView
组件的 Activity
并初始化好相关设置,然后剩下的交给 Web 开发就好了。
首先,想要使用 WeChat Pay 的接口,要先向微信支付商户平台提交申请,因为我们是需要在 H5 中调起微信支付,所以就需要申请 H5 支付的权限,提交申请材料后需要等待 3~5 个工作日后才能知道申请结果,由于是测试版本的原因,内容填写的并不是太完善,但是审核也不是太严格。
接下来就是在 H5 中按照微信官方提供的开发文档来搭建这个支付接口了。
Android 方面,也需要配置一定的代码,直接请求的话会出现以下错误:
微信支付的开发文档有相关的错误描述:商家参数格式有误,请联系商家解决。
官方提供的解决方法如下:
- 当前调起H5支付的referer为空导致,一般是因为直接访问页面调起H5支付,请按正常流程进行页面跳转后发起支付,或自行抓包确认referer值是否为空
- 如果是APP里调起H5支付,需要在webview中手动设置referer,如(
Map extraHeaders = new HashMap();
extraHeaders.put("Referer", "商户申请H5时提交的授权域名");//例如 http://www.baidu.com ))
不过这个示例也对小白太不友好了,就这么两行代码,十分考验想象力。
在网上查了下前辈们的做法,得出以下代码:
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
// 判断为微信支付头则调起微信支付
webView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith("weixin://wap/pay?")) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
return true;
} else {
Map extraHeaders = new HashMap();
extraHeaders.put("Referer", domain); // 商户申请H5时提交的授权域名
view.loadUrl(url, extraHeaders);
}
return super.shouldOverrideUrlLoading(view, url);
}
});
webView.loadUrl(payUrl);
这里重写了 WebViewClient
内的 shouldOverrideUrlLoading(WebView, String)
方法,使其检测 URL 中是否带有微信支付头,即 weixin://wap/pay?
,如果是,则调起 WeChat Pay,而在实测中,基本都会跑到这个判断中,而不会跑到下方微信提供的方法,所以暂时不知道其有何作用。
另外,使用 shouldOverrideUrlLoading(WebView, String)
的时候发现该方法被标记为已过时,虽然暂时只是不推荐使用,未被抛弃,不过还是尽快转移到更新的方法上比较好,我在文档中看到有一个相似的方法 shouldOverrideUrlLoading(WebView, WebResourceRequest)
,粗略的浏览了一下,似乎还没有人使用该方法替代上面的方法,于是自行尝试了一下,发现可以把上方的代码改写为:
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
String url = request.getUrl().toString();
if (url.startsWith("weixin://wap/pay?")) {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
return true;
} else {
Map extraHeaders = new HashMap();
extraHeaders.put("Referer", DOMAIN); // 商户申请H5时提交的授权域名
view.loadUrl(url, extraHeaders);
}
}
return super.shouldOverrideUrlLoading(view, request);
}
其实差别也不大,只不过 URL 不能从形参中直接获取而是要从 WebResourceRequest
中获取罢了。
有时候不行可能是因为 Referer
没写进去,可以使用以下方法抓取 Referer
:
MyWebViewClient myWebViewClient = new MyWebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
...
Log.d("===WebViewURL===", view.getUrl()); // 打印当前页面的 Url
Uri ref = getReferrer(); // 抓取 Referer
if (ref != null) {
Log.d("====REFERER====", ref.toString());
} else {
Log.e("====REFERER====", "NULL");
}
return super.shouldOverrideUrlLoading(view, url);
}
};