首先看一下效果图:
注意:本Demo使用的银联SDK版本:3.1.0 更新时间:2017-08-02
概述
银联手机支付控件(以下简称支付控件),主要为合作商户的手机客户端提供安全、便捷的支付服务。用户通过在支付控件中输入银行卡卡号、手机号、密码(借记卡和预付卡)或者CVN2、有效期(信用卡)、验证码等要素完成支付。支付流程介绍
通过支付控件进行交易的流程如下图:
流程图说明:
(1)用户在客户端中点击购买商品,客户端发起订单生成请求到商户后台;
(2)商户后台收到订单生成请求后,按照《手机控件支付产品接口规范》组织并推送订单信息至银联后台;
(3)银联后台接收订单信息并检查通过后,生成对应交易流水号(即TN),并回复交易流水号至商户后台(应答要素:交易流水号等);
(4)商户后台接收到交易流水号,将交易流水号返回给客户端;
(5)客户端通过交易流水号(TN)调用支付控件;
(6)用户在支付控件中输入相关支付信息后,由支付控件向银联后台发起支付请求;
(7)支付成功后,银联后台将支付结果通知给商户后台;
(8)银联将支付结果通知支付控件;
(9)支付控件显示支付结果并将支付结果返回给客户端;
目前各个平台支持的设备情况如下:
Android平台SDK主要适用于Android 2.3及以上版本的终端设备;测试账号
提供测试使用卡号、手机号信息(此类信息仅供测试,不会发生正式交易)
Android客户端接入 (Android studio 版本)
添加SDK包到项目中:
1.拷贝两个jar包:UPPayAssistEx.jar UPPayPluginExPro.jar到libs目录下
2.在main包下新建assets文件夹放置资源文件data.bin
3.在main包下新建jniLibs文件夹分别放置armeabi-v7a、armeabi、arm64-v8a、x86、x86_64文件夹下的.so文件
效果图:
清单文件AndroidManifest.xml配置注册支付插件使用的Activity
<activity
android:name="com.unionpay.uppay.PayActivity"
android:configChanges="orientation|keyboardHidden"
android:excludeFromRecents="true"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize" />
demo中有请求网络拿tn,需配置网络权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce" />
6.调用支付控件
// “00” – 银联正式环境
// “01” – 银联测试环境,该环境中不发生真实交易
String tn = (String) msg.obj;
if (!TextUtils.isEmpty(tn)) {
// 测试环境
tring serverMode = "01";
UPPayAssistEx.startPayByJAR(MainActivity.this, PayActivity.class, null, null, tn, serverMode);
}
子线程获取tn(流水号,实际项目中由后台返回)
/**
* 获取tn线程
*/
private class MyThread extends Thread {
public MyThread() {
}
@Override
public void run() {
super.run();
String tn = null;
InputStream is;
try {
String url = TN_URL_01;
URL myURL = new URL(url);
URLConnection ucon = myURL.openConnection();
ucon.setConnectTimeout(120 * 1000);
is = ucon.getInputStream();
int i = -1;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((i = is.read()) != -1) {
baos.write(i);
}
tn = baos.toString();
is.close();
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
Message msg = mHandler.obtainMessage();
msg.obj = tn;
mHandler.sendMessage(msg);
}
}
最后处理支付后的结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (data == null) {
return;
}
String str = data.getExtras().getString("pay_result");
Log.e("xuke", "sign=" + str);
if (str.equalsIgnoreCase(R_SUCCESS)) {
Snackbar.make(container, R.string.pay_success, Snackbar.LENGTH_LONG).show();
} else if (str.equalsIgnoreCase(R_FAIL)) {
Snackbar.make(container, R.string.pay_fail, Snackbar.LENGTH_LONG).show();
} else if (str.equalsIgnoreCase(R_CANCEL)) {
Snackbar.make(container, R.string.pay_cancel, Snackbar.LENGTH_LONG).show();
}
}
实际开发中最好有验证签名信息为好,控件返回的结果信息仅作为参考,商户订单是否成功支付应该以商户后台主动到全渠道查询的结果或者收到全渠道支付结果通知为准。
收到控件返回结果后,建议无视结果中的内容和签名信息,直接到自己的后台查状态,如果后台此时未收到全渠道的后台通知,则主动发起查询接口到全渠道查状态。这样可既保证APP中展示的订单状态和后台记录一致,也可及时更新后台记录的订单状态。
如仍希望使用控件返回的信息,验签时建议送到后台去验签;如果需要在APP中验签,则需要自行实现验签公钥更新的机制,否则银联更新密钥后会验签失败。
具体详细demo可参考官方文档
demo下载