Android支付宝支付集成
Android支付宝支付
标签: android
Android支付宝支付使用的流程介绍
- 支付宝流程介绍
支付宝流程
支付宝流程相对于微信支付要简单很多下面我们先从支付流程开始介绍
支付流程.png在开始集成之前我们了解一下常用的接入方式和框架建议
在开始之前网上有很多这样的操作
/**
* create the order info. 创建订单信息
*/
private String getOrderInfo(String subject, String body, String price) {
// 签约合作者身份ID
String orderInfo = "partner=" + "\"" + PARTNER + "\"";
// 签约卖家支付宝账号
orderInfo += "&seller_id=" + "\"" + SELLER + "\"";
// 商户网站唯一订单号
orderInfo += "&out_trade_no=" + "\"" + getOutTradeNo() + "\"";
// 商品名称
orderInfo += "&subject=" + "\"" + subject + "\"";
// 商品详情
orderInfo += "&body=" + "\"" + body + "\"";
// 商品金额
orderInfo += "&total_fee=" + "\"" + price + "\"";
// 服务器异步通知页面路径
orderInfo += "¬ify_url=" + "\"" + "http://notify.msp.hk/notify.htm" + "\"";
// 服务接口名称, 固定值
orderInfo += "&service=\"mobile.securitypay.pay\"";
// 支付类型, 固定值
orderInfo += "&payment_type=\"1\"";
// 参数编码, 固定值
orderInfo += "&_input_charset=\"utf-8\"";
// 设置未付款交易的超时时间
// 默认30分钟,一旦超时,该笔交易就会自动被关闭。
// 取值范围:1m~15d。
// m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
// 该参数数值不接受小数点,如1.5h,可转换为90m。
orderInfo += "&it_b_pay=\"30m\"";
// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";
// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
orderInfo += "&return_url=\"m.alipay.com\"";
// 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)
// orderInfo += "&paymethod=\"expressGateway\"";
return orderInfo;
}
这一大堆代码,估计一些新司机就有点懵逼了,至于吗?集成一个第三方的,不应该是调用越简洁越好吗,而且还是大厂的第三方,不应该啊?所以,笔者有必要出面说明一下,那些老司机,你们弄好了,也不能这么吓唬新司机啊,说正经的,网上代码那么长,是因为他们在本地区生成的订单签名,这个订单签名也就是一个字符串,他由订单信息,支付金额,订单号,商户信息等拼接起来的(基本上都是后台返回的)
下面是APP支付请求所需的参数
APP支付请求所需的参数
参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
---|---|---|---|---|---|
app_id | String | 是 | 32 | 支付宝分配给开发者的应用ID | 2014072300007148 |
method | String | 是 | 128 | 接口名称 | alipay.trade.app.pay |
format | String | 否 | 40 | 仅支持JSON | JSON |
charset | String | 是 | 10 | 请求使用的编码格式,如utf-8,gbk,gb2312等 | utf-8 |
sign_type | String | 是 | 10 | 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2 | RSA2 |
sign | String | 是 | 256 | 商户请求参数的签名串,详见签名 | 详见示例 |
timestamp | String | 是 | 19 | 发送请求的时间,格式"yyyy-MM-dd HH:mm:ss" | 2014-07-24 03:07:50 |
version | String | 是 | 3 | 调用的接口版本,固定为:1.0 | 1.0 |
notify_url | String | 是 | 256 | 支付宝服务器主动通知商户服务器里指定的页面http/https路径。建议商户使用https | https://api.xx.com/receive_notify.htm |
biz_content | String | 是 | - | 业务请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档 |
接下来的事情嘛,就比较简单了 这里配置就不多介绍 详细介绍
1. 清单文件做如下配置
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name="com.alipay.sdk.app.H5AuthActivity"
android:configChanges="orientation|keyboardHidden|navigation"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" />
2. 请求自己服务器,获取订单签名字符串,然后调用支付宝SDK,发起支付请求
/**
* 显示支付宝签名
*
* @param aliPayBean 自己服务器返回的订单签名字符串
*/
public void aliPayData(AliPayBean aliPayBean) {
//支付宝支付请求所需的签名字符串
final String orderInfo = aliPayBean.getResult().getMessage();
Runnable payRunnable = new Runnable() {
@Override
public void run() {
PayTask alipay = new PayTask(PaymentActivity.this);
Map<String, String> result = alipay.payV2(orderInfo, true);
Log.i("msp", result.toString());
Message msg = new Message();
msg.what = SDK_ALI_PAY_FLAG;
msg.obj = result;
mHandler.sendMessage(msg);
}
};
// 必须异步调用
Thread payThread = new Thread(payRunnable);
payThread.start();
}
3. 支付宝支付结果的回调
/支付宝返回数据handler
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressWarnings("unused")
public void handleMessage(Message msg) {
switch (msg.what) {
case SDK_ALI_PAY_FLAG: {
@SuppressWarnings("unchecked")
PayResult payResult = new PayResult((Map<String, String>) msg.obj);
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String resultStatus = payResult.getResultStatus();
String result = "";
// 判断resultStatus 为9000则代表支付成功
Log.i(TAG, resultStatus);
if (TextUtils.equals(resultStatus, "9000")) {
//支付成功
result = "支付成功";
aliPaySuccess();
} else if ("6001".equals(resultStatus)) {
result = "您取消了支付";
} else {
// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
result = "支付失败";
}
ToastUtils.showToast(mContext, result);
break;
}
}
}
};
注意:这里支付成功,我只是以客户端作为标准,实际传支付结果,最好以服务端为标准,我们调用支付宝支付的时候,支付宝会有2个回调,一个是APP的回调,就是我们上面这个,9000代表支付成功,一个是支付宝服务器通知我们自己的服务器,所以,我们自己的服务器也有个回调。所以APP可以请求后台的接口来获取支付结果。
Android 常遇到的问题
1.签约的坑
一般来说,最初签约完开发者通常只有当面付和手机网站支付两个途径
手机网站支付即调用Web的支付宝付款,在APP中也可以将Web支付变为自己的支付途径
但相比而言原生APP支付更加方便
在申请APP支付签约时首先要进入商家中心签好约不然所有的APP支付签约会被支付宝取消(如下图)
签约功能.png
支付宝商家平台地址
签约完毕之后我们就能愉快的发起支付
2.签名的坑
当时我们用的后台服务器是用php写的
生成密钥.png
java服务器选择PKCS8格式 php服务器选择PKCS1格式
确定了密钥长度后就可以生成密钥了
密钥.png
密钥有两种1.应用私钥2.应用公钥 这两种密钥互相对应分别对应于支付宝平台和服务器
应用公钥即设置在支付宝中暴露给外界的,客户端在调用支付时支付宝会将两者匹配,匹配不成功时会出现错误
如果只是密钥对应不上就会报这个错
密钥对应不上.png
而若是其他key和PID都不对的话,说明其他配置信息都有错误需要仔细排查
密钥及其他配置有误.png
在这个过程中的坑点就是支付宝不会返回具体的返回码当你按下确定或者退出时
返回一个用户取消的消息所以你只能自己找错误,真的很坑!
公钥的放置地方:下图的3个密钥平台的RSA或者RSA2都要填同一公钥
公钥的设置.png
而私钥则是存放在服务器中通过订单生成和签名encoding返回给客户端的
这里PHP最坑的是支付宝提供的签名工具模拟签名时请求参数要带上sign_type导致签名后的结果与服务器返回的结果完全不符,所以无法验证服务器的签名到底是否正确
还有支付宝提供的demo不支持PKCS1的密钥(你TM逗我?)而且使用SDK进行的服务器上的签名报错?????最后找了个办法只好让服务器的密钥转化为PKCS8才能成功签名返回并客户端提交支付成功
不多说了一口老血吐出来,若是后台兄弟在这问题半天就搞定了,就当涨姿势了,希望后头的兄弟不要因为这样的事情而浪费时间,做项目卡住只能怪技术,而为第三方接入浪费大把时间真的不值,以后不要在犯同样的错误.
作者 @windrain_boy
2017年06月06日