H5中调起支付宝支付,处理方式比较简单,主要对url进行拦截,判断是否以alipay开头,则进行拦截,不在使用webview加载,直接跳转Intent。这里有个点,需要注意下:
不能以alipays://
作为判断条件,例如有时返回的链接是这样的alipayqr
alipayqr://platformapi/startapp?saId=100&clientVersion=3.7.0.0718&qrcode=https://qr.alipay.com/ltx3afsnrpajaeji52?_s=web-other
所以在拦截url的时候放宽了判断条件,只要以alipay
开头的,则拦截跳转,代码如下:
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//支付宝
if (url.startsWith(ALIPAYS_SCHEME)) {
try {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
} catch (ActivityNotFoundException e){
Toast.makeText(DemoActivity.this, "请安装支付宝客户端", Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
view.loadUrl(url);
return true;
}
到此,一切正常。突然有一天,测试过来找到我,接入的购票系统,用支付宝支付的时候,手机有安装支付宝却提示未安装。
我说我不信,在演示一下,问题复现了。我自言自语到:不可能啊!!!后来开始排查,跳转支付宝的链接,如下:
//url中删除了敏感信息
alipay://alipayclient/?%7b%22requestType%22%3a%22SafePay%22%2c%22dataString%22%3a%22dispatch_cluster_target%3dmrmapi%26ord_amt%3d8.00%26_input_charset%3dUTF-8%26sign%3dfhpN0rJGyfGCZXg%253D%253D%26ord_cur%3dCNY%26ord_id_ext%3dM2020087%26alipay_exterface_invoke_assign_target%3dcreateAndPayByBuyer.htm%26%26alipay_exterface_invoke_assign_client_ip%3d47.94.97.52%26bizcontext%3d%7b%5c%22appkey%5c%22%3a%5c%22201%5c%22%7d%22%2c%22fromAppUrlScheme%22%3a%22%22%7d
alipay://alipayclient,查了下这个链接,需要集成支付宝SDK在应用内打开支付宝,
上面的链接是经过url编码的,可以使用在线url解码,看下解码后的结果:
alipay://alipayclient/?{
"requestType":"SafePay",
"dataString":"dispatch_cluster_target=mrmapi&ord_amt=8.00&_input_charset=UTF-8&sign=fhpN0rJGyfGCZXg%3D%3D&ord_cur=CNY&ord_id_ext=M2020087&alipay_exterface_invoke_assign_target=createAndPayByBuyer.htm&&alipay_exterface_invoke_assign_client_ip=47.94.97.52&bizcontext={\"appkey\":\"201\"}",
"fromAppUrlScheme":""
}
其中,dataString
便是对应的是订单信息。支付宝API需要传入。基本分为3步:
1.对Url进行解码
2.解码后以?号进行分割,对第二部分进行json解析
3.拿到字段dataString
传入支付宝API进行调用
代码如下:
private void startAlipaySDK(String url) {
//? 号分割,?后面为订单参数
String[] urlSplit = url.split("\\?");
if (urlSplit.length > 1) {
try {
String data = urlSplit[1];
if (TextUtils.isEmpty(data)) {
Toast.makeText(DemoActivity.this, "调用失败, Toast.LENGTH_LONG).show();
return ;
}
//对url进行解码,解码后解析
String decodeUrl = URLDecoder.decode(data, "UTF-8");
JSONObject obj = new JSONObject(decodeUrl);
//订单信息
String orderInfo = obj.getString("dataString");
// 必须异步调用
new Thread(() -> {
PayTask alipay = new PayTask(X5WebActivity.this);
//如果需要处理回调,可把result发送Handler消息,在handler中处理
Map<String, String> result = alipay.payV2(orderInfo, true);
}).start();
} catch (Exception e) {
e.printStackTrace();
}
}else{
Toast.makeText(DemoActivity.this, "调用失败, Toast.LENGTH_LONG).show();
}
}
拦截Url中的最终代码:
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
//支付宝
if (url.startsWith(ALIPAYS_SCHEME)) {
try {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
} catch (ActivityNotFoundException e){
if (url.startsWith("alipay://alipayclient")) {//调用支付宝SDK打开
startAlipaySDK(url);
}else{
Toast.makeText(this, "请安装支付宝").show();
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
view.loadUrl(url);
return true;
}