第三方sdk接入 支付宝 微信支付
对于一些接入第三方的东西,感觉实在是没多少可说的,干脆我就整理成了一个帖子,一块简要说说吧。
一.android接入支付——支付宝
支付宝接入的流程啥的我就不多说了,网上资料一大堆,直接说和后台、和平台的交互以及代码的书写吧。首先是在蚂蚁金服开放平台申请企业账号、签约(客户,或项目经理做),然后是创建应用:
签约会自动生成一个应用2.0签约应用,以及appid,当然我们自己也需要创建一个应用,并且提交资料,包括生成的公钥,应用包名等等。
设置好之后就ok了,然后down下那段支付宝经典的代码:
/**
* 这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
* 真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
* 防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
* orderInfo的获取必须来自服务端;
*/
Log.e("===", "订单信息:" + order_info);
order_info = order_info.substring(1);
order_info = order_info.replaceAll("&", "&");
Log.e("===", "处理后订单信息:" + order_info);
========= 根据支付宝的提示 加签过程放到服务器小哥那 所以这段代码可忽略哦 ===========
boolean rsa2 = (RSA2_PRIVATE.length() > 0);
Map<String, String> params = OrderInfoUtil2_0.buildOrderParamMap(APPID, rsa2);
String orderParam = OrderInfoUtil2_0.buildOrderParam(params);
String privateKey = rsa2 ? RSA2_PRIVATE : RSA_PRIVATE;
String sign = OrderInfoUtil2_0.getSign(params, privateKey, rsa2);
final String orderInfo = orderParam + "&" + sign;
==================================================
Runnable payRunnable = new Runnable() { @Override public void run() { PayTask alipay = new PayTask(PayActivity.this); Map<String, String> result = alipay.payV2(order_info, true); android.util.Log.i("msp", result.toString()); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); }};Thread payThread = new Thread(payRunnable);payThread.start();
这个时候有经验的大咖就会问了,你为啥在order_info放到payV2方法之前还对order_info截串,截完还替换&,这个我一开始也不想做,
但是从php那边拿过来order_info后我调起支付,总是会出现Ali40247的错误,不用看着指定是参数不对啊,仔细观察了下返回过来的order_info
发现这个串前边有一个自带的“ ~ ”,不知道是服务器那边的事还是我这边框架的问题,然后我干脆就直接1索引截取了,并且还发现,json数据
过来后它竟然把&转义了,把“&”转换成了“&”,所以再全部替换喽。
有一次支付宝支付还遇到一个奇葩问题,也是报Ali40247,但是就是找不到原因,后来我发现是我设置公钥设置在RSA一栏了,而我们后台调用的则使
RSA2,所以就出错了,直接让后台改成RSA就ok了。有时候就是因为这么一点小小的问题就会导致到问题。
还有一次报了Ali59错误码,这个代表你的支付金额为空啦,最低0.01就好了。
接着就是接受结果的地方,不多做解释,9000是成功,如果出错就打印String re = msg.obj.toString();,查看错误信息。还有就是关于appID,大家
也看到了,只有在本地签名的时候有用到,而支付宝不推荐本地做签名,所以我们直接从后台那边拿到就可以。那几个字段全都是后台走的api,返回
过来的数据好了,支付宝就啰嗦这么多。
二.android接入支付——微信
啰嗦那么多,接下来就开始进入正题,同支付宝一样,先创建账号,创建应用(包名,签名)后进行商家认证,申请支付能力:
搞完之后就会拿到 AppID和AppSecret,配置代码:
api = WXAPIFactory.createWXAPI(PayActivity.this, "wxxxxxxxxxxxxxxx");
api.registerApp("wxxxxxxxxxxxxxxx");
String str = "Sign=WXPay";
if (RequestCode == 100) {
Log.e("=========", "微信支付内容:" + content);
Gson gson = new Gson();
WxpayBean wxpayBean = gson.fromJson(content, WxpayBean.class);
if (Integer.parseInt(wxpayBean.getCode()) == 200) {
WxpayBean.DataBean data = wxpayBean.getData();
SortedMap<String, Object> params = new TreeMap<String, Object>();
params.put("appid", data.getAPPID());
params.put("partnerid", data.getMCH_ID());
params.put("prepayid", data.getPREPAY_ID());
params.put("package", "Sign=WXPay");
params.put("noncestr", data.getNONCE_STR());
params.put("timestamp", data.getTimestamp() + "");
String sign = createSign(params);
PayReq req = new PayReq();
req.appId = data.getAPPID(); //后台和本地都可
req.partnerId = data.getMCH_ID(); //后台给出 微信支付分配的商户号
req.prepayId = data.getPREPAY_ID(); //后台给出 预支付订单号,app服务器调用“统一下单”接口获取
req.nonceStr = data.getNONCE_STR(); //后台给出 /随机字符串,不长于32位
req.timeStamp = data.getTimestamp() + ""; //时间戳
req.packageValue = str; //固定值Sign=WXPay
req.sign = sign; //签名
Toast.makeText(PayActivity.this, "正常调起支付", Toast.LENGTH_SHORT).show();
// 在支付之前,如果应用没有注册到微信,应该先调用IWXMsg.registerApp将应用注册到微信
api.sendReq(req);
}
}
都说微信支付坑,坑在哪里,坑在出现错误后结果返回-1,而有时候就不会给提示,后来经过我和后台的反复测试,在一篇帖子的引导下,确定了是签名的问题,
后台做了签名,而我直接拿取的后台的sign填入其中才导致了这样的问题,那篇博客的大意好像是说因为时间戳的原因,拉不起来支付,因为签名的时候需要混入时间戳的,所以我
们商量一下我本地也做了签名,但目的不是为了签名而签名,而是为了拉起来本地支付接口,实际上支付走的签名信息还是后台做的,有时间会找到那篇文章链接放
在这,方法:
public static String createSign(SortedMap<String, Object> parameters) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + "xxxxxxxxxxxxxxxx");
// String sign = MD5Utils.encode(sb.toString()).toUpperCase();
String sign = getPwd(sb.toString()).toUpperCase();
return sign;
}
/**
* @author CQY13 MD5加密工具类
*/
public static String getPwd(String pwd) {
try {
// 创建加密对象
MessageDigest digest = MessageDigest.getInstance("md5");
// 调用加密对象的方法,加密的动作已经完成
byte[] bs = digest.digest(pwd.getBytes());
// 接下来,我们要对加密后的结果,进行优化,按照mysql的优化思路走
// mysql的优化思路:
// 第一步,将数据全部转换成正数:
String hexString = "";
for (byte b : bs) {
// 第一步,将数据全部转换成正数:
// 解释:为什么采用b&255
/*
* b:它本来是一个byte类型的数据(1个字节) 255:是一个int类型的数据(4个字节)
* byte类型的数据与int类型的数据进行运算,会自动类型提升为int类型 eg: b: 1001 1100(原始数据)
* 运算时: b: 0000 0000 0000 0000 0000 0000 1001 1100 255: 0000
* 0000 0000 0000 0000 0000 1111 1111 结果:0000 0000 0000 0000
* 0000 0000 1001 1100 此时的temp是一个int类型的整数
*/
int temp = b & 255;
// 第二步,将所有的数据转换成16进制的形式
// 注意:转换的时候注意if正数>=0&&<16,那么如果使用Integer.toHexString(),可能会造成缺少位数
// 因此,需要对temp进行判断
if (temp < 16 && temp >= 0) {
// 手动补上一个“0”
hexString = hexString + "0" + Integer.toHexString(temp);
} else {
hexString = hexString + Integer.toHexString(temp);
}
}
return hexString;
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
经过签名后果断就拉起支付过来,也不会返回-1了。 这个情况也不知道是后台还是我的原因,感觉这样解决还是太low,等我研究透了,再帖上原因,也希望大家有知道原因的,
楼下留言。互相学习。
然后就是回调了,WXPayEntryActivity 接受结果,通过eventbus或handler传递到其他页面结果(此类及所在包均不可改名)。