这几天给app对接了微信支付,官方的demo真是。。。第一次果然不免爬几个坑,记录一下,避免遗忘。

错误说明

在保证提供的参数都正确的情况下,往往测试微信支付失败的原因是签名错误,这个时候应该仔细核对流程。就我自己而言碰到的问题就是搞错了最后发送订单的时候的签名sign参数。这个签名不是第一次组拼的签名,也不是生成预支付交易单,获取prepayId时返回的签名,而是获取到prepayId后用prepayId和其他参数第二次组拼成的sign。

流程说明

详细的业务流程为微信官方文档里有,我这边以所有参数由客户端提供的方式简单说明一下请求流程。

获取必须参数,第一次签名。

需要说明的是签名中的key参数是由我方自行在微信商户平台设置的。具体位置:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置

生成预支付交易单,获取prepayId。

调用微信的接口“https://api.mch.weixin.qq.com/pay/unifiedorder”获取prepayId。另外返回信息中的sign并不是最后调起支付中的sign参数。

第二次签名。

用"appid","noncestr","package","partnerid","prepayid","timestamp"生成第二次签名。签名方式与第一次相同,参数不同(注意参数顺序)。这样就拿到了调起微信支付所需的所有参数。

调起微信支付。

代码说明

public class WXPayUtils {

private Context mContext;

private PayReq req;

private IWXAPI iwxapi; //微信支付api

private Map resultunifiedorder;

public WXPayUtils() {

}

public WXPayUtils(Context context) {

this.mContext = context;

req = new PayReq();

iwxapi = WXAPIFactory.createWXAPI(context, null); //初始化微信api

}

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case 0: //获取参数及调起支付

getPayParameter();

sendPayReq();

break;

default:

break;

}

}

};

/**

* 第一次签名及生成prepayId

**/

public void toWXPayAndSign(int money) {

PrePayIdAsyncTask prePayIdAsyncTask = new PrePayIdAsyncTask();

prePayIdAsyncTask.execute(money);

}

private class PrePayIdAsyncTask extends AsyncTask> {

@Override

protected void onPreExecute() {

// TODO Auto-generated method stub

super.onPreExecute();

}

@Override

protected Map doInBackground(Integer... params) {

// TODO Auto-generated method stub

String urlString = "https://api.mch.weixin.qq.com/pay/unifiedorder";

int money = params[0];

String entity = getProductArgs(money);

Log.e("Simon", ">>>>" + entity);

byte[] buf = Util.httpPost(urlString, entity);

String content = new String(buf);

Log.e("orion", "----" + content);

Map xml = decodeXml(content);

return xml;

}

@Override

protected void onPostExecute(Map result) {

// TODO Auto-generated method stub

super.onPostExecute(result);

resultunifiedorder = result;

handler.sendEmptyMessage(0);

}

}

/**

* 生成xml参数,用于生成预支付交易单,获取prepayId

* @param money

* @return

*/

private String getProductArgs(int money) {

StringBuffer xml = new StringBuffer();

try {

DecimalFormat df = new DecimalFormat("#");

String price = df.format(money * 100);

String nonceStr = getNonceStr();

xml.append("");

List packageParams = new LinkedList();

packageParams.add(new BasicNameValuePair("appid", WXKeys.WX_APPID));

packageParams.add(new BasicNameValuePair("body", "APP pay test"));

packageParams.add(new BasicNameValuePair("mch_id", WXKeys.WX_MCH_ID));

packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));

packageParams.add(new BasicNameValuePair("notify_url", "http://www.baidu.com/"));//你自己的的回调地址!!!

packageParams.add(new BasicNameValuePair("out_trade_no", getOutTradeNo()));

packageParams.add(new BasicNameValuePair("total_fee", price));

packageParams.add(new BasicNameValuePair("trade_type", "APP"));

String sign = getPackageSign(packageParams);

packageParams.add(new BasicNameValuePair("sign", sign));

String xmlString = toXml(packageParams);

return xmlString;

} catch (Exception e) {

// TODO: handle exception

return null;

}

}

/**

* 获取支付参数

*/

private void getPayParameter() {

req.appId = WXKeys.WX_APPID;

req.partnerId = WXKeys.WX_MCH_ID;

if (resultunifiedorder != null) {

req.prepayId = resultunifiedorder.get("prepay_id");

} else {

Toast.makeText(mContext, "预支付交易单生成失败", Toast.LENGTH_SHORT).show();

}

req.packageValue = "Sign=WXPay";

req.nonceStr = getNonceStr();

req.timeStamp = String.valueOf(genTimeStamp());

List signParams = new LinkedList();

signParams.add(new BasicNameValuePair("appid", req.appId));

signParams.add(new BasicNameValuePair("noncestr", req.nonceStr));

signParams.add(new BasicNameValuePair("package", req.packageValue));

signParams.add(new BasicNameValuePair("partnerid", req.partnerId));

signParams.add(new BasicNameValuePair("prepayid", req.prepayId));

signParams.add(new BasicNameValuePair("timestamp", req.timeStamp));

req.sign = getPaySign(signParams);

}

