出于安全考虑,验签我们都是放到后台进行验签的。对于我们移动端节省了很多的劳动力。
支付界面如下:
支付完成界面如下:
ok,接下来开始我们轻松的开发之旅:
准备:需要以公司名义,在支付宝,微信等平台上开通公司账户并且认证,如:支付过程中需要公司的帐号和商户号。
支付宝:
1、获取订单信息(根据自己公司的实际情况:可以在服务端完成,也可以在本地完成)
2、客户端拿这些订单信息向服务器后台进行请求,返回支付签名信息signInfo
3、app携带支付信息,调用支付接口请求支付宝客户端,从而调起支付界面
/**
* 支付宝进行请求
*
* @param signInfo
*/
private void payToOrderService(final String signInfo) {
new Thread() {
@Override
public void run() {
super.run();
PayTask payTask = new PayTask(MyScannerPayActivity.this);
// String result = payTask.pay(signInfo, true);
Map result = payTask.payV2(signInfo, true);
Message message = mHandler.obtainMessage();
message.what = SDK_PAY_FLAG;
message.obj = result;
mHandler.sendMessage(message);
}
}.start();
}
4、
用户操作,输入密码支付,支付成功;直接返回取消支付;出现错误,支付失败;进入支付界面,但输入密码支付,支付待确认;
5、支付宝客户端将支付结果告诉app客户端,商户服务器通知app服务器支付结果;
6、app客户端处理支付结果;
7、app服务器处理支付结果。
app客户端结果处理代码:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case SDK_PAY_FLAG:
PayResult payResult = null;
try {
payResult = new PayResult((Map) msg.obj);
} catch (Exception e) {
e.printStackTrace();
}
/**
对于支付结果,请商户依赖服务端的异步通知结果。同步通知结果,仅作为支付结束的通知。
*/
String resultInfo = payResult.getResult();// 同步返回需要验证的信息
String resultStatus = payResult.getResultStatus();
// 判断resultStatus 为9000则代表支付成功
if (TextUtils.equals(resultStatus, PAY_OK)) {
ActivityUtils.showActivity(MyScannerPayActivity.this, ScannerPaySuccessActivity.class);
finish();
} else if (TextUtils.equals(resultStatus, PAY_FAILED)) {//------------------------->支付失败
// 该笔订单真实的支付结果,需要依赖服务端的异步通知。
Toast.makeText(MyScannerPayActivity.this, "" + payResult.getMemo(), Toast.LENGTH_LONG).show();
} else if (TextUtils.equals(resultStatus, PAY_CANCLE)) {//-------------------------->交易取消
Toast.makeText(MyScannerPayActivity.this, "" + payResult.getMemo(), Toast.LENGTH_LONG).show();
} else if (TextUtils.equals(resultStatus, PAY_NET_ERR)) {//------------------------->网络出现错误
Toast.makeText(MyScannerPayActivity.this, "" + payResult.getMemo(), Toast.LENGTH_LONG).show();
} else if (TextUtils.equals(resultStatus, PAY_WAIT_CONFIRM)) {//--------------------->交替等待
}
break;
}
}
};
先上官方流程图
1.客户端代码得到用户购买的商品信息,将之传给自己公司app服务器,参数包含但不限于以下:
HashMap params = getHeadMap();
params.put("appid", appID);// 微信appid,选择性上传,服务器写死亦可
params.put("money", money);// 支付金额,单位:分
params.put("goodName", goodsName);// 商品名称
params.put("productNum", String.valueOf(12));// 商品的数量
2.app服务器调用微信 统一下单 接口,得到prepayId并返回客户端
3.app客户端使用prepayId和商品信息调用sdk进行微信支付请求
IWXAPI mWxApi = WXAPIFactory.createWXAPI(mContext, WX_APPID, true);
mWxApi.registerApp(WX_APPID);
/**
* 请求app服务器得到的回调结果
*/
@Override
public void onGet(JSONObject jsonObject) {
if (mWxApi != null) {
PayReq req = new PayReq();
req.appId = WX_APPID;// 微信开放平台审核通过的应用APPID
try {
req.partnerId = jsonObject.getString("partnerid");// 微信支付分配的商户号
req.prepayId = jsonObject.getString("prepayid");// 预支付订单号,app服务器调用“统一下单”接口获取
req.nonceStr = jsonObject.getString("noncestr");// 随机字符串,不长于32位,服务器小哥会给咱生成
req.timeStamp = jsonObject.getString("timestamp");// 时间戳,app服务器小哥给出
req.packageValue = jsonObject.getString("package");// 固定值Sign=WXPay,可以直接写死,服务器返回的也是这个固定值
req.sign = jsonObject.getString("sign");// 签名,服务器小哥给出,他会根据:https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3指导得到这个
} catch (JSONException e) {
e.printStackTrace();
}
mWxApi.sendReq(req);
Log.d("发起微信支付申请");
}
}
4.微信回调客户端支付结果
5.微信服务器异步通知app服务器支付结果
注意:
1.首先如果要使用微信支付的话
必须先到微信开放平台注册应用,具体地址为https://open.weixin.qq.com/
注册时需要填应用的包名和签名,注意这里的签名是App正式版的签名,可以找一个已上线的包或打一个正式包,使用微信提供的工具(签名工具下载地址为https://open.weixin.qq.com/zh_CN/htmledition/res/dev/download/sdk/Gen_Signature_Android.apk)来获取,获取后填上即可。
待审核通过后,会得到一个AppID和AppSecret,AppID分享和支付都要用到,AppSecret没什么实际用途,此时微信分享能力是直接拥有的,支付能力还要额外申请,其中涉及到财务信息等
2.微信分享和微信支付SDK是同一个架包,名为libammsdk.jar。
3.官方开发文档中有一处错误,需要注意下,如下图最后一行参数req应该为request,照搬代码的估计IDE也不会放过你,哈哈
5.还是签名,网上有人说要注意大小写,这点其实是不必的。在微信开放平台看到审核通过的App的签名是大写的,而用微信签名获取工具获得的则显示小写,这个没关系,不要贸然改动平台注册信息,不然又可能导致漫长的审核等待,上面也说了,微信分享如可以,那就不是签名问题。
6.来说下官方demo,这东西害人不浅啊!很多人参考其写法,如生成sign放在客户端啊,调支付的Activity添加intent-filter啊,最主要的还是签名问题。其实客户端逻辑很简单,直接上手集成即可,demo看看逻辑就行,照抄小心掉坑里。
7.网上有人说需要给调用支付的Activity配置如下intent-filter(见下图),可能也是被demo误导了
8.对于errCode返回-1,有人说清除微信缓存或切换账户就好了,这种解决方案治标不治本啊,根本不能算解决方案。虽然我没遇到能用这方法解决的问题,但目测是签名的问题,建议还得找到真正的问题所在。
9.生成sign时特别需要注意:
10.req.packageValue=”Sign=WXPay”,一般都是这样写死这个参数值。也有人说写成req.packageValue=”prepay_id=” + prepayid,经测试Android两种写法都是可以调起微信支付的,至少最新版本SDK是可以的,以后则不清楚,官方也建议写Sign=WXPay,据说iOS只支持这种写法。
1.微信支付和支付宝支付是现在APP常用的支付方式,但是真正接入过两种支付方式的猿友会很明显的感觉到微信支付真心比支付宝麻烦很多,会出现很多莫名其妙的错误,但是官方的文档却很难给出较好的解决方案.
2.前几天公司的APP需要支付功能然后也需要这个-1问题,简直感觉微信支付丧心病狂,这里总结下自己出现的问题和一些其他网友出现的问题做个总结
reso.errCode = -1 官方的描述: -1 错误 可能的原因:签名错误、未注册APPID、项目设置APPID不正确、注册的APPID与设置的不匹配、其他异常等。
先看流程图
大家不要被这张图片搞懵逼的了,其实很简单,这里我将其分为5小步。
第一步:根据官方文档选择符合自己的sdk
官方文档:
https://open.unionpay.com/ajweb/help/file/techFile?productId=3
第二步:将相对应的.so文件copy到 自己的工程里面去。
特别注意:
.so文件要放在src/main 目录下,和Java文件并行。还有就是把用到的权限复制到自己项目中)
第三步: 和支付宝一样,APP客户端带着这些订单号向服务器后台请求订单号orderNo
第四步:服务器后台接收到购买信息之后,将信息提交给银联后台,银联接收到后台之后给服务器返回tn号
第五步:开启调用银联支付。APP客户端带着这个流水号,也就是第三步中服务器返回的tn号,调用银联SDK所提供的方法
注意:
这个订单流水号为21位纯数字号
调用方法: UPPayAssistEx.startPay(this, null, null, tn, mMode);
请求支付
String serverMode = "01";
String tn="";// 从服务器获取的流水号
UPPayAssistEx.startPayByJAR(MainActivity.this, PayActivity.class, "", "", tn, serverMode);
tn值就是上面第三后台给的tn,给到服务器那里
结果返回:
处理银联手机支付控件返回的支付结果
调用银联支付后,返回app的时候用了,看返回结果传,成功,失败,或者是什么返回。
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.e(TAG, "onActivityResult: ");
if (data == null) {
Log.e(TAG, "onActivityResult: 是空");
return;
}
String str = data.getExtras().getString("pay_result");
if (str.equalsIgnoreCase("success")) {
Log.e(TAG, "onActivityResult: 支付成功!");
} else if (str.equalsIgnoreCase("fail")) {
Log.e(TAG, "onActivityResult: 支付失败!");
} else if (str.equalsIgnoreCase("cancel")) {
Log.e(TAG, "onActivityResult: 支付取消!");
}
}
总感觉银联支付的SDK调用起来怪怪的,貌似回到了原始深林
最后,我封装了三方支付库,已传到github,欢迎各位使用和star!https://github.com/shuaijia/JsEasyPay