微信支付之把服务端做的事放在客户端做-客户端生成预付款订单

先附上 微信支付文档给出的说明商户系统和微信支付系统主要交互说明:

步骤1:用户在商户APP中选择商品,提交订单,选择微信支付。

步骤2:商户后台收到用户支付单,调用微信支付统一下单接口。参见【统一下单API】。

步骤3:统一下单接口返回正常的prepay_id,再按签名规范重新生成签名后,将数据传输给APP参与签名的字段名为的appid,PARTNERID,prepayid,noncestr,时间戳,包注意:包的值格式为符号= WXPay

步骤4:商户APP调起微信支付.api参见本章节【app端开发步骤说明

步骤5:商户后台接收支付通知.api参见【支付结果通知API

步骤6:商户后台查询支付结果。,api参见【查询订单API


以上是官网给出的服务端与客户端的交互流程

统一下单大致的意思是:

服务端:统一下单需要10个参数其中第10个是签名是对前9个参数进行签名处理,微信后台会返回生成的预付款订单,然后服务端会给客户端返回7个参数其中第7个参数是对前6个参数整体进行的签名
app端:掉起微信支付需要服务器传递过来的7个参数

其中步骤2和步骤3是服务端做的事,本文是把步骤2和步骤3的操作放在客户端进行,

作用:

1.熟练掌握微信支付的流程    

 2.可以检测服务器是否返回的内容有错(我当时用了将近1天的时间去处理微信返回的错误码是-1的情况,后来我在本地生成了预付款订单,把服务端的操作全放在了本地,可以正常支付,才发现不是我的问题,而是服务端的问题)


具体实现:

1.网络请求用的AsyncTask 调用微信的统一下单接口 需要10个参数,其中第10个是对前9个参数的签名,签名规则要根据微信的要求来

protected Map<String, String> doInBackground(Void... params) {
    //本地调用统一下单的接口    微信返回的数据格式是xml 需要本地处理
    String url = String.format("https://api.mch.weixin.qq.com/pay/unifiedorder");
    String entity = genEntity();
    Log.e("实体", entity);
    byte[] buf = Util.httpPost(url, entity);
    String content = new String(buf);
    Log.e("内容", content);
    Map<String, String> xml = decodeXml(content);
    return xml;
}

public String genEntity() {
    String nonceStr = genNonceStr();
    List<NameValuePair> packageParams = new LinkedList<NameValuePair>();
    packageParams.add(new BasicNameValuePair("appid", Constants.APP_ID));
    packageParams.add(new BasicNameValuePair("body", "我是购买的商品"));
    packageParams.add(new BasicNameValuePair("mch_id", Constants.MCH_ID));
    packageParams.add(new BasicNameValuePair("nonce_str", nonceStr));
    packageParams.add(new BasicNameValuePair("notify_url", "http://121.40.35.3/test"));
    packageParams.add(new BasicNameValuePair("out_trade_no", genOutTradNo()));
    packageParams.add(new BasicNameValuePair("spbill_create_ip", "127.0.0.1"));
    packageParams.add(new BasicNameValuePair("total_fee", "1"));
    packageParams.add(new BasicNameValuePair("trade_type", "APP"));
    String sign = genPackageSign(packageParams);
    packageParams.add(new BasicNameValuePair("sign", sign));
    String xmlstring = XmlUtil.toXml(packageParams);
    try {
        return new String(xmlstring.toString().getBytes(), "ISO-8859-1");

    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }
    return null;
}

微信的签名规则

public static String genPackageSign(List<NameValuePair> params) {
    try {
        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(Constants.API_KEY);

        String packageSign = MD5Util.getMessageDigest(
                sb.toString().getBytes("utf-8")).toUpperCase();
        return packageSign;
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
        return null;
    }
}

2.调用统一下单接口后,微信会返回xml 根据返回的xml 获取到预支付的会话标示 prepay_id

(解释:服务端的操作是根据微信返回的参数,对appid ,mch_id ,nonce_str ,prepay_id ,trade_type ,微信默认的字符串package="Sign=WXPay"这6个参数进行签名处理 生成第7个参数sign 返回给客户端,客户端拿到这7个参数,然后掉起来微信


3.拿到预支付的会话标示后掉起微信,此时需要7个参数

/**
 * 掉起微信支付 这里是客户端必须进行的 也就是接受服务器 返回的数据 进行处理
 */
private void genPayReq() {

    req.appId = Constants.APP_ID;
    req.partnerId = Constants.MCH_ID;
    req.prepayId = resultunifiedorder.get("prepay_id");
    req.packageValue = "Sign=WXPay";
    String prepayID = resultunifiedorder.get("prepay_id");

    req.nonceStr = genNonceStr();
    req.timeStamp = String.valueOf(genTimeStamp());
    
    List<NameValuePair> signParams = new LinkedList<NameValuePair>();
    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));
    //因为微信支付需要签2次名  这里是第二次签名  本应该放在服务端的
    req.sign = genAppSign(signParams);


    sb.append("sign\n" + req.sign + "\n\n");
    //show.setText(sb.toString());


    Log.e("orion", signParams.toString());
    //调起微信支付
    msgApi.registerApp(Constants.APP_ID);
    msgApi.sendReq(req);

}


如果想要运行本demo 必须填写以下信息

//appid
public static final String APP_ID = "";//
//商户id
public static final String MCH_ID = "";
//商户和微信签约的秘钥
public static final String API_KEY = "";


demo地址点击打开链接

提示:

如果直接run 运行的项目 请修改微信后台的签名 -改为debug签名,

微信后台的签名只要和你当前项目的签名保持一致即可,比如:如果你微信后台填写的是正式签名,那么你app就不能直接run执行 ,因为run 执行默认的是用的debug签名

所以 为了方便测试,我微信后台暂时填写的是我debug的签名




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值