/**

* 调起微信支付

*/

private void sendPayReq() {

iwxapi.registerApp(WXKeys.WX_APPID);

iwxapi.sendReq(req);

}

/**

* 生成随机数

* @return

*/

private String getNonceStr() {

// TODO Auto-generated method stub

Random random = new Random();

return getMessageDigest(String.valueOf(random.nextInt(10000)).getBytes());

}

/**

* 生成第一次签名

* @param params

* @return

*/

private String getPackageSign(List params) {

StringBuilder sb = new StringBuilder();

for (int i = 0; i < params.size(); i++) {

sb.append(params.get(i).getName());

sb.append('=');

sb.append(params.get(i).getValue());

sb.append('&');

}

sb.append("key=");

sb.append(WXKeys.WX_PRIVATE_KEY);

String packageSign = getMessageDigest(sb.toString().getBytes()).toUpperCase();

Log.e("Simon", ">>>>" + packageSign);

return packageSign;

}

/**

* 生成第二次签名

* @param params

* @return

*/

private String getPaySign(List params) {

StringBuilder sb = new StringBuilder();

for (int i = 0; i < params.size(); i++) {

sb.append(params.get(i).getName());

sb.append('=');

sb.append(params.get(i).getValue());

sb.append('&');

}

sb.append("key=");

sb.append(WXKeys.WX_PRIVATE_KEY);

String appSign = getMessageDigest(sb.toString().getBytes());

Log.e("Simon","----"+appSign);

return appSign;

}

/**

* 获取时间戳

*

* @return

*/

private static long genTimeStamp() {

return System.currentTimeMillis() / 1000;

}

/**

* 获取设备ip地址

* @return

*/

private static String getIpAddressString() {

try {

for (Enumeration enNetI = NetworkInterface

.getNetworkInterfaces(); enNetI.hasMoreElements(); ) {

NetworkInterface netI = enNetI.nextElement();

for (Enumeration enumIpAddr = netI

.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {

InetAddress inetAddress = enumIpAddr.nextElement();

if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) {

return inetAddress.getHostAddress();

}

}

}

} catch (SocketException e) {

e.printStackTrace();

}

return "127.0.0.1";

}

/**

* 获取外部订单号

*/

String getOutTradeNo() {

SimpleDateFormat format = new SimpleDateFormat("MMddHHmmss");

Date date = new Date();

String strKey = format.format(date);

java.util.Random r = new java.util.Random();

strKey = strKey + r.nextInt();

strKey = strKey.substring(0, 15);

return strKey;

}

/**

* 转换xml

* @param params

* @return

*/

private static String toXml(List params) {

StringBuilder sb = new StringBuilder();

sb.append("");

for (int i = 0; i < params.size(); i++) {

sb.append("");

sb.append(params.get(i).getValue());

sb.append("" + params.get(i).getName() + ">");

}

sb.append("");

Log.e("Simon", ">>>>" + sb.toString());

return sb.toString();

}

/**

* 转换xml

* @param content

* @return

*/

private Map decodeXml(String content) {

try {

Map xml = new HashMap();

XmlPullParser parser = Xml.newPullParser();

parser.setInput(new StringReader(content));

int event = parser.getEventType();

while (event != XmlPullParser.END_DOCUMENT) {

String nodeName = parser.getName();

switch (event) {

case XmlPullParser.START_DOCUMENT:

break;

case XmlPullParser.START_TAG:

if ("xml".equals(nodeName) == false) {

//实例化student对象

xml.put(nodeName, parser.nextText());

}

break;

case XmlPullParser.END_TAG:

break;

}

event = parser.next();

}

return xml;

} catch (Exception e) {

Log.e("Simon", "----" + e.toString());

}

return null;

}

/**

* md5加密

*

* @param buffer

* @return

*/

private static String getMessageDigest(byte[] buffer) {

char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

try {

MessageDigest mdTemp = MessageDigest.getInstance("MD5");

mdTemp.update(buffer);

byte[] md = mdTemp.digest();

int j = md.length;

char str[] = new char[j * 2];

int k = 0;

for (int i = 0; i < j; i++) {

byte byte0 = md[i];

str[k++] = hexDigits[byte0 >>> 4 & 0xf];

str[k++] = hexDigits[byte0 & 0xf];

}

return new String(str);

} catch (Exception e) {

return null;

}

}

}

参考

大致的流程就如上面所说,其他没有提到的大多在官方demo中有。需要详细的过程可以参考下面两个两篇(感谢原作者):

Android微信支付详解与Demo

详细介绍Android开发集成微信支付(二) --- 完整版本

android微信支付跳转逻辑,Android对接微信支付相关推荐

  1. java支付接口开发原理_java对接微信支付接口开发的过程是什么?

    java对接微信支付接口开发的过程是什么?以下是小编整理的java对接微信支付接口实现的方法和过程,有需要的朋友可以学习以下的java对接微信支付接口内容. java对接微信支付接口开发的过程是什么? ...

  2. android点击跳转卸载,[android]通过JNI实现卸载自身App后台发送Http请求~

    freddon 发表于2016-10-21 阅读 1252 | 评论 1 使用JNI fork进程实现 监控自身App被卸载 首先这个功能仅供cankao 也可以使用linux exec命令跳转到浏览 ...

  3. 微信小程序盲盒-可对接微信支付

    简介: 分享一款盲盒小程序,已亲测亲测可对接微信,可手动给用户充值 网盘下载地址: http://zijiepan5.xyz/ipKQ7pSHW2D0 图片:

  4. ios微信组件跳转_IOS如何从微信中跳转APP

    如果不考虑屏蔽,跳转APP的方式主要有: url scheme 这是一种ios与Android都支持的叫做schema的协议.至于具体怎么设置,交给IOS或者安卓开发人员吧. 这种方式在除微信外的大部 ...

  5. php微信公众号怎么开发_PHP对接微信公众平台消息接口开发流程详解及实例

    这篇文章主要介绍了PHP对接微信公众平台消息接口开发流程,如何使用PHP版接口操作公众平台消息,需要的朋友可以参考下 一.写好接口程序 在你的服务器上上传好一个接口程序文件内容如下: 代码如下:< ...

  6. android 5.0跳转动画,android Lollipop(5.0)--activity跳转动画

    android Lollipop(5.0)对app中有共享view的activity直接的跳转提供了更好的动画交互. 实现步骤: 1,编写需要的transform. 2,给activity设置样式st ...

  7. 微信支付宝换钱源码 可对接易支付

    源码介绍: 在线安装,独立程序,支持随意对接任何易支付平台,对接代付接口,在线提交,实时秒到. 网盘下载地址: http://www.bytepan.com/1qa7rVyeQhN 图片:

  8. android电量计电量跳变问题,Android电池电量跳变

    问题情形: 1.电量跳变到50% 2.电池ID脚接地 3.温度脚来判断电池是否在位 推测原因: 判断电池在位的方法: qpnp-linear-charger.c enum bpd_type{ BPD_ ...

  9. 微信浏览器跳转小程序php,微信浏览器里面h5跳转小程序

    微信浏览器里面h5跳转小程序 注意事项,以vue框架为例 一.获取jssdk配置,在wx.ready回调函数里面展示按钮wx.config({ debug: false, appId: data.ap ...

  10. laravel+easywechat对接微信公众号自动回复图文消息

    laravel+easywechat对接微信公众号自动回复图文消息 图文回复消息创建 对接数据库根据关键词返回图文信息 前面我们对接配置了微信公众号,laravel5.4 对接微信公众号使用larav ...

最新文章

  1. hdu2553 N皇后问题-dfs回溯剪枝+打表
  2. scala闭包 变量_Scala闭包,自由和绑定变量,匿名函数
  3. RoadRunner安装与使用教程
  4. python numpy官方文档_[ Numpy中文文档 ] 介绍 - pytorch中文网
  5. VC2012 ActiveX 控制台打印调试
  6. 缺少tlsys.conf文件
  7. spring-05 AOP
  8. Java的11个关键术语
  9. QMH、AMC和STM之间的关系
  10. python编译原理 书籍_如何想学点编译原理,又不想直接看龙虎之类的书籍,太多理论,干燥?...
  11. windows同步linux用户,用winbind实现windowsPDC和linux系统的帐号同步
  12. 透过爷爷的一生,浅析选择的重要性
  13. PTA 6 循环日程表
  14. 驱动程序开发:多点电容触摸屏
  15. 「区块链系列」区块链技术与应用
  16. 如何退出Google的Gmail信箱
  17. 基于MNIST手写体数字识别--含可直接使用代码【Python+Tensorflow+CNN+Keras】
  18. 【Heritrix 03】heritrix_dmesg.log
  19. Cisco Catalyst 3560-E系列交换机
  20. XCode 下载链接

热门文章

  1. Mybatis Plus
  2. 区块链开发主流编程语言居然是Go语言!
  3. PHP汉字转拼音函数类
  4. Word插入参考文献时自动编号
  5. ts/js 函数传参带函数写法
  6. PowerPoint 消除所有动画VBA指令
  7. C语言文本输入中文乱码问题
  8. Java零基础入门(五)
  9. 最怕虚拟机连不上网-记一次网卡消失
  10. Hearbeat + Nginx 安装配